Blame gio/gnetworkmonitor.c

Packit ae235b
/* GIO - GLib Input, Output and Streaming Library
Packit ae235b
 *
Packit ae235b
 * Copyright 2011 Red Hat, Inc
Packit ae235b
 *
Packit ae235b
 * This library is free software; you can redistribute it and/or
Packit ae235b
 * modify it under the terms of the GNU Lesser General Public
Packit ae235b
 * License as published by the Free Software Foundation; either
Packit ae235b
 * version 2.1 of the License, or (at your option) any later version.
Packit ae235b
 *
Packit ae235b
 * This library is distributed in the hope that it will be useful,
Packit ae235b
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit ae235b
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit ae235b
 * Lesser General Public License for more details.
Packit ae235b
 *
Packit ae235b
 * You should have received a copy of the GNU Lesser General
Packit ae235b
 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
Packit ae235b
 */
Packit ae235b
Packit ae235b
#include "config.h"
Packit ae235b
#include "glib.h"
Packit ae235b
#include "glibintl.h"
Packit ae235b
Packit ae235b
#include "gnetworkmonitor.h"
Packit ae235b
#include "ginetaddress.h"
Packit ae235b
#include "ginetsocketaddress.h"
Packit ae235b
#include "ginitable.h"
Packit ae235b
#include "gioenumtypes.h"
Packit ae235b
#include "giomodule-priv.h"
Packit ae235b
#include "gtask.h"
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * SECTION:gnetworkmonitor
Packit ae235b
 * @title: GNetworkMonitor
Packit ae235b
 * @short_description: Network status monitor
Packit ae235b
 * @include: gio/gio.h
Packit ae235b
 *
Packit ae235b
 * #GNetworkMonitor provides an easy-to-use cross-platform API
Packit ae235b
 * for monitoring network connectivity. On Linux, the available
Packit ae235b
 * implementations are based on the kernel's netlink interface and
Packit ae235b
 * on NetworkManager.
Packit ae235b
 *
Packit ae235b
 * There is also an implementation for use inside Flatpak sandboxes.
Packit ae235b
 */
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * GNetworkMonitor:
Packit ae235b
 *
Packit ae235b
 * #GNetworkMonitor monitors the status of network connections and
Packit ae235b
 * indicates when a possibly-user-visible change has occurred.
Packit ae235b
 *
Packit ae235b
 * Since: 2.32
Packit ae235b
 */
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * GNetworkMonitorInterface:
Packit ae235b
 * @g_iface: The parent interface.
Packit ae235b
 * @network_changed: the virtual function pointer for the
Packit ae235b
 *  GNetworkMonitor::network-changed signal.
Packit ae235b
 * @can_reach: the virtual function pointer for g_network_monitor_can_reach()
Packit ae235b
 * @can_reach_async: the virtual function pointer for
Packit ae235b
 *  g_network_monitor_can_reach_async()
Packit ae235b
 * @can_reach_finish: the virtual function pointer for
Packit ae235b
 *  g_network_monitor_can_reach_finish()
Packit ae235b
 *
Packit ae235b
 * The virtual function table for #GNetworkMonitor.
Packit ae235b
 *
Packit ae235b
 * Since: 2.32
Packit ae235b
 */
Packit ae235b
Packit ae235b
G_DEFINE_INTERFACE_WITH_CODE (GNetworkMonitor, g_network_monitor, G_TYPE_OBJECT,
Packit ae235b
                              g_type_interface_add_prerequisite (g_define_type_id, G_TYPE_INITABLE);)
Packit ae235b
Packit ae235b
Packit ae235b
enum {
Packit ae235b
  NETWORK_CHANGED,
Packit ae235b
  LAST_SIGNAL
Packit ae235b
};
Packit ae235b
Packit ae235b
static guint signals[LAST_SIGNAL] = { 0 };
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_network_monitor_get_default:
Packit ae235b
 *
Packit ae235b
 * Gets the default #GNetworkMonitor for the system.
Packit ae235b
 *
Packit ae235b
 * Returns: (transfer none): a #GNetworkMonitor
Packit ae235b
 *
Packit ae235b
 * Since: 2.32
Packit ae235b
 */
Packit ae235b
GNetworkMonitor *
Packit ae235b
g_network_monitor_get_default (void)
Packit ae235b
{
Packit ae235b
  return _g_io_module_get_default (G_NETWORK_MONITOR_EXTENSION_POINT_NAME,
Packit ae235b
                                   "GIO_USE_NETWORK_MONITOR",
Packit ae235b
                                   NULL);
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_network_monitor_get_network_available:
Packit ae235b
 * @monitor: the #GNetworkMonitor
Packit ae235b
 *
Packit ae235b
 * Checks if the network is available. "Available" here means that the
Packit ae235b
 * system has a default route available for at least one of IPv4 or
Packit ae235b
 * IPv6. It does not necessarily imply that the public Internet is
Packit ae235b
 * reachable. See #GNetworkMonitor:network-available for more details.
Packit ae235b
 *
Packit ae235b
 * Returns: whether the network is available
Packit ae235b
 *
Packit ae235b
 * Since: 2.32
Packit ae235b
 */
Packit ae235b
gboolean
Packit ae235b
g_network_monitor_get_network_available (GNetworkMonitor *monitor)
Packit ae235b
{
Packit ae235b
  gboolean available = FALSE;
Packit ae235b
Packit ae235b
  g_object_get (G_OBJECT (monitor), "network-available", &available, NULL);
Packit ae235b
  return available;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_network_monitor_get_network_metered:
Packit ae235b
 * @monitor: the #GNetworkMonitor
Packit ae235b
 *
Packit ae235b
 * Checks if the network is metered.
Packit ae235b
 * See #GNetworkMonitor:network-metered for more details.
Packit ae235b
 *
Packit ae235b
 * Returns: whether the connection is metered
Packit ae235b
 *
Packit ae235b
 * Since: 2.46
Packit ae235b
 */
Packit ae235b
gboolean
Packit ae235b
g_network_monitor_get_network_metered (GNetworkMonitor *monitor)
Packit ae235b
{
Packit ae235b
  gboolean metered = FALSE;
Packit ae235b
Packit ae235b
  g_object_get (G_OBJECT (monitor), "network-metered", &metered, NULL);
Packit ae235b
  return metered;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_network_monitor_get_connectivity:
Packit ae235b
 * @monitor: the #GNetworkMonitor
Packit ae235b
 *
Packit ae235b
 * Gets a more detailed networking state than
Packit ae235b
 * g_network_monitor_get_network_available().
Packit ae235b
 *
Packit ae235b
 * If #GNetworkMonitor:network-available is %FALSE, then the
Packit ae235b
 * connectivity state will be %G_NETWORK_CONNECTIVITY_LOCAL.
Packit ae235b
 *
Packit ae235b
 * If #GNetworkMonitor:network-available is %TRUE, then the
Packit ae235b
 * connectivity state will be %G_NETWORK_CONNECTIVITY_FULL (if there
Packit ae235b
 * is full Internet connectivity), %G_NETWORK_CONNECTIVITY_LIMITED (if
Packit ae235b
 * the host has a default route, but appears to be unable to actually
Packit ae235b
 * reach the full Internet), or %G_NETWORK_CONNECTIVITY_PORTAL (if the
Packit ae235b
 * host is trapped behind a "captive portal" that requires some sort
Packit ae235b
 * of login or acknowledgement before allowing full Internet access).
Packit ae235b
 *
Packit ae235b
 * Note that in the case of %G_NETWORK_CONNECTIVITY_LIMITED and
Packit ae235b
 * %G_NETWORK_CONNECTIVITY_PORTAL, it is possible that some sites are
Packit ae235b
 * reachable but others are not. In this case, applications can
Packit ae235b
 * attempt to connect to remote servers, but should gracefully fall
Packit ae235b
 * back to their "offline" behavior if the connection attempt fails.
Packit ae235b
 *
Packit ae235b
 * Return value: the network connectivity state
Packit ae235b
 *
Packit ae235b
 * Since: 2.44
Packit ae235b
 */
Packit ae235b
GNetworkConnectivity
Packit ae235b
g_network_monitor_get_connectivity (GNetworkMonitor *monitor)
Packit ae235b
{
Packit ae235b
  GNetworkConnectivity connectivity;
Packit ae235b
Packit ae235b
  g_object_get (G_OBJECT (monitor), "connectivity", &connectivity, NULL);
Packit ae235b
Packit ae235b
  return connectivity;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_network_monitor_can_reach:
Packit ae235b
 * @monitor: a #GNetworkMonitor
Packit ae235b
 * @connectable: a #GSocketConnectable
Packit ae235b
 * @cancellable: (nullable): a #GCancellable, or %NULL
Packit ae235b
 * @error: return location for a #GError, or %NULL
Packit ae235b
 *
Packit ae235b
 * Attempts to determine whether or not the host pointed to by
Packit ae235b
 * @connectable can be reached, without actually trying to connect to
Packit ae235b
 * it.
Packit ae235b
 *
Packit ae235b
 * This may return %TRUE even when #GNetworkMonitor:network-available
Packit ae235b
 * is %FALSE, if, for example, @monitor can determine that
Packit ae235b
 * @connectable refers to a host on a local network.
Packit ae235b
 *
Packit ae235b
 * If @monitor believes that an attempt to connect to @connectable
Packit ae235b
 * will succeed, it will return %TRUE. Otherwise, it will return
Packit ae235b
 * %FALSE and set @error to an appropriate error (such as
Packit ae235b
 * %G_IO_ERROR_HOST_UNREACHABLE).
Packit ae235b
 *
Packit ae235b
 * Note that although this does not attempt to connect to
Packit ae235b
 * @connectable, it may still block for a brief period of time (eg,
Packit ae235b
 * trying to do multicast DNS on the local network), so if you do not
Packit ae235b
 * want to block, you should use g_network_monitor_can_reach_async().
Packit ae235b
 *
Packit ae235b
 * Returns: %TRUE if @connectable is reachable, %FALSE if not.
Packit ae235b
 *
Packit ae235b
 * Since: 2.32
Packit ae235b
 */
Packit ae235b
gboolean
Packit ae235b
g_network_monitor_can_reach (GNetworkMonitor     *monitor,
Packit ae235b
                             GSocketConnectable  *connectable,
Packit ae235b
                             GCancellable        *cancellable,
Packit ae235b
                             GError             **error)
Packit ae235b
{
Packit ae235b
  GNetworkMonitorInterface *iface;
Packit ae235b
Packit ae235b
  iface = G_NETWORK_MONITOR_GET_INTERFACE (monitor);
Packit ae235b
  return iface->can_reach (monitor, connectable, cancellable, error);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
g_network_monitor_real_can_reach_async (GNetworkMonitor     *monitor,
Packit ae235b
                                        GSocketConnectable  *connectable,
Packit ae235b
                                        GCancellable        *cancellable,
Packit ae235b
                                        GAsyncReadyCallback  callback,
Packit ae235b
                                        gpointer             user_data)
Packit ae235b
{
Packit ae235b
  GTask *task;
Packit ae235b
  GError *error = NULL;
Packit ae235b
Packit ae235b
  task = g_task_new (monitor, cancellable, callback, user_data);
Packit ae235b
  g_task_set_source_tag (task, g_network_monitor_real_can_reach_async);
Packit ae235b
Packit ae235b
  if (g_network_monitor_can_reach (monitor, connectable, cancellable, &error))
Packit ae235b
    g_task_return_boolean (task, TRUE);
Packit ae235b
  else
Packit ae235b
    g_task_return_error (task, error);
Packit ae235b
  g_object_unref (task);
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_network_monitor_can_reach_async:
Packit ae235b
 * @monitor: a #GNetworkMonitor
Packit ae235b
 * @connectable: a #GSocketConnectable
Packit ae235b
 * @cancellable: (nullable): a #GCancellable, or %NULL
Packit ae235b
 * @callback: (scope async): a #GAsyncReadyCallback to call when the
Packit ae235b
 *     request is satisfied
Packit ae235b
 * @user_data: (closure): the data to pass to callback function
Packit ae235b
 *
Packit ae235b
 * Asynchronously attempts to determine whether or not the host
Packit ae235b
 * pointed to by @connectable can be reached, without actually
Packit ae235b
 * trying to connect to it.
Packit ae235b
 *
Packit ae235b
 * For more details, see g_network_monitor_can_reach().
Packit ae235b
 *
Packit ae235b
 * When the operation is finished, @callback will be called.
Packit ae235b
 * You can then call g_network_monitor_can_reach_finish()
Packit ae235b
 * to get the result of the operation.
Packit ae235b
 */
Packit ae235b
void
Packit ae235b
g_network_monitor_can_reach_async (GNetworkMonitor     *monitor,
Packit ae235b
                                   GSocketConnectable  *connectable,
Packit ae235b
                                   GCancellable        *cancellable,
Packit ae235b
                                   GAsyncReadyCallback  callback,
Packit ae235b
                                   gpointer             user_data)
Packit ae235b
{
Packit ae235b
  GNetworkMonitorInterface *iface;
Packit ae235b
Packit ae235b
  iface = G_NETWORK_MONITOR_GET_INTERFACE (monitor);
Packit ae235b
  iface->can_reach_async (monitor, connectable, cancellable, callback, user_data);
Packit ae235b
}
Packit ae235b
Packit ae235b
static gboolean
Packit ae235b
g_network_monitor_real_can_reach_finish (GNetworkMonitor  *monitor,
Packit ae235b
                                         GAsyncResult     *result,
Packit ae235b
                                         GError          **error)
Packit ae235b
{
Packit ae235b
  g_return_val_if_fail (g_task_is_valid (result, monitor), FALSE);
Packit ae235b
Packit ae235b
  return g_task_propagate_boolean (G_TASK (result), error);
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_network_monitor_can_reach_finish:
Packit ae235b
 * @monitor: a #GNetworkMonitor
Packit ae235b
 * @result: a #GAsyncResult
Packit ae235b
 * @error: return location for errors, or %NULL
Packit ae235b
 *
Packit ae235b
 * Finishes an async network connectivity test.
Packit ae235b
 * See g_network_monitor_can_reach_async().
Packit ae235b
 *
Packit ae235b
 * Returns: %TRUE if network is reachable, %FALSE if not.
Packit ae235b
 */
Packit ae235b
gboolean
Packit ae235b
g_network_monitor_can_reach_finish (GNetworkMonitor     *monitor,
Packit ae235b
                                    GAsyncResult        *result,
Packit ae235b
                                    GError             **error)
Packit ae235b
{
Packit ae235b
  GNetworkMonitorInterface *iface;
Packit ae235b
Packit ae235b
  iface = G_NETWORK_MONITOR_GET_INTERFACE (monitor);
Packit ae235b
  return iface->can_reach_finish (monitor, result, error);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
g_network_monitor_default_init (GNetworkMonitorInterface *iface)
Packit ae235b
{
Packit ae235b
  iface->can_reach_async  = g_network_monitor_real_can_reach_async;
Packit ae235b
  iface->can_reach_finish = g_network_monitor_real_can_reach_finish;
Packit ae235b
Packit ae235b
  /**
Packit ae235b
   * GNetworkMonitor::network-changed:
Packit ae235b
   * @monitor: a #GNetworkMonitor
Packit ae235b
   * @network_available: the current value of #GNetworkMonitor:network-available
Packit ae235b
   *
Packit ae235b
   * Emitted when the network configuration changes.
Packit ae235b
   *
Packit ae235b
   * Since: 2.32
Packit ae235b
   */
Packit ae235b
  signals[NETWORK_CHANGED] =
Packit ae235b
    g_signal_new (I_("network-changed"),
Packit ae235b
                  G_TYPE_NETWORK_MONITOR,
Packit ae235b
                  G_SIGNAL_RUN_LAST,
Packit ae235b
                  G_STRUCT_OFFSET (GNetworkMonitorInterface, network_changed),
Packit ae235b
                  NULL, NULL,
Packit ae235b
                  g_cclosure_marshal_VOID__BOOLEAN,
Packit ae235b
                  G_TYPE_NONE, 1,
Packit ae235b
                  G_TYPE_BOOLEAN);
Packit ae235b
Packit ae235b
  /**
Packit ae235b
   * GNetworkMonitor:network-available:
Packit ae235b
   *
Packit ae235b
   * Whether the network is considered available. That is, whether the
Packit ae235b
   * system has a default route for at least one of IPv4 or IPv6.
Packit ae235b
   *
Packit ae235b
   * Real-world networks are of course much more complicated than
Packit ae235b
   * this; the machine may be connected to a wifi hotspot that
Packit ae235b
   * requires payment before allowing traffic through, or may be
Packit ae235b
   * connected to a functioning router that has lost its own upstream
Packit ae235b
   * connectivity. Some hosts might only be accessible when a VPN is
Packit ae235b
   * active. Other hosts might only be accessible when the VPN is
Packit ae235b
   * not active. Thus, it is best to use g_network_monitor_can_reach()
Packit ae235b
   * or g_network_monitor_can_reach_async() to test for reachability
Packit ae235b
   * on a host-by-host basis. (On the other hand, when the property is
Packit ae235b
   * %FALSE, the application can reasonably expect that no remote
Packit ae235b
   * hosts at all are reachable, and should indicate this to the user
Packit ae235b
   * in its UI.)
Packit ae235b
   *
Packit ae235b
   * See also #GNetworkMonitor::network-changed.
Packit ae235b
   *
Packit ae235b
   * Since: 2.32
Packit ae235b
   */
Packit ae235b
  g_object_interface_install_property (iface,
Packit ae235b
                                       g_param_spec_boolean ("network-available",
Packit ae235b
                                                             P_("Network available"),
Packit ae235b
                                                             P_("Whether the network is available"),
Packit ae235b
                                                             FALSE,
Packit ae235b
                                                             G_PARAM_READABLE |
Packit ae235b
                                                             G_PARAM_STATIC_STRINGS));
Packit ae235b
Packit ae235b
  /**
Packit ae235b
   * GNetworkMonitor:network-metered:
Packit ae235b
   *
Packit ae235b
   * Whether the network is considered metered. That is, whether the
Packit ae235b
   * system has traffic flowing through the default connection that is
Packit ae235b
   * subject to limitations set by service providers. For example, traffic
Packit ae235b
   * might be billed by the amount of data transmitted, or there might be a
Packit ae235b
   * quota on the amount of traffic per month. This is typical with tethered
Packit ae235b
   * connections (3G and 4G) and in such situations, bandwidth intensive
Packit ae235b
   * applications may wish to avoid network activity where possible if it will
Packit ae235b
   * cost the user money or use up their limited quota.
Packit ae235b
   *
Packit ae235b
   * If more information is required about specific devices then the
Packit ae235b
   * system network management API should be used instead (for example,
Packit ae235b
   * NetworkManager or ConnMan).
Packit ae235b
   *
Packit ae235b
   * If this information is not available then no networks will be
Packit ae235b
   * marked as metered.
Packit ae235b
   *
Packit ae235b
   * See also #GNetworkMonitor:network-available.
Packit ae235b
   *
Packit ae235b
   * Since: 2.46
Packit ae235b
   */
Packit ae235b
  g_object_interface_install_property (iface,
Packit ae235b
                                       g_param_spec_boolean ("network-metered",
Packit ae235b
                                                             P_("Network metered"),
Packit ae235b
                                                             P_("Whether the network is metered"),
Packit ae235b
                                                             FALSE,
Packit ae235b
                                                             G_PARAM_READABLE |
Packit ae235b
                                                             G_PARAM_STATIC_STRINGS));
Packit ae235b
Packit ae235b
  /**
Packit ae235b
   * GNetworkMonitor:connectivity:
Packit ae235b
   *
Packit ae235b
   * More detailed information about the host's network connectivity.
Packit ae235b
   * See g_network_monitor_get_connectivity() and
Packit ae235b
   * #GNetworkConnectivity for more details.
Packit ae235b
   *
Packit ae235b
   * Since: 2.44
Packit ae235b
   */
Packit ae235b
  g_object_interface_install_property (iface,
Packit ae235b
                                       g_param_spec_enum ("connectivity",
Packit ae235b
                                                          P_("Network connectivity"),
Packit ae235b
                                                          P_("Level of network connectivity"),
Packit ae235b
                                                          G_TYPE_NETWORK_CONNECTIVITY,
Packit ae235b
                                                          G_NETWORK_CONNECTIVITY_FULL,
Packit ae235b
                                                          G_PARAM_READABLE |
Packit ae235b
                                                          G_PARAM_STATIC_STRINGS));
Packit ae235b
}