1 /* GIO - GLib Input, Output and Streaming Library
2 *
3 * Copyright 2011 Red Hat, Inc.
4 *
5 * SPDX-License-Identifier: LGPL-2.1-or-later
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General
18 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "config.h"
22
23 #include "gnetworkmonitorbase.h"
24 #include "ginetaddress.h"
25 #include "ginetaddressmask.h"
26 #include "ginetsocketaddress.h"
27 #include "ginitable.h"
28 #include "gioerror.h"
29 #include "giomodule-priv.h"
30 #include "gnetworkmonitor.h"
31 #include "gsocketaddressenumerator.h"
32 #include "gsocketconnectable.h"
33 #include "gtask.h"
34 #include "glibintl.h"
35
36 static void g_network_monitor_base_iface_init (GNetworkMonitorInterface *iface);
37 static void g_network_monitor_base_initable_iface_init (GInitableIface *iface);
38
39 enum
40 {
41 PROP_0,
42
43 PROP_NETWORK_AVAILABLE,
44 PROP_NETWORK_METERED,
45 PROP_CONNECTIVITY
46 };
47
48 struct _GNetworkMonitorBasePrivate
49 {
50 GHashTable *networks /* (element-type GInetAddressMask) (owned) */;
51 gboolean have_ipv4_default_route;
52 gboolean have_ipv6_default_route;
53 gboolean is_available;
54
55 GMainContext *context;
56 GSource *network_changed_source;
57 gboolean initializing;
58 };
59
60 static guint network_changed_signal = 0;
61
62 static void queue_network_changed (GNetworkMonitorBase *monitor);
63 static guint inet_address_mask_hash (gconstpointer key);
64 static gboolean inet_address_mask_equal (gconstpointer a,
65 gconstpointer b);
66
67 G_DEFINE_TYPE_WITH_CODE (GNetworkMonitorBase, g_network_monitor_base, G_TYPE_OBJECT,
68 G_ADD_PRIVATE (GNetworkMonitorBase)
69 G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
70 g_network_monitor_base_initable_iface_init)
71 G_IMPLEMENT_INTERFACE (G_TYPE_NETWORK_MONITOR,
72 g_network_monitor_base_iface_init)
73 _g_io_modules_ensure_extension_points_registered ();
74 g_io_extension_point_implement (G_NETWORK_MONITOR_EXTENSION_POINT_NAME,
75 g_define_type_id,
76 "base",
77 0))
78
79 static void
80 g_network_monitor_base_init (GNetworkMonitorBase *monitor)
81 {
82 monitor->priv = g_network_monitor_base_get_instance_private (monitor);
83 monitor->priv->networks = g_hash_table_new_full (inet_address_mask_hash,
84 inet_address_mask_equal,
85 g_object_unref, NULL);
86 monitor->priv->context = g_main_context_get_thread_default ();
87 if (monitor->priv->context)
88 g_main_context_ref (monitor->priv->context);
89
90 monitor->priv->initializing = TRUE;
91 }
92
93 static void
94 g_network_monitor_base_constructed (GObject *object)
95 {
96 GNetworkMonitorBase *monitor = G_NETWORK_MONITOR_BASE (object);
97
98 if (G_OBJECT_TYPE (monitor) == G_TYPE_NETWORK_MONITOR_BASE)
99 {
100 GInetAddressMask *mask;
101
102 /* We're the dumb base class, not a smarter subclass. So just
103 * assume that the network is available.
104 */
105 mask = g_inet_address_mask_new_from_string ("0.0.0.0/0", NULL);
106 g_network_monitor_base_add_network (monitor, mask);
107 g_object_unref (mask);
108
109 mask = g_inet_address_mask_new_from_string ("::/0", NULL);
110 if (mask)
111 {
112 /* On some environments (for example Windows without IPv6 support
113 * enabled) the string "::/0" can't be processed and causes
114 * g_inet_address_mask_new_from_string to return NULL */
115 g_network_monitor_base_add_network (monitor, mask);
116 g_object_unref (mask);
117 }
118 }
119 }
120
121 static void
122 g_network_monitor_base_get_property (GObject *object,
123 guint prop_id,
124 GValue *value,
125 GParamSpec *pspec)
126 {
127 GNetworkMonitorBase *monitor = G_NETWORK_MONITOR_BASE (object);
128
129 switch (prop_id)
130 {
131 case PROP_NETWORK_AVAILABLE:
132 g_value_set_boolean (value, monitor->priv->is_available);
133 break;
134
135 case PROP_NETWORK_METERED:
136 /* Default to FALSE in the unknown case. */
137 g_value_set_boolean (value, FALSE);
138 break;
139
140 case PROP_CONNECTIVITY:
141 g_value_set_enum (value,
142 monitor->priv->is_available ?
143 G_NETWORK_CONNECTIVITY_FULL :
144 G_NETWORK_CONNECTIVITY_LOCAL);
145 break;
146
147 default:
148 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
149 break;
150 }
151
152 }
153
154 static void
155 g_network_monitor_base_finalize (GObject *object)
156 {
157 GNetworkMonitorBase *monitor = G_NETWORK_MONITOR_BASE (object);
158
159 g_hash_table_unref (monitor->priv->networks);
160 if (monitor->priv->network_changed_source)
161 {
162 g_source_destroy (monitor->priv->network_changed_source);
163 g_source_unref (monitor->priv->network_changed_source);
164 }
165 if (monitor->priv->context)
166 g_main_context_unref (monitor->priv->context);
167
168 G_OBJECT_CLASS (g_network_monitor_base_parent_class)->finalize (object);
169 }
170
171 static void
172 g_network_monitor_base_class_init (GNetworkMonitorBaseClass *monitor_class)
173 {
174 GObjectClass *gobject_class = G_OBJECT_CLASS (monitor_class);
175
176 gobject_class->constructed = g_network_monitor_base_constructed;
177 gobject_class->get_property = g_network_monitor_base_get_property;
178 gobject_class->finalize = g_network_monitor_base_finalize;
179
180 g_object_class_override_property (gobject_class, PROP_NETWORK_AVAILABLE, "network-available");
181 g_object_class_override_property (gobject_class, PROP_NETWORK_METERED, "network-metered");
182 g_object_class_override_property (gobject_class, PROP_CONNECTIVITY, "connectivity");
183 }
184
185 static gboolean
186 g_network_monitor_base_can_reach_sockaddr (GNetworkMonitorBase *base,
187 GSocketAddress *sockaddr)
188 {
189 GInetAddress *iaddr;
190 GHashTableIter iter;
191 gpointer key;
192
193 if (!G_IS_INET_SOCKET_ADDRESS (sockaddr))
194 return FALSE;
195
196 iaddr = g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (sockaddr));
197 g_hash_table_iter_init (&iter, base->priv->networks);
198 while (g_hash_table_iter_next (&iter, &key, NULL))
199 {
200 GInetAddressMask *mask = key;
201 if (g_inet_address_mask_matches (mask, iaddr))
202 return TRUE;
203 }
204
205 return FALSE;
206 }
207
208 static gboolean
209 g_network_monitor_base_can_reach (GNetworkMonitor *monitor,
210 GSocketConnectable *connectable,
211 GCancellable *cancellable,
212 GError **error)
213 {
214 GNetworkMonitorBase *base = G_NETWORK_MONITOR_BASE (monitor);
215 GSocketAddressEnumerator *enumerator;
216 GSocketAddress *addr;
217
218 if (g_hash_table_size (base->priv->networks) == 0)
219 {
220 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NETWORK_UNREACHABLE,
221 _("Network unreachable"));
222 return FALSE;
223 }
224
225 enumerator = g_socket_connectable_proxy_enumerate (connectable);
226 addr = g_socket_address_enumerator_next (enumerator, cancellable, error);
227 if (!addr)
228 {
229 /* Either the user cancelled, or DNS resolution failed */
230 g_object_unref (enumerator);
231 return FALSE;
232 }
233
234 if (base->priv->have_ipv4_default_route &&
235 base->priv->have_ipv6_default_route)
236 {
237 g_object_unref (enumerator);
238 g_object_unref (addr);
239 return TRUE;
240 }
241
242 while (addr)
243 {
244 if (g_network_monitor_base_can_reach_sockaddr (base, addr))
245 {
246 g_object_unref (addr);
247 g_object_unref (enumerator);
248 return TRUE;
249 }
250
251 g_object_unref (addr);
252 addr = g_socket_address_enumerator_next (enumerator, cancellable, error);
253 }
254 g_object_unref (enumerator);
255
256 if (error && !*error)
257 {
258 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_HOST_UNREACHABLE,
259 _("Host unreachable"));
260 }
261 return FALSE;
262 }
263
264 static void
265 can_reach_async_got_address (GObject *object,
266 GAsyncResult *result,
267 gpointer user_data)
268 {
269 GSocketAddressEnumerator *enumerator = G_SOCKET_ADDRESS_ENUMERATOR (object);
270 GTask *task = user_data;
271 GNetworkMonitorBase *base = g_task_get_source_object (task);
272 GSocketAddress *addr;
273 GError *error = NULL;
274
275 addr = g_socket_address_enumerator_next_finish (enumerator, result, &error);
276 if (!addr)
277 {
278 if (error)
279 {
280 /* Either the user cancelled, or DNS resolution failed */
281 g_task_return_error (task, error);
282 g_object_unref (task);
283 return;
284 }
285 else
286 {
287 /* Resolved all addresses, none matched */
288 g_task_return_new_error_literal (task, G_IO_ERROR,
289 G_IO_ERROR_HOST_UNREACHABLE,
290 _("Host unreachable"));
291 g_object_unref (task);
292 return;
293 }
294 }
295
296 if (g_network_monitor_base_can_reach_sockaddr (base, addr))
297 {
298 g_object_unref (addr);
299 g_task_return_boolean (task, TRUE);
300 g_object_unref (task);
301 return;
302 }
303 g_object_unref (addr);
304
305 g_socket_address_enumerator_next_async (enumerator,
306 g_task_get_cancellable (task),
307 can_reach_async_got_address, task);
308 }
309
310 static void
311 g_network_monitor_base_can_reach_async (GNetworkMonitor *monitor,
312 GSocketConnectable *connectable,
313 GCancellable *cancellable,
314 GAsyncReadyCallback callback,
315 gpointer user_data)
316 {
317 GTask *task;
318 GSocketAddressEnumerator *enumerator;
319
320 task = g_task_new (monitor, cancellable, callback, user_data);
321 g_task_set_source_tag (task, g_network_monitor_base_can_reach_async);
322
323 if (g_hash_table_size (G_NETWORK_MONITOR_BASE (monitor)->priv->networks) == 0)
324 {
325 g_task_return_new_error_literal (task, G_IO_ERROR, G_IO_ERROR_NETWORK_UNREACHABLE,
326 _("Network unreachable"));
327 g_object_unref (task);
328 return;
329 }
330
331 enumerator = g_socket_connectable_proxy_enumerate (connectable);
332 g_socket_address_enumerator_next_async (enumerator, cancellable,
333 can_reach_async_got_address, task);
334 g_object_unref (enumerator);
335 }
336
337 static gboolean
338 g_network_monitor_base_can_reach_finish (GNetworkMonitor *monitor,
339 GAsyncResult *result,
340 GError **error)
341 {
342 g_return_val_if_fail (g_task_is_valid (result, monitor), FALSE);
343
344 return g_task_propagate_boolean (G_TASK (result), error);
345 }
346
347 static void
348 g_network_monitor_base_iface_init (GNetworkMonitorInterface *monitor_iface)
349 {
350 monitor_iface->can_reach = g_network_monitor_base_can_reach;
351 monitor_iface->can_reach_async = g_network_monitor_base_can_reach_async;
352 monitor_iface->can_reach_finish = g_network_monitor_base_can_reach_finish;
353
354 network_changed_signal = g_signal_lookup ("network-changed", G_TYPE_NETWORK_MONITOR);
355 }
356
357 static gboolean
358 g_network_monitor_base_initable_init (GInitable *initable,
359 GCancellable *cancellable,
360 GError **error)
361 {
362 GNetworkMonitorBase *base = G_NETWORK_MONITOR_BASE (initable);
363
364 base->priv->initializing = FALSE;
365
366 return TRUE;
367 }
368
369 static void
370 g_network_monitor_base_initable_iface_init (GInitableIface *iface)
371 {
372 iface->init = g_network_monitor_base_initable_init;
373 }
374
375 static guint
376 inet_address_mask_hash (gconstpointer key)
377 {
378 GInetAddressMask *mask = G_INET_ADDRESS_MASK (key);
379 guint addr_hash;
380 guint mask_length = g_inet_address_mask_get_length (mask);
381 GInetAddress *addr = g_inet_address_mask_get_address (mask);
382 const guint8 *bytes = g_inet_address_to_bytes (addr);
383 gsize bytes_length = g_inet_address_get_native_size (addr);
384
385 union
386 {
387 const guint8 *bytes;
388 guint32 *hash32;
389 guint64 *hash64;
390 } integerifier;
391
392 /* If we can fit the entire address into the hash key, do it. Don’t worry
393 * about endianness; the address should always be in network endianness. */
394 if (bytes_length == sizeof (guint32))
395 {
396 integerifier.bytes = bytes;
397 addr_hash = *integerifier.hash32;
398 }
399 else if (bytes_length == sizeof (guint64))
400 {
401 integerifier.bytes = bytes;
402 addr_hash = *integerifier.hash64;
403 }
404 else
405 {
406 gsize i;
407
408 /* Otherwise, fall back to adding the bytes together. We do this, rather
409 * than XORing them, as routes often have repeated tuples which would
410 * cancel out under XOR. */
411 addr_hash = 0;
412 for (i = 0; i < bytes_length; i++)
413 addr_hash += bytes[i];
414 }
415
416 return addr_hash + mask_length;;
417 }
418
419 static gboolean
420 inet_address_mask_equal (gconstpointer a,
421 gconstpointer b)
422 {
423 GInetAddressMask *mask_a = G_INET_ADDRESS_MASK (a);
424 GInetAddressMask *mask_b = G_INET_ADDRESS_MASK (b);
425
426 return g_inet_address_mask_equal (mask_a, mask_b);
427 }
428
429 static gboolean
430 emit_network_changed (gpointer user_data)
431 {
432 GNetworkMonitorBase *monitor = user_data;
433 gboolean is_available;
434
435 if (g_source_is_destroyed (g_main_current_source ()))
436 return FALSE;
437
438 g_object_ref (monitor);
439
440 is_available = (monitor->priv->have_ipv4_default_route ||
441 monitor->priv->have_ipv6_default_route);
442 if (monitor->priv->is_available != is_available)
443 {
444 monitor->priv->is_available = is_available;
445 g_object_notify (G_OBJECT (monitor), "network-available");
446 }
447
448 g_signal_emit (monitor, network_changed_signal, 0, is_available);
449
450 g_source_unref (monitor->priv->network_changed_source);
451 monitor->priv->network_changed_source = NULL;
452
453 g_object_unref (monitor);
454 return FALSE;
455 }
456
457 static void
458 queue_network_changed (GNetworkMonitorBase *monitor)
459 {
460 if (!monitor->priv->network_changed_source &&
461 !monitor->priv->initializing)
462 {
463 GSource *source;
464
465 source = g_idle_source_new ();
466 /* Use G_PRIORITY_HIGH_IDLE priority so that multiple
467 * network-change-related notifications coming in at
468 * G_PRIORITY_DEFAULT will get coalesced into one signal
469 * emission.
470 */
471 g_source_set_priority (source, G_PRIORITY_HIGH_IDLE);
472 g_source_set_callback (source, emit_network_changed, monitor, NULL);
473 g_source_set_static_name (source, "[gio] emit_network_changed");
474 g_source_attach (source, monitor->priv->context);
475 monitor->priv->network_changed_source = source;
476 }
477
478 /* Normally we wait to update is_available until we emit the signal,
479 * to keep things consistent. But when we're first creating the
480 * object, we want it to be correct right away.
481 */
482 if (monitor->priv->initializing)
483 {
484 monitor->priv->is_available = (monitor->priv->have_ipv4_default_route ||
485 monitor->priv->have_ipv6_default_route);
486 }
487 }
488
489 /**
490 * g_network_monitor_base_add_network:
491 * @monitor: the #GNetworkMonitorBase
492 * @network: (transfer none): a #GInetAddressMask
493 *
494 * Adds @network to @monitor's list of available networks.
495 *
496 * Since: 2.32
497 */
498 void
499 g_network_monitor_base_add_network (GNetworkMonitorBase *monitor,
500 GInetAddressMask *network)
501 {
502 if (!g_hash_table_add (monitor->priv->networks, g_object_ref (network)))
503 return;
504
505 if (g_inet_address_mask_get_length (network) == 0)
506 {
507 switch (g_inet_address_mask_get_family (network))
508 {
509 case G_SOCKET_FAMILY_IPV4:
510 monitor->priv->have_ipv4_default_route = TRUE;
511 break;
512 case G_SOCKET_FAMILY_IPV6:
513 monitor->priv->have_ipv6_default_route = TRUE;
514 break;
515 default:
516 break;
517 }
518 }
519
520 /* Don't emit network-changed when multicast-link-local routing
521 * changes. This rather arbitrary decision is mostly because it
522 * seems to change quite often...
523 */
524 if (g_inet_address_get_is_mc_link_local (g_inet_address_mask_get_address (network)))
525 return;
526
527 queue_network_changed (monitor);
528 }
529
530 /**
531 * g_network_monitor_base_remove_network:
532 * @monitor: the #GNetworkMonitorBase
533 * @network: a #GInetAddressMask
534 *
535 * Removes @network from @monitor's list of available networks.
536 *
537 * Since: 2.32
538 */
539 void
540 g_network_monitor_base_remove_network (GNetworkMonitorBase *monitor,
541 GInetAddressMask *network)
542 {
543 if (!g_hash_table_remove (monitor->priv->networks, network))
544 return;
545
546 if (g_inet_address_mask_get_length (network) == 0)
547 {
548 switch (g_inet_address_mask_get_family (network))
549 {
550 case G_SOCKET_FAMILY_IPV4:
551 monitor->priv->have_ipv4_default_route = FALSE;
552 break;
553 case G_SOCKET_FAMILY_IPV6:
554 monitor->priv->have_ipv6_default_route = FALSE;
555 break;
556 default:
557 break;
558 }
559 }
560
561 queue_network_changed (monitor);
562 }
563
564 /**
565 * g_network_monitor_base_set_networks:
566 * @monitor: the #GNetworkMonitorBase
567 * @networks: (array length=length): an array of #GInetAddressMask
568 * @length: length of @networks
569 *
570 * Drops @monitor's current list of available networks and replaces
571 * it with @networks.
572 */
573 void
574 g_network_monitor_base_set_networks (GNetworkMonitorBase *monitor,
575 GInetAddressMask **networks,
576 gint length)
577 {
578 int i;
579
580 g_hash_table_remove_all (monitor->priv->networks);
581 monitor->priv->have_ipv4_default_route = FALSE;
582 monitor->priv->have_ipv6_default_route = FALSE;
583
584 for (i = 0; i < length; i++)
585 g_network_monitor_base_add_network (monitor, networks[i]);
586 }