1/* GIO - GLib Input, Output and Streaming Library
2 *
3 * Copyright 2011 Red Hat, Inc
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General
16 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include "config.h"
20#include "glib.h"
21#include "glibintl.h"
22
23#include "gnetworkmonitor.h"
24#include "ginetaddress.h"
25#include "ginetsocketaddress.h"
26#include "ginitable.h"
27#include "gioenumtypes.h"
28#include "giomodule-priv.h"
29#include "gtask.h"
30
31/**
32 * SECTION:gnetworkmonitor
33 * @title: GNetworkMonitor
34 * @short_description: Network status monitor
35 * @include: gio/gio.h
36 *
37 * #GNetworkMonitor provides an easy-to-use cross-platform API
38 * for monitoring network connectivity. On Linux, the available
39 * implementations are based on the kernel's netlink interface and
40 * on NetworkManager.
41 *
42 * There is also an implementation for use inside Flatpak sandboxes.
43 */
44
45/**
46 * GNetworkMonitor:
47 *
48 * #GNetworkMonitor monitors the status of network connections and
49 * indicates when a possibly-user-visible change has occurred.
50 *
51 * Since: 2.32
52 */
53
54/**
55 * GNetworkMonitorInterface:
56 * @g_iface: The parent interface.
57 * @network_changed: the virtual function pointer for the
58 * GNetworkMonitor::network-changed signal.
59 * @can_reach: the virtual function pointer for g_network_monitor_can_reach()
60 * @can_reach_async: the virtual function pointer for
61 * g_network_monitor_can_reach_async()
62 * @can_reach_finish: the virtual function pointer for
63 * g_network_monitor_can_reach_finish()
64 *
65 * The virtual function table for #GNetworkMonitor.
66 *
67 * Since: 2.32
68 */
69
70G_DEFINE_INTERFACE_WITH_CODE (GNetworkMonitor, g_network_monitor, G_TYPE_OBJECT,
71 g_type_interface_add_prerequisite (g_define_type_id, G_TYPE_INITABLE))
72
73
74enum {
75 NETWORK_CHANGED,
76 LAST_SIGNAL
77};
78
79static guint signals[LAST_SIGNAL] = { 0 };
80static GNetworkMonitor *network_monitor_default_singleton = NULL; /* (owned) (atomic) */
81
82/**
83 * g_network_monitor_get_default:
84 *
85 * Gets the default #GNetworkMonitor for the system.
86 *
87 * Returns: (not nullable) (transfer none): a #GNetworkMonitor, which will be
88 * a dummy object if no network monitor is available
89 *
90 * Since: 2.32
91 */
92GNetworkMonitor *
93g_network_monitor_get_default (void)
94{
95 if (g_once_init_enter (&network_monitor_default_singleton))
96 {
97 GNetworkMonitor *singleton;
98
99 singleton = _g_io_module_get_default (G_NETWORK_MONITOR_EXTENSION_POINT_NAME,
100 envvar: "GIO_USE_NETWORK_MONITOR",
101 NULL);
102
103 g_once_init_leave (&network_monitor_default_singleton, singleton);
104 }
105
106 return network_monitor_default_singleton;
107}
108
109/**
110 * g_network_monitor_get_network_available:
111 * @monitor: the #GNetworkMonitor
112 *
113 * Checks if the network is available. "Available" here means that the
114 * system has a default route available for at least one of IPv4 or
115 * IPv6. It does not necessarily imply that the public Internet is
116 * reachable. See #GNetworkMonitor:network-available for more details.
117 *
118 * Returns: whether the network is available
119 *
120 * Since: 2.32
121 */
122gboolean
123g_network_monitor_get_network_available (GNetworkMonitor *monitor)
124{
125 gboolean available = FALSE;
126
127 g_object_get (G_OBJECT (monitor), first_property_name: "network-available", &available, NULL);
128 return available;
129}
130
131/**
132 * g_network_monitor_get_network_metered:
133 * @monitor: the #GNetworkMonitor
134 *
135 * Checks if the network is metered.
136 * See #GNetworkMonitor:network-metered for more details.
137 *
138 * Returns: whether the connection is metered
139 *
140 * Since: 2.46
141 */
142gboolean
143g_network_monitor_get_network_metered (GNetworkMonitor *monitor)
144{
145 gboolean metered = FALSE;
146
147 g_object_get (G_OBJECT (monitor), first_property_name: "network-metered", &metered, NULL);
148 return metered;
149}
150
151/**
152 * g_network_monitor_get_connectivity:
153 * @monitor: the #GNetworkMonitor
154 *
155 * Gets a more detailed networking state than
156 * g_network_monitor_get_network_available().
157 *
158 * If #GNetworkMonitor:network-available is %FALSE, then the
159 * connectivity state will be %G_NETWORK_CONNECTIVITY_LOCAL.
160 *
161 * If #GNetworkMonitor:network-available is %TRUE, then the
162 * connectivity state will be %G_NETWORK_CONNECTIVITY_FULL (if there
163 * is full Internet connectivity), %G_NETWORK_CONNECTIVITY_LIMITED (if
164 * the host has a default route, but appears to be unable to actually
165 * reach the full Internet), or %G_NETWORK_CONNECTIVITY_PORTAL (if the
166 * host is trapped behind a "captive portal" that requires some sort
167 * of login or acknowledgement before allowing full Internet access).
168 *
169 * Note that in the case of %G_NETWORK_CONNECTIVITY_LIMITED and
170 * %G_NETWORK_CONNECTIVITY_PORTAL, it is possible that some sites are
171 * reachable but others are not. In this case, applications can
172 * attempt to connect to remote servers, but should gracefully fall
173 * back to their "offline" behavior if the connection attempt fails.
174 *
175 * Return value: the network connectivity state
176 *
177 * Since: 2.44
178 */
179GNetworkConnectivity
180g_network_monitor_get_connectivity (GNetworkMonitor *monitor)
181{
182 GNetworkConnectivity connectivity;
183
184 g_object_get (G_OBJECT (monitor), first_property_name: "connectivity", &connectivity, NULL);
185
186 return connectivity;
187}
188
189/**
190 * g_network_monitor_can_reach:
191 * @monitor: a #GNetworkMonitor
192 * @connectable: a #GSocketConnectable
193 * @cancellable: (nullable): a #GCancellable, or %NULL
194 * @error: return location for a #GError, or %NULL
195 *
196 * Attempts to determine whether or not the host pointed to by
197 * @connectable can be reached, without actually trying to connect to
198 * it.
199 *
200 * This may return %TRUE even when #GNetworkMonitor:network-available
201 * is %FALSE, if, for example, @monitor can determine that
202 * @connectable refers to a host on a local network.
203 *
204 * If @monitor believes that an attempt to connect to @connectable
205 * will succeed, it will return %TRUE. Otherwise, it will return
206 * %FALSE and set @error to an appropriate error (such as
207 * %G_IO_ERROR_HOST_UNREACHABLE).
208 *
209 * Note that although this does not attempt to connect to
210 * @connectable, it may still block for a brief period of time (eg,
211 * trying to do multicast DNS on the local network), so if you do not
212 * want to block, you should use g_network_monitor_can_reach_async().
213 *
214 * Returns: %TRUE if @connectable is reachable, %FALSE if not.
215 *
216 * Since: 2.32
217 */
218gboolean
219g_network_monitor_can_reach (GNetworkMonitor *monitor,
220 GSocketConnectable *connectable,
221 GCancellable *cancellable,
222 GError **error)
223{
224 GNetworkMonitorInterface *iface;
225
226 iface = G_NETWORK_MONITOR_GET_INTERFACE (monitor);
227 return iface->can_reach (monitor, connectable, cancellable, error);
228}
229
230static void
231g_network_monitor_real_can_reach_async (GNetworkMonitor *monitor,
232 GSocketConnectable *connectable,
233 GCancellable *cancellable,
234 GAsyncReadyCallback callback,
235 gpointer user_data)
236{
237 GTask *task;
238 GError *error = NULL;
239
240 task = g_task_new (source_object: monitor, cancellable, callback, callback_data: user_data);
241 g_task_set_source_tag (task, g_network_monitor_real_can_reach_async);
242
243 if (g_network_monitor_can_reach (monitor, connectable, cancellable, error: &error))
244 g_task_return_boolean (task, TRUE);
245 else
246 g_task_return_error (task, error);
247 g_object_unref (object: task);
248}
249
250/**
251 * g_network_monitor_can_reach_async:
252 * @monitor: a #GNetworkMonitor
253 * @connectable: a #GSocketConnectable
254 * @cancellable: (nullable): a #GCancellable, or %NULL
255 * @callback: (scope async): a #GAsyncReadyCallback to call when the
256 * request is satisfied
257 * @user_data: (closure): the data to pass to callback function
258 *
259 * Asynchronously attempts to determine whether or not the host
260 * pointed to by @connectable can be reached, without actually
261 * trying to connect to it.
262 *
263 * For more details, see g_network_monitor_can_reach().
264 *
265 * When the operation is finished, @callback will be called.
266 * You can then call g_network_monitor_can_reach_finish()
267 * to get the result of the operation.
268 */
269void
270g_network_monitor_can_reach_async (GNetworkMonitor *monitor,
271 GSocketConnectable *connectable,
272 GCancellable *cancellable,
273 GAsyncReadyCallback callback,
274 gpointer user_data)
275{
276 GNetworkMonitorInterface *iface;
277
278 iface = G_NETWORK_MONITOR_GET_INTERFACE (monitor);
279 iface->can_reach_async (monitor, connectable, cancellable, callback, user_data);
280}
281
282static gboolean
283g_network_monitor_real_can_reach_finish (GNetworkMonitor *monitor,
284 GAsyncResult *result,
285 GError **error)
286{
287 g_return_val_if_fail (g_task_is_valid (result, monitor), FALSE);
288
289 return g_task_propagate_boolean (G_TASK (result), error);
290}
291
292/**
293 * g_network_monitor_can_reach_finish:
294 * @monitor: a #GNetworkMonitor
295 * @result: a #GAsyncResult
296 * @error: return location for errors, or %NULL
297 *
298 * Finishes an async network connectivity test.
299 * See g_network_monitor_can_reach_async().
300 *
301 * Returns: %TRUE if network is reachable, %FALSE if not.
302 */
303gboolean
304g_network_monitor_can_reach_finish (GNetworkMonitor *monitor,
305 GAsyncResult *result,
306 GError **error)
307{
308 GNetworkMonitorInterface *iface;
309
310 iface = G_NETWORK_MONITOR_GET_INTERFACE (monitor);
311 return iface->can_reach_finish (monitor, result, error);
312}
313
314static void
315g_network_monitor_default_init (GNetworkMonitorInterface *iface)
316{
317 iface->can_reach_async = g_network_monitor_real_can_reach_async;
318 iface->can_reach_finish = g_network_monitor_real_can_reach_finish;
319
320 /**
321 * GNetworkMonitor::network-changed:
322 * @monitor: a #GNetworkMonitor
323 * @network_available: the current value of #GNetworkMonitor:network-available
324 *
325 * Emitted when the network configuration changes.
326 *
327 * Since: 2.32
328 */
329 signals[NETWORK_CHANGED] =
330 g_signal_new (I_("network-changed"),
331 G_TYPE_NETWORK_MONITOR,
332 signal_flags: G_SIGNAL_RUN_LAST,
333 G_STRUCT_OFFSET (GNetworkMonitorInterface, network_changed),
334 NULL, NULL,
335 NULL,
336 G_TYPE_NONE, n_params: 1,
337 G_TYPE_BOOLEAN);
338
339 /**
340 * GNetworkMonitor:network-available:
341 *
342 * Whether the network is considered available. That is, whether the
343 * system has a default route for at least one of IPv4 or IPv6.
344 *
345 * Real-world networks are of course much more complicated than
346 * this; the machine may be connected to a wifi hotspot that
347 * requires payment before allowing traffic through, or may be
348 * connected to a functioning router that has lost its own upstream
349 * connectivity. Some hosts might only be accessible when a VPN is
350 * active. Other hosts might only be accessible when the VPN is
351 * not active. Thus, it is best to use g_network_monitor_can_reach()
352 * or g_network_monitor_can_reach_async() to test for reachability
353 * on a host-by-host basis. (On the other hand, when the property is
354 * %FALSE, the application can reasonably expect that no remote
355 * hosts at all are reachable, and should indicate this to the user
356 * in its UI.)
357 *
358 * See also #GNetworkMonitor::network-changed.
359 *
360 * Since: 2.32
361 */
362 g_object_interface_install_property (g_iface: iface,
363 pspec: g_param_spec_boolean (name: "network-available",
364 P_("Network available"),
365 P_("Whether the network is available"),
366 FALSE,
367 flags: G_PARAM_READABLE |
368 G_PARAM_STATIC_STRINGS));
369
370 /**
371 * GNetworkMonitor:network-metered:
372 *
373 * Whether the network is considered metered. That is, whether the
374 * system has traffic flowing through the default connection that is
375 * subject to limitations set by service providers. For example, traffic
376 * might be billed by the amount of data transmitted, or there might be a
377 * quota on the amount of traffic per month. This is typical with tethered
378 * connections (3G and 4G) and in such situations, bandwidth intensive
379 * applications may wish to avoid network activity where possible if it will
380 * cost the user money or use up their limited quota.
381 *
382 * If more information is required about specific devices then the
383 * system network management API should be used instead (for example,
384 * NetworkManager or ConnMan).
385 *
386 * If this information is not available then no networks will be
387 * marked as metered.
388 *
389 * See also #GNetworkMonitor:network-available.
390 *
391 * Since: 2.46
392 */
393 g_object_interface_install_property (g_iface: iface,
394 pspec: g_param_spec_boolean (name: "network-metered",
395 P_("Network metered"),
396 P_("Whether the network is metered"),
397 FALSE,
398 flags: G_PARAM_READABLE |
399 G_PARAM_STATIC_STRINGS));
400
401 /**
402 * GNetworkMonitor:connectivity:
403 *
404 * More detailed information about the host's network connectivity.
405 * See g_network_monitor_get_connectivity() and
406 * #GNetworkConnectivity for more details.
407 *
408 * Since: 2.44
409 */
410 g_object_interface_install_property (g_iface: iface,
411 pspec: g_param_spec_enum (name: "connectivity",
412 P_("Network connectivity"),
413 P_("Level of network connectivity"),
414 enum_type: G_TYPE_NETWORK_CONNECTIVITY,
415 default_value: G_NETWORK_CONNECTIVITY_FULL,
416 flags: G_PARAM_READABLE |
417 G_PARAM_STATIC_STRINGS));
418}
419

source code of gtk/subprojects/glib/gio/gnetworkmonitor.c