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