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