1 /* GIO - GLib Input, Output and Streaming Library
3 * Copyright 2011 Red Hat, Inc.
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.
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.
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/>.
21 #include "gnetworkmonitorbase.h"
22 #include "ginetaddress.h"
23 #include "ginetaddressmask.h"
24 #include "ginetsocketaddress.h"
25 #include "ginitable.h"
27 #include "giomodule-priv.h"
28 #include "gnetworkmonitor.h"
29 #include "gsocketaddressenumerator.h"
30 #include "gsocketconnectable.h"
34 static void g_network_monitor_base_iface_init (GNetworkMonitorInterface
*iface
);
35 static void g_network_monitor_base_initable_iface_init (GInitableIface
*iface
);
41 PROP_NETWORK_AVAILABLE
,
46 struct _GNetworkMonitorBasePrivate
49 gboolean have_ipv4_default_route
;
50 gboolean have_ipv6_default_route
;
51 gboolean is_available
;
53 GMainContext
*context
;
54 GSource
*network_changed_source
;
55 gboolean initializing
;
58 static guint network_changed_signal
= 0;
60 static void queue_network_changed (GNetworkMonitorBase
*monitor
);
62 G_DEFINE_TYPE_WITH_CODE (GNetworkMonitorBase
, g_network_monitor_base
, G_TYPE_OBJECT
,
63 G_ADD_PRIVATE (GNetworkMonitorBase
)
64 G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE
,
65 g_network_monitor_base_initable_iface_init
)
66 G_IMPLEMENT_INTERFACE (G_TYPE_NETWORK_MONITOR
,
67 g_network_monitor_base_iface_init
)
68 _g_io_modules_ensure_extension_points_registered ();
69 g_io_extension_point_implement (G_NETWORK_MONITOR_EXTENSION_POINT_NAME
,
75 g_network_monitor_base_init (GNetworkMonitorBase
*monitor
)
77 monitor
->priv
= g_network_monitor_base_get_instance_private (monitor
);
78 monitor
->priv
->networks
= g_ptr_array_new_with_free_func (g_object_unref
);
79 monitor
->priv
->context
= g_main_context_get_thread_default ();
80 if (monitor
->priv
->context
)
81 g_main_context_ref (monitor
->priv
->context
);
83 monitor
->priv
->initializing
= TRUE
;
87 g_network_monitor_base_constructed (GObject
*object
)
89 GNetworkMonitorBase
*monitor
= G_NETWORK_MONITOR_BASE (object
);
91 if (G_OBJECT_TYPE (monitor
) == G_TYPE_NETWORK_MONITOR_BASE
)
93 GInetAddressMask
*mask
;
95 /* We're the dumb base class, not a smarter subclass. So just
96 * assume that the network is available.
98 mask
= g_inet_address_mask_new_from_string ("0.0.0.0/0", NULL
);
99 g_network_monitor_base_add_network (monitor
, mask
);
100 g_object_unref (mask
);
102 mask
= g_inet_address_mask_new_from_string ("::/0", NULL
);
105 /* On some environments (for example Windows without IPv6 support
106 * enabled) the string "::/0" can't be processed and causes
107 * g_inet_address_mask_new_from_string to return NULL */
108 g_network_monitor_base_add_network (monitor
, mask
);
109 g_object_unref (mask
);
115 g_network_monitor_base_get_property (GObject
*object
,
120 GNetworkMonitorBase
*monitor
= G_NETWORK_MONITOR_BASE (object
);
124 case PROP_NETWORK_AVAILABLE
:
125 g_value_set_boolean (value
, monitor
->priv
->is_available
);
128 case PROP_NETWORK_METERED
:
129 /* Default to FALSE in the unknown case. */
130 g_value_set_boolean (value
, FALSE
);
133 case PROP_CONNECTIVITY
:
134 g_value_set_enum (value
,
135 monitor
->priv
->is_available
?
136 G_NETWORK_CONNECTIVITY_FULL
:
137 G_NETWORK_CONNECTIVITY_LOCAL
);
141 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
148 g_network_monitor_base_finalize (GObject
*object
)
150 GNetworkMonitorBase
*monitor
= G_NETWORK_MONITOR_BASE (object
);
152 g_ptr_array_free (monitor
->priv
->networks
, TRUE
);
153 if (monitor
->priv
->network_changed_source
)
155 g_source_destroy (monitor
->priv
->network_changed_source
);
156 g_source_unref (monitor
->priv
->network_changed_source
);
158 if (monitor
->priv
->context
)
159 g_main_context_unref (monitor
->priv
->context
);
161 G_OBJECT_CLASS (g_network_monitor_base_parent_class
)->finalize (object
);
165 g_network_monitor_base_class_init (GNetworkMonitorBaseClass
*monitor_class
)
167 GObjectClass
*gobject_class
= G_OBJECT_CLASS (monitor_class
);
169 gobject_class
->constructed
= g_network_monitor_base_constructed
;
170 gobject_class
->get_property
= g_network_monitor_base_get_property
;
171 gobject_class
->finalize
= g_network_monitor_base_finalize
;
173 g_object_class_override_property (gobject_class
, PROP_NETWORK_AVAILABLE
, "network-available");
174 g_object_class_override_property (gobject_class
, PROP_NETWORK_METERED
, "network-metered");
175 g_object_class_override_property (gobject_class
, PROP_CONNECTIVITY
, "connectivity");
179 g_network_monitor_base_can_reach_sockaddr (GNetworkMonitorBase
*base
,
180 GSocketAddress
*sockaddr
)
185 if (!G_IS_INET_SOCKET_ADDRESS (sockaddr
))
188 iaddr
= g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (sockaddr
));
189 for (i
= 0; i
< base
->priv
->networks
->len
; i
++)
191 if (g_inet_address_mask_matches (base
->priv
->networks
->pdata
[i
], iaddr
))
199 g_network_monitor_base_can_reach (GNetworkMonitor
*monitor
,
200 GSocketConnectable
*connectable
,
201 GCancellable
*cancellable
,
204 GNetworkMonitorBase
*base
= G_NETWORK_MONITOR_BASE (monitor
);
205 GSocketAddressEnumerator
*enumerator
;
206 GSocketAddress
*addr
;
208 if (base
->priv
->networks
->len
== 0)
210 g_set_error_literal (error
, G_IO_ERROR
, G_IO_ERROR_NETWORK_UNREACHABLE
,
211 _("Network unreachable"));
215 enumerator
= g_socket_connectable_proxy_enumerate (connectable
);
216 addr
= g_socket_address_enumerator_next (enumerator
, cancellable
, error
);
219 /* Either the user cancelled, or DNS resolution failed */
220 g_object_unref (enumerator
);
224 if (base
->priv
->have_ipv4_default_route
&&
225 base
->priv
->have_ipv6_default_route
)
227 g_object_unref (enumerator
);
228 g_object_unref (addr
);
234 if (g_network_monitor_base_can_reach_sockaddr (base
, addr
))
236 g_object_unref (addr
);
237 g_object_unref (enumerator
);
241 g_object_unref (addr
);
242 addr
= g_socket_address_enumerator_next (enumerator
, cancellable
, error
);
244 g_object_unref (enumerator
);
246 if (error
&& !*error
)
248 g_set_error_literal (error
, G_IO_ERROR
, G_IO_ERROR_HOST_UNREACHABLE
,
249 _("Host unreachable"));
255 can_reach_async_got_address (GObject
*object
,
256 GAsyncResult
*result
,
259 GSocketAddressEnumerator
*enumerator
= G_SOCKET_ADDRESS_ENUMERATOR (object
);
260 GTask
*task
= user_data
;
261 GNetworkMonitorBase
*base
= g_task_get_source_object (task
);
262 GSocketAddress
*addr
;
263 GError
*error
= NULL
;
265 addr
= g_socket_address_enumerator_next_finish (enumerator
, result
, &error
);
270 /* Either the user cancelled, or DNS resolution failed */
271 g_task_return_error (task
, error
);
272 g_object_unref (task
);
277 /* Resolved all addresses, none matched */
278 g_task_return_new_error (task
, G_IO_ERROR
, G_IO_ERROR_HOST_UNREACHABLE
,
279 _("Host unreachable"));
280 g_object_unref (task
);
285 if (g_network_monitor_base_can_reach_sockaddr (base
, addr
))
287 g_object_unref (addr
);
288 g_task_return_boolean (task
, TRUE
);
289 g_object_unref (task
);
292 g_object_unref (addr
);
294 g_socket_address_enumerator_next_async (enumerator
,
295 g_task_get_cancellable (task
),
296 can_reach_async_got_address
, task
);
300 g_network_monitor_base_can_reach_async (GNetworkMonitor
*monitor
,
301 GSocketConnectable
*connectable
,
302 GCancellable
*cancellable
,
303 GAsyncReadyCallback callback
,
307 GSocketAddressEnumerator
*enumerator
;
309 task
= g_task_new (monitor
, cancellable
, callback
, user_data
);
310 g_task_set_source_tag (task
, g_network_monitor_base_can_reach_async
);
312 if (G_NETWORK_MONITOR_BASE (monitor
)->priv
->networks
->len
== 0)
314 g_task_return_new_error (task
, G_IO_ERROR
, G_IO_ERROR_NETWORK_UNREACHABLE
,
315 _("Network unreachable"));
316 g_object_unref (task
);
320 enumerator
= g_socket_connectable_proxy_enumerate (connectable
);
321 g_socket_address_enumerator_next_async (enumerator
, cancellable
,
322 can_reach_async_got_address
, task
);
323 g_object_unref (enumerator
);
327 g_network_monitor_base_can_reach_finish (GNetworkMonitor
*monitor
,
328 GAsyncResult
*result
,
331 g_return_val_if_fail (g_task_is_valid (result
, monitor
), FALSE
);
333 return g_task_propagate_boolean (G_TASK (result
), error
);
337 g_network_monitor_base_iface_init (GNetworkMonitorInterface
*monitor_iface
)
339 monitor_iface
->can_reach
= g_network_monitor_base_can_reach
;
340 monitor_iface
->can_reach_async
= g_network_monitor_base_can_reach_async
;
341 monitor_iface
->can_reach_finish
= g_network_monitor_base_can_reach_finish
;
343 network_changed_signal
= g_signal_lookup ("network-changed", G_TYPE_NETWORK_MONITOR
);
347 g_network_monitor_base_initable_init (GInitable
*initable
,
348 GCancellable
*cancellable
,
351 GNetworkMonitorBase
*base
= G_NETWORK_MONITOR_BASE (initable
);
353 base
->priv
->initializing
= FALSE
;
359 g_network_monitor_base_initable_iface_init (GInitableIface
*iface
)
361 iface
->init
= g_network_monitor_base_initable_init
;
365 emit_network_changed (gpointer user_data
)
367 GNetworkMonitorBase
*monitor
= user_data
;
368 gboolean is_available
;
370 if (g_source_is_destroyed (g_main_current_source ()))
373 g_object_ref (monitor
);
375 is_available
= (monitor
->priv
->have_ipv4_default_route
||
376 monitor
->priv
->have_ipv6_default_route
);
377 if (monitor
->priv
->is_available
!= is_available
)
379 monitor
->priv
->is_available
= is_available
;
380 g_object_notify (G_OBJECT (monitor
), "network-available");
383 g_signal_emit (monitor
, network_changed_signal
, 0, is_available
);
385 g_source_unref (monitor
->priv
->network_changed_source
);
386 monitor
->priv
->network_changed_source
= NULL
;
388 g_object_unref (monitor
);
393 queue_network_changed (GNetworkMonitorBase
*monitor
)
395 if (!monitor
->priv
->network_changed_source
&&
396 !monitor
->priv
->initializing
)
400 source
= g_idle_source_new ();
401 /* Use G_PRIORITY_HIGH_IDLE priority so that multiple
402 * network-change-related notifications coming in at
403 * G_PRIORITY_DEFAULT will get coalesced into one signal
406 g_source_set_priority (source
, G_PRIORITY_HIGH_IDLE
);
407 g_source_set_callback (source
, emit_network_changed
, monitor
, NULL
);
408 g_source_set_name (source
, "[gio] emit_network_changed");
409 g_source_attach (source
, monitor
->priv
->context
);
410 monitor
->priv
->network_changed_source
= source
;
413 /* Normally we wait to update is_available until we emit the signal,
414 * to keep things consistent. But when we're first creating the
415 * object, we want it to be correct right away.
417 if (monitor
->priv
->initializing
)
419 monitor
->priv
->is_available
= (monitor
->priv
->have_ipv4_default_route
||
420 monitor
->priv
->have_ipv6_default_route
);
425 * g_network_monitor_base_add_network:
426 * @monitor: the #GNetworkMonitorBase
427 * @network: a #GInetAddressMask
429 * Adds @network to @monitor's list of available networks.
434 g_network_monitor_base_add_network (GNetworkMonitorBase
*monitor
,
435 GInetAddressMask
*network
)
439 for (i
= 0; i
< monitor
->priv
->networks
->len
; i
++)
441 if (g_inet_address_mask_equal (monitor
->priv
->networks
->pdata
[i
], network
))
445 g_ptr_array_add (monitor
->priv
->networks
, g_object_ref (network
));
446 if (g_inet_address_mask_get_length (network
) == 0)
448 switch (g_inet_address_mask_get_family (network
))
450 case G_SOCKET_FAMILY_IPV4
:
451 monitor
->priv
->have_ipv4_default_route
= TRUE
;
453 case G_SOCKET_FAMILY_IPV6
:
454 monitor
->priv
->have_ipv6_default_route
= TRUE
;
461 /* Don't emit network-changed when multicast-link-local routing
462 * changes. This rather arbitrary decision is mostly because it
463 * seems to change quite often...
465 if (g_inet_address_get_is_mc_link_local (g_inet_address_mask_get_address (network
)))
468 queue_network_changed (monitor
);
472 * g_network_monitor_base_remove_network:
473 * @monitor: the #GNetworkMonitorBase
474 * @network: a #GInetAddressMask
476 * Removes @network from @monitor's list of available networks.
481 g_network_monitor_base_remove_network (GNetworkMonitorBase
*monitor
,
482 GInetAddressMask
*network
)
486 for (i
= 0; i
< monitor
->priv
->networks
->len
; i
++)
488 if (g_inet_address_mask_equal (monitor
->priv
->networks
->pdata
[i
], network
))
490 g_ptr_array_remove_index_fast (monitor
->priv
->networks
, i
);
492 if (g_inet_address_mask_get_length (network
) == 0)
494 switch (g_inet_address_mask_get_family (network
))
496 case G_SOCKET_FAMILY_IPV4
:
497 monitor
->priv
->have_ipv4_default_route
= FALSE
;
499 case G_SOCKET_FAMILY_IPV6
:
500 monitor
->priv
->have_ipv6_default_route
= FALSE
;
507 queue_network_changed (monitor
);
514 * g_network_monitor_base_set_networks:
515 * @monitor: the #GNetworkMonitorBase
516 * @networks: (array length=length): an array of #GInetAddressMask
517 * @length: length of @networks
519 * Drops @monitor's current list of available networks and replaces
523 g_network_monitor_base_set_networks (GNetworkMonitorBase
*monitor
,
524 GInetAddressMask
**networks
,
529 g_ptr_array_set_size (monitor
->priv
->networks
, 0);
530 monitor
->priv
->have_ipv4_default_route
= FALSE
;
531 monitor
->priv
->have_ipv6_default_route
= FALSE
;
533 for (i
= 0; i
< length
; i
++)
534 g_network_monitor_base_add_network (monitor
, networks
[i
]);