/src/glib/gio/gnetworkmonitorbase.c
Line | Count | Source (jump to first uncovered line) |
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 | 0 | { |
82 | 0 | monitor->priv = g_network_monitor_base_get_instance_private (monitor); |
83 | 0 | monitor->priv->networks = g_hash_table_new_full (inet_address_mask_hash, |
84 | 0 | inet_address_mask_equal, |
85 | 0 | g_object_unref, NULL); |
86 | 0 | monitor->priv->context = g_main_context_get_thread_default (); |
87 | 0 | if (monitor->priv->context) |
88 | 0 | g_main_context_ref (monitor->priv->context); |
89 | |
|
90 | 0 | monitor->priv->initializing = TRUE; |
91 | 0 | } |
92 | | |
93 | | static void |
94 | | g_network_monitor_base_constructed (GObject *object) |
95 | 0 | { |
96 | 0 | GNetworkMonitorBase *monitor = G_NETWORK_MONITOR_BASE (object); |
97 | |
|
98 | 0 | if (G_OBJECT_TYPE (monitor) == G_TYPE_NETWORK_MONITOR_BASE) |
99 | 0 | { |
100 | 0 | 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 | 0 | mask = g_inet_address_mask_new_from_string ("0.0.0.0/0", NULL); |
106 | 0 | g_network_monitor_base_add_network (monitor, mask); |
107 | 0 | g_object_unref (mask); |
108 | |
|
109 | 0 | mask = g_inet_address_mask_new_from_string ("::/0", NULL); |
110 | 0 | if (mask) |
111 | 0 | { |
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 | 0 | g_network_monitor_base_add_network (monitor, mask); |
116 | 0 | g_object_unref (mask); |
117 | 0 | } |
118 | 0 | } |
119 | 0 | } |
120 | | |
121 | | static void |
122 | | g_network_monitor_base_get_property (GObject *object, |
123 | | guint prop_id, |
124 | | GValue *value, |
125 | | GParamSpec *pspec) |
126 | 0 | { |
127 | 0 | GNetworkMonitorBase *monitor = G_NETWORK_MONITOR_BASE (object); |
128 | |
|
129 | 0 | switch (prop_id) |
130 | 0 | { |
131 | 0 | case PROP_NETWORK_AVAILABLE: |
132 | 0 | g_value_set_boolean (value, monitor->priv->is_available); |
133 | 0 | break; |
134 | | |
135 | 0 | case PROP_NETWORK_METERED: |
136 | | /* Default to FALSE in the unknown case. */ |
137 | 0 | g_value_set_boolean (value, FALSE); |
138 | 0 | break; |
139 | | |
140 | 0 | case PROP_CONNECTIVITY: |
141 | 0 | g_value_set_enum (value, |
142 | 0 | monitor->priv->is_available ? |
143 | 0 | G_NETWORK_CONNECTIVITY_FULL : |
144 | 0 | G_NETWORK_CONNECTIVITY_LOCAL); |
145 | 0 | break; |
146 | | |
147 | 0 | default: |
148 | 0 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
149 | 0 | break; |
150 | 0 | } |
151 | |
|
152 | 0 | } |
153 | | |
154 | | static void |
155 | | g_network_monitor_base_finalize (GObject *object) |
156 | 0 | { |
157 | 0 | GNetworkMonitorBase *monitor = G_NETWORK_MONITOR_BASE (object); |
158 | |
|
159 | 0 | g_hash_table_unref (monitor->priv->networks); |
160 | 0 | if (monitor->priv->network_changed_source) |
161 | 0 | { |
162 | 0 | g_source_destroy (monitor->priv->network_changed_source); |
163 | 0 | g_source_unref (monitor->priv->network_changed_source); |
164 | 0 | } |
165 | 0 | if (monitor->priv->context) |
166 | 0 | g_main_context_unref (monitor->priv->context); |
167 | |
|
168 | 0 | G_OBJECT_CLASS (g_network_monitor_base_parent_class)->finalize (object); |
169 | 0 | } |
170 | | |
171 | | static void |
172 | | g_network_monitor_base_class_init (GNetworkMonitorBaseClass *monitor_class) |
173 | 0 | { |
174 | 0 | GObjectClass *gobject_class = G_OBJECT_CLASS (monitor_class); |
175 | |
|
176 | 0 | gobject_class->constructed = g_network_monitor_base_constructed; |
177 | 0 | gobject_class->get_property = g_network_monitor_base_get_property; |
178 | 0 | gobject_class->finalize = g_network_monitor_base_finalize; |
179 | |
|
180 | 0 | g_object_class_override_property (gobject_class, PROP_NETWORK_AVAILABLE, "network-available"); |
181 | 0 | g_object_class_override_property (gobject_class, PROP_NETWORK_METERED, "network-metered"); |
182 | 0 | g_object_class_override_property (gobject_class, PROP_CONNECTIVITY, "connectivity"); |
183 | 0 | } |
184 | | |
185 | | static gboolean |
186 | | g_network_monitor_base_can_reach_sockaddr (GNetworkMonitorBase *base, |
187 | | GSocketAddress *sockaddr) |
188 | 0 | { |
189 | 0 | GInetAddress *iaddr; |
190 | 0 | GHashTableIter iter; |
191 | 0 | gpointer key; |
192 | |
|
193 | 0 | if (!G_IS_INET_SOCKET_ADDRESS (sockaddr)) |
194 | 0 | return FALSE; |
195 | | |
196 | 0 | iaddr = g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (sockaddr)); |
197 | 0 | g_hash_table_iter_init (&iter, base->priv->networks); |
198 | 0 | while (g_hash_table_iter_next (&iter, &key, NULL)) |
199 | 0 | { |
200 | 0 | GInetAddressMask *mask = key; |
201 | 0 | if (g_inet_address_mask_matches (mask, iaddr)) |
202 | 0 | return TRUE; |
203 | 0 | } |
204 | | |
205 | 0 | return FALSE; |
206 | 0 | } |
207 | | |
208 | | static gboolean |
209 | | g_network_monitor_base_can_reach (GNetworkMonitor *monitor, |
210 | | GSocketConnectable *connectable, |
211 | | GCancellable *cancellable, |
212 | | GError **error) |
213 | 0 | { |
214 | 0 | GNetworkMonitorBase *base = G_NETWORK_MONITOR_BASE (monitor); |
215 | 0 | GSocketAddressEnumerator *enumerator; |
216 | 0 | GSocketAddress *addr; |
217 | |
|
218 | 0 | if (g_hash_table_size (base->priv->networks) == 0) |
219 | 0 | { |
220 | 0 | g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NETWORK_UNREACHABLE, |
221 | 0 | _("Network unreachable")); |
222 | 0 | return FALSE; |
223 | 0 | } |
224 | | |
225 | 0 | enumerator = g_socket_connectable_proxy_enumerate (connectable); |
226 | 0 | addr = g_socket_address_enumerator_next (enumerator, cancellable, error); |
227 | 0 | if (!addr) |
228 | 0 | { |
229 | | /* Either the user cancelled, or DNS resolution failed */ |
230 | 0 | g_object_unref (enumerator); |
231 | 0 | return FALSE; |
232 | 0 | } |
233 | | |
234 | 0 | if (base->priv->have_ipv4_default_route && |
235 | 0 | base->priv->have_ipv6_default_route) |
236 | 0 | { |
237 | 0 | g_object_unref (enumerator); |
238 | 0 | g_object_unref (addr); |
239 | 0 | return TRUE; |
240 | 0 | } |
241 | | |
242 | 0 | while (addr) |
243 | 0 | { |
244 | 0 | if (g_network_monitor_base_can_reach_sockaddr (base, addr)) |
245 | 0 | { |
246 | 0 | g_object_unref (addr); |
247 | 0 | g_object_unref (enumerator); |
248 | 0 | return TRUE; |
249 | 0 | } |
250 | | |
251 | 0 | g_object_unref (addr); |
252 | 0 | addr = g_socket_address_enumerator_next (enumerator, cancellable, error); |
253 | 0 | } |
254 | 0 | g_object_unref (enumerator); |
255 | |
|
256 | 0 | if (error && !*error) |
257 | 0 | { |
258 | 0 | g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_HOST_UNREACHABLE, |
259 | 0 | _("Host unreachable")); |
260 | 0 | } |
261 | 0 | return FALSE; |
262 | 0 | } |
263 | | |
264 | | static void |
265 | | can_reach_async_got_address (GObject *object, |
266 | | GAsyncResult *result, |
267 | | gpointer user_data) |
268 | 0 | { |
269 | 0 | GSocketAddressEnumerator *enumerator = G_SOCKET_ADDRESS_ENUMERATOR (object); |
270 | 0 | GTask *task = user_data; |
271 | 0 | GNetworkMonitorBase *base = g_task_get_source_object (task); |
272 | 0 | GSocketAddress *addr; |
273 | 0 | GError *error = NULL; |
274 | |
|
275 | 0 | addr = g_socket_address_enumerator_next_finish (enumerator, result, &error); |
276 | 0 | if (!addr) |
277 | 0 | { |
278 | 0 | if (error) |
279 | 0 | { |
280 | | /* Either the user cancelled, or DNS resolution failed */ |
281 | 0 | g_task_return_error (task, error); |
282 | 0 | g_object_unref (task); |
283 | 0 | return; |
284 | 0 | } |
285 | 0 | else |
286 | 0 | { |
287 | | /* Resolved all addresses, none matched */ |
288 | 0 | g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_HOST_UNREACHABLE, |
289 | 0 | _("Host unreachable")); |
290 | 0 | g_object_unref (task); |
291 | 0 | return; |
292 | 0 | } |
293 | 0 | } |
294 | | |
295 | 0 | if (g_network_monitor_base_can_reach_sockaddr (base, addr)) |
296 | 0 | { |
297 | 0 | g_object_unref (addr); |
298 | 0 | g_task_return_boolean (task, TRUE); |
299 | 0 | g_object_unref (task); |
300 | 0 | return; |
301 | 0 | } |
302 | 0 | g_object_unref (addr); |
303 | |
|
304 | 0 | g_socket_address_enumerator_next_async (enumerator, |
305 | 0 | g_task_get_cancellable (task), |
306 | 0 | can_reach_async_got_address, task); |
307 | 0 | } |
308 | | |
309 | | static void |
310 | | g_network_monitor_base_can_reach_async (GNetworkMonitor *monitor, |
311 | | GSocketConnectable *connectable, |
312 | | GCancellable *cancellable, |
313 | | GAsyncReadyCallback callback, |
314 | | gpointer user_data) |
315 | 0 | { |
316 | 0 | GTask *task; |
317 | 0 | GSocketAddressEnumerator *enumerator; |
318 | |
|
319 | 0 | task = g_task_new (monitor, cancellable, callback, user_data); |
320 | 0 | g_task_set_source_tag (task, g_network_monitor_base_can_reach_async); |
321 | |
|
322 | 0 | if (g_hash_table_size (G_NETWORK_MONITOR_BASE (monitor)->priv->networks) == 0) |
323 | 0 | { |
324 | 0 | g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NETWORK_UNREACHABLE, |
325 | 0 | _("Network unreachable")); |
326 | 0 | g_object_unref (task); |
327 | 0 | return; |
328 | 0 | } |
329 | | |
330 | 0 | enumerator = g_socket_connectable_proxy_enumerate (connectable); |
331 | 0 | g_socket_address_enumerator_next_async (enumerator, cancellable, |
332 | 0 | can_reach_async_got_address, task); |
333 | 0 | g_object_unref (enumerator); |
334 | 0 | } |
335 | | |
336 | | static gboolean |
337 | | g_network_monitor_base_can_reach_finish (GNetworkMonitor *monitor, |
338 | | GAsyncResult *result, |
339 | | GError **error) |
340 | 0 | { |
341 | 0 | g_return_val_if_fail (g_task_is_valid (result, monitor), FALSE); |
342 | | |
343 | 0 | return g_task_propagate_boolean (G_TASK (result), error); |
344 | 0 | } |
345 | | |
346 | | static void |
347 | | g_network_monitor_base_iface_init (GNetworkMonitorInterface *monitor_iface) |
348 | 0 | { |
349 | 0 | monitor_iface->can_reach = g_network_monitor_base_can_reach; |
350 | 0 | monitor_iface->can_reach_async = g_network_monitor_base_can_reach_async; |
351 | 0 | monitor_iface->can_reach_finish = g_network_monitor_base_can_reach_finish; |
352 | |
|
353 | 0 | network_changed_signal = g_signal_lookup ("network-changed", G_TYPE_NETWORK_MONITOR); |
354 | 0 | } |
355 | | |
356 | | static gboolean |
357 | | g_network_monitor_base_initable_init (GInitable *initable, |
358 | | GCancellable *cancellable, |
359 | | GError **error) |
360 | 0 | { |
361 | 0 | GNetworkMonitorBase *base = G_NETWORK_MONITOR_BASE (initable); |
362 | |
|
363 | 0 | base->priv->initializing = FALSE; |
364 | |
|
365 | 0 | return TRUE; |
366 | 0 | } |
367 | | |
368 | | static void |
369 | | g_network_monitor_base_initable_iface_init (GInitableIface *iface) |
370 | 0 | { |
371 | 0 | iface->init = g_network_monitor_base_initable_init; |
372 | 0 | } |
373 | | |
374 | | static guint |
375 | | inet_address_mask_hash (gconstpointer key) |
376 | 0 | { |
377 | 0 | GInetAddressMask *mask = G_INET_ADDRESS_MASK (key); |
378 | 0 | guint addr_hash; |
379 | 0 | guint mask_length = g_inet_address_mask_get_length (mask); |
380 | 0 | GInetAddress *addr = g_inet_address_mask_get_address (mask); |
381 | 0 | const guint8 *bytes = g_inet_address_to_bytes (addr); |
382 | 0 | gsize bytes_length = g_inet_address_get_native_size (addr); |
383 | |
|
384 | 0 | union |
385 | 0 | { |
386 | 0 | const guint8 *bytes; |
387 | 0 | guint32 *hash32; |
388 | 0 | guint64 *hash64; |
389 | 0 | } integerifier; |
390 | | |
391 | | /* If we can fit the entire address into the hash key, do it. Don’t worry |
392 | | * about endianness; the address should always be in network endianness. */ |
393 | 0 | if (bytes_length == sizeof (guint32)) |
394 | 0 | { |
395 | 0 | integerifier.bytes = bytes; |
396 | 0 | addr_hash = *integerifier.hash32; |
397 | 0 | } |
398 | 0 | else if (bytes_length == sizeof (guint64)) |
399 | 0 | { |
400 | 0 | integerifier.bytes = bytes; |
401 | 0 | addr_hash = *integerifier.hash64; |
402 | 0 | } |
403 | 0 | else |
404 | 0 | { |
405 | 0 | gsize i; |
406 | | |
407 | | /* Otherwise, fall back to adding the bytes together. We do this, rather |
408 | | * than XORing them, as routes often have repeated tuples which would |
409 | | * cancel out under XOR. */ |
410 | 0 | addr_hash = 0; |
411 | 0 | for (i = 0; i < bytes_length; i++) |
412 | 0 | addr_hash += bytes[i]; |
413 | 0 | } |
414 | |
|
415 | 0 | return addr_hash + mask_length;; |
416 | 0 | } |
417 | | |
418 | | static gboolean |
419 | | inet_address_mask_equal (gconstpointer a, |
420 | | gconstpointer b) |
421 | 0 | { |
422 | 0 | GInetAddressMask *mask_a = G_INET_ADDRESS_MASK (a); |
423 | 0 | GInetAddressMask *mask_b = G_INET_ADDRESS_MASK (b); |
424 | |
|
425 | 0 | return g_inet_address_mask_equal (mask_a, mask_b); |
426 | 0 | } |
427 | | |
428 | | static gboolean |
429 | | emit_network_changed (gpointer user_data) |
430 | 0 | { |
431 | 0 | GNetworkMonitorBase *monitor = user_data; |
432 | 0 | gboolean is_available; |
433 | |
|
434 | 0 | if (g_source_is_destroyed (g_main_current_source ())) |
435 | 0 | return FALSE; |
436 | | |
437 | 0 | g_object_ref (monitor); |
438 | |
|
439 | 0 | is_available = (monitor->priv->have_ipv4_default_route || |
440 | 0 | monitor->priv->have_ipv6_default_route); |
441 | 0 | if (monitor->priv->is_available != is_available) |
442 | 0 | { |
443 | 0 | monitor->priv->is_available = is_available; |
444 | 0 | g_object_notify (G_OBJECT (monitor), "network-available"); |
445 | 0 | } |
446 | |
|
447 | 0 | g_signal_emit (monitor, network_changed_signal, 0, is_available); |
448 | |
|
449 | 0 | g_source_unref (monitor->priv->network_changed_source); |
450 | 0 | monitor->priv->network_changed_source = NULL; |
451 | |
|
452 | 0 | g_object_unref (monitor); |
453 | 0 | return FALSE; |
454 | 0 | } |
455 | | |
456 | | static void |
457 | | queue_network_changed (GNetworkMonitorBase *monitor) |
458 | 0 | { |
459 | 0 | if (!monitor->priv->network_changed_source && |
460 | 0 | !monitor->priv->initializing) |
461 | 0 | { |
462 | 0 | GSource *source; |
463 | |
|
464 | 0 | source = g_idle_source_new (); |
465 | | /* Use G_PRIORITY_HIGH_IDLE priority so that multiple |
466 | | * network-change-related notifications coming in at |
467 | | * G_PRIORITY_DEFAULT will get coalesced into one signal |
468 | | * emission. |
469 | | */ |
470 | 0 | g_source_set_priority (source, G_PRIORITY_HIGH_IDLE); |
471 | 0 | g_source_set_callback (source, emit_network_changed, monitor, NULL); |
472 | 0 | g_source_set_static_name (source, "[gio] emit_network_changed"); |
473 | 0 | g_source_attach (source, monitor->priv->context); |
474 | 0 | monitor->priv->network_changed_source = source; |
475 | 0 | } |
476 | | |
477 | | /* Normally we wait to update is_available until we emit the signal, |
478 | | * to keep things consistent. But when we're first creating the |
479 | | * object, we want it to be correct right away. |
480 | | */ |
481 | 0 | if (monitor->priv->initializing) |
482 | 0 | { |
483 | 0 | monitor->priv->is_available = (monitor->priv->have_ipv4_default_route || |
484 | 0 | monitor->priv->have_ipv6_default_route); |
485 | 0 | } |
486 | 0 | } |
487 | | |
488 | | /** |
489 | | * g_network_monitor_base_add_network: |
490 | | * @monitor: the #GNetworkMonitorBase |
491 | | * @network: (transfer none): a #GInetAddressMask |
492 | | * |
493 | | * Adds @network to @monitor's list of available networks. |
494 | | * |
495 | | * Since: 2.32 |
496 | | */ |
497 | | void |
498 | | g_network_monitor_base_add_network (GNetworkMonitorBase *monitor, |
499 | | GInetAddressMask *network) |
500 | 0 | { |
501 | 0 | if (!g_hash_table_add (monitor->priv->networks, g_object_ref (network))) |
502 | 0 | return; |
503 | | |
504 | 0 | if (g_inet_address_mask_get_length (network) == 0) |
505 | 0 | { |
506 | 0 | switch (g_inet_address_mask_get_family (network)) |
507 | 0 | { |
508 | 0 | case G_SOCKET_FAMILY_IPV4: |
509 | 0 | monitor->priv->have_ipv4_default_route = TRUE; |
510 | 0 | break; |
511 | 0 | case G_SOCKET_FAMILY_IPV6: |
512 | 0 | monitor->priv->have_ipv6_default_route = TRUE; |
513 | 0 | break; |
514 | 0 | default: |
515 | 0 | break; |
516 | 0 | } |
517 | 0 | } |
518 | | |
519 | | /* Don't emit network-changed when multicast-link-local routing |
520 | | * changes. This rather arbitrary decision is mostly because it |
521 | | * seems to change quite often... |
522 | | */ |
523 | 0 | if (g_inet_address_get_is_mc_link_local (g_inet_address_mask_get_address (network))) |
524 | 0 | return; |
525 | | |
526 | 0 | queue_network_changed (monitor); |
527 | 0 | } |
528 | | |
529 | | /** |
530 | | * g_network_monitor_base_remove_network: |
531 | | * @monitor: the #GNetworkMonitorBase |
532 | | * @network: a #GInetAddressMask |
533 | | * |
534 | | * Removes @network from @monitor's list of available networks. |
535 | | * |
536 | | * Since: 2.32 |
537 | | */ |
538 | | void |
539 | | g_network_monitor_base_remove_network (GNetworkMonitorBase *monitor, |
540 | | GInetAddressMask *network) |
541 | 0 | { |
542 | 0 | if (!g_hash_table_remove (monitor->priv->networks, network)) |
543 | 0 | return; |
544 | | |
545 | 0 | if (g_inet_address_mask_get_length (network) == 0) |
546 | 0 | { |
547 | 0 | switch (g_inet_address_mask_get_family (network)) |
548 | 0 | { |
549 | 0 | case G_SOCKET_FAMILY_IPV4: |
550 | 0 | monitor->priv->have_ipv4_default_route = FALSE; |
551 | 0 | break; |
552 | 0 | case G_SOCKET_FAMILY_IPV6: |
553 | 0 | monitor->priv->have_ipv6_default_route = FALSE; |
554 | 0 | break; |
555 | 0 | default: |
556 | 0 | break; |
557 | 0 | } |
558 | 0 | } |
559 | | |
560 | 0 | queue_network_changed (monitor); |
561 | 0 | } |
562 | | |
563 | | /** |
564 | | * g_network_monitor_base_set_networks: |
565 | | * @monitor: the #GNetworkMonitorBase |
566 | | * @networks: (array length=length): an array of #GInetAddressMask |
567 | | * @length: length of @networks |
568 | | * |
569 | | * Drops @monitor's current list of available networks and replaces |
570 | | * it with @networks. |
571 | | */ |
572 | | void |
573 | | g_network_monitor_base_set_networks (GNetworkMonitorBase *monitor, |
574 | | GInetAddressMask **networks, |
575 | | gint length) |
576 | 0 | { |
577 | 0 | int i; |
578 | |
|
579 | 0 | g_hash_table_remove_all (monitor->priv->networks); |
580 | 0 | monitor->priv->have_ipv4_default_route = FALSE; |
581 | 0 | monitor->priv->have_ipv6_default_route = FALSE; |
582 | |
|
583 | 0 | for (i = 0; i < length; i++) |
584 | 0 | g_network_monitor_base_add_network (monitor, networks[i]); |
585 | 0 | } |