Updated Telugu translation
[glib.git] / gio / gnetworkmonitorbase.c
blobead9e6436e1474ab470422c1a2049f8e540309bf
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 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/>.
19 #include "config.h"
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"
34 static void g_network_monitor_base_iface_init (GNetworkMonitorInterface *iface);
35 static void g_network_monitor_base_initable_iface_init (GInitableIface *iface);
37 enum
39 PROP_0,
41 PROP_NETWORK_AVAILABLE
44 struct _GNetworkMonitorBasePrivate
46 GPtrArray *networks;
47 gboolean have_ipv4_default_route;
48 gboolean have_ipv6_default_route;
49 gboolean is_available;
51 GMainContext *context;
52 GSource *network_changed_source;
53 gboolean initializing;
56 static guint network_changed_signal = 0;
58 static void queue_network_changed (GNetworkMonitorBase *monitor);
60 G_DEFINE_TYPE_WITH_CODE (GNetworkMonitorBase, g_network_monitor_base, G_TYPE_OBJECT,
61 G_ADD_PRIVATE (GNetworkMonitorBase)
62 G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
63 g_network_monitor_base_initable_iface_init)
64 G_IMPLEMENT_INTERFACE (G_TYPE_NETWORK_MONITOR,
65 g_network_monitor_base_iface_init)
66 _g_io_modules_ensure_extension_points_registered ();
67 g_io_extension_point_implement (G_NETWORK_MONITOR_EXTENSION_POINT_NAME,
68 g_define_type_id,
69 "base",
70 0))
72 static void
73 g_network_monitor_base_init (GNetworkMonitorBase *monitor)
75 monitor->priv = g_network_monitor_base_get_instance_private (monitor);
76 monitor->priv->networks = g_ptr_array_new_with_free_func (g_object_unref);
77 monitor->priv->context = g_main_context_get_thread_default ();
78 if (monitor->priv->context)
79 g_main_context_ref (monitor->priv->context);
81 monitor->priv->initializing = TRUE;
82 queue_network_changed (monitor);
85 static void
86 g_network_monitor_base_constructed (GObject *object)
88 GNetworkMonitorBase *monitor = G_NETWORK_MONITOR_BASE (object);
90 if (G_OBJECT_TYPE (monitor) == G_TYPE_NETWORK_MONITOR_BASE)
92 GInetAddressMask *mask;
94 /* We're the dumb base class, not a smarter subclass. So just
95 * assume that the network is available.
97 mask = g_inet_address_mask_new_from_string ("0.0.0.0/0", NULL);
98 g_network_monitor_base_add_network (monitor, mask);
99 g_object_unref (mask);
101 mask = g_inet_address_mask_new_from_string ("::/0", NULL);
102 g_network_monitor_base_add_network (monitor, mask);
103 g_object_unref (mask);
107 static void
108 g_network_monitor_base_get_property (GObject *object,
109 guint prop_id,
110 GValue *value,
111 GParamSpec *pspec)
113 GNetworkMonitorBase *monitor = G_NETWORK_MONITOR_BASE (object);
115 switch (prop_id)
117 case PROP_NETWORK_AVAILABLE:
118 g_value_set_boolean (value, monitor->priv->is_available);
119 break;
121 default:
122 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
127 static void
128 g_network_monitor_base_finalize (GObject *object)
130 GNetworkMonitorBase *monitor = G_NETWORK_MONITOR_BASE (object);
132 g_ptr_array_free (monitor->priv->networks, TRUE);
133 if (monitor->priv->network_changed_source)
135 g_source_destroy (monitor->priv->network_changed_source);
136 g_source_unref (monitor->priv->network_changed_source);
138 if (monitor->priv->context)
139 g_main_context_unref (monitor->priv->context);
141 G_OBJECT_CLASS (g_network_monitor_base_parent_class)->finalize (object);
144 static void
145 g_network_monitor_base_class_init (GNetworkMonitorBaseClass *monitor_class)
147 GObjectClass *gobject_class = G_OBJECT_CLASS (monitor_class);
149 gobject_class->constructed = g_network_monitor_base_constructed;
150 gobject_class->get_property = g_network_monitor_base_get_property;
151 gobject_class->finalize = g_network_monitor_base_finalize;
153 g_object_class_override_property (gobject_class, PROP_NETWORK_AVAILABLE, "network-available");
156 static gboolean
157 g_network_monitor_base_can_reach_sockaddr (GNetworkMonitorBase *base,
158 GSocketAddress *sockaddr)
160 GInetAddress *iaddr;
161 int i;
163 if (!G_IS_INET_SOCKET_ADDRESS (sockaddr))
164 return FALSE;
166 iaddr = g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (sockaddr));
167 for (i = 0; i < base->priv->networks->len; i++)
169 if (g_inet_address_mask_matches (base->priv->networks->pdata[i], iaddr))
170 return TRUE;
173 return FALSE;
176 static gboolean
177 g_network_monitor_base_can_reach (GNetworkMonitor *monitor,
178 GSocketConnectable *connectable,
179 GCancellable *cancellable,
180 GError **error)
182 GNetworkMonitorBase *base = G_NETWORK_MONITOR_BASE (monitor);
183 GSocketAddressEnumerator *enumerator;
184 GSocketAddress *addr;
186 if (base->priv->networks->len == 0)
188 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NETWORK_UNREACHABLE,
189 _("Network unreachable"));
190 return FALSE;
193 enumerator = g_socket_connectable_proxy_enumerate (connectable);
194 addr = g_socket_address_enumerator_next (enumerator, cancellable, error);
195 if (!addr)
197 /* Either the user cancelled, or DNS resolution failed */
198 g_object_unref (enumerator);
199 return FALSE;
202 if (base->priv->have_ipv4_default_route &&
203 base->priv->have_ipv6_default_route)
205 g_object_unref (enumerator);
206 g_object_unref (addr);
207 return TRUE;
210 while (addr)
212 if (g_network_monitor_base_can_reach_sockaddr (base, addr))
214 g_object_unref (addr);
215 g_object_unref (enumerator);
216 return TRUE;
219 g_object_unref (addr);
220 addr = g_socket_address_enumerator_next (enumerator, cancellable, error);
222 g_object_unref (enumerator);
224 if (error && !*error)
226 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_HOST_UNREACHABLE,
227 _("Host unreachable"));
229 return FALSE;
232 static void
233 can_reach_async_got_address (GObject *object,
234 GAsyncResult *result,
235 gpointer user_data)
237 GSocketAddressEnumerator *enumerator = G_SOCKET_ADDRESS_ENUMERATOR (object);
238 GTask *task = user_data;
239 GNetworkMonitorBase *base = g_task_get_source_object (task);
240 GSocketAddress *addr;
241 GError *error = NULL;
243 addr = g_socket_address_enumerator_next_finish (enumerator, result, &error);
244 if (!addr)
246 if (error)
248 /* Either the user cancelled, or DNS resolution failed */
249 g_task_return_error (task, error);
250 g_object_unref (task);
251 return;
253 else
255 /* Resolved all addresses, none matched */
256 g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_HOST_UNREACHABLE,
257 _("Host unreachable"));
258 g_object_unref (task);
259 return;
263 if (g_network_monitor_base_can_reach_sockaddr (base, addr))
265 g_object_unref (addr);
266 g_task_return_boolean (task, TRUE);
267 g_object_unref (task);
268 return;
270 g_object_unref (addr);
272 g_socket_address_enumerator_next_async (enumerator,
273 g_task_get_cancellable (task),
274 can_reach_async_got_address, task);
277 static void
278 g_network_monitor_base_can_reach_async (GNetworkMonitor *monitor,
279 GSocketConnectable *connectable,
280 GCancellable *cancellable,
281 GAsyncReadyCallback callback,
282 gpointer user_data)
284 GTask *task;
285 GSocketAddressEnumerator *enumerator;
287 task = g_task_new (monitor, cancellable, callback, user_data);
289 if (G_NETWORK_MONITOR_BASE (monitor)->priv->networks->len == 0)
291 g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NETWORK_UNREACHABLE,
292 _("Network unreachable"));
293 g_object_unref (task);
294 return;
297 enumerator = g_socket_connectable_proxy_enumerate (connectable);
298 g_socket_address_enumerator_next_async (enumerator, cancellable,
299 can_reach_async_got_address, task);
300 g_object_unref (enumerator);
303 static gboolean
304 g_network_monitor_base_can_reach_finish (GNetworkMonitor *monitor,
305 GAsyncResult *result,
306 GError **error)
308 g_return_val_if_fail (g_task_is_valid (result, monitor), FALSE);
310 return g_task_propagate_boolean (G_TASK (result), error);
313 static void
314 g_network_monitor_base_iface_init (GNetworkMonitorInterface *monitor_iface)
316 monitor_iface->can_reach = g_network_monitor_base_can_reach;
317 monitor_iface->can_reach_async = g_network_monitor_base_can_reach_async;
318 monitor_iface->can_reach_finish = g_network_monitor_base_can_reach_finish;
320 network_changed_signal = g_signal_lookup ("network-changed", G_TYPE_NETWORK_MONITOR);
323 static gboolean
324 g_network_monitor_base_initable_init (GInitable *initable,
325 GCancellable *cancellable,
326 GError **error)
328 return TRUE;
331 static void
332 g_network_monitor_base_initable_iface_init (GInitableIface *iface)
334 iface->init = g_network_monitor_base_initable_init;
337 static gboolean
338 emit_network_changed (gpointer user_data)
340 GNetworkMonitorBase *monitor = user_data;
341 gboolean is_available;
343 g_object_ref (monitor);
345 if (monitor->priv->initializing)
346 monitor->priv->initializing = FALSE;
347 else
349 is_available = (monitor->priv->have_ipv4_default_route ||
350 monitor->priv->have_ipv6_default_route);
351 if (monitor->priv->is_available != is_available)
353 monitor->priv->is_available = is_available;
354 g_object_notify (G_OBJECT (monitor), "network-available");
357 g_signal_emit (monitor, network_changed_signal, 0, is_available);
360 g_source_unref (monitor->priv->network_changed_source);
361 monitor->priv->network_changed_source = NULL;
363 g_object_unref (monitor);
364 return FALSE;
367 static void
368 queue_network_changed (GNetworkMonitorBase *monitor)
370 if (!monitor->priv->network_changed_source)
372 GSource *source;
374 source = g_idle_source_new ();
375 /* Use G_PRIORITY_HIGH_IDLE priority so that multiple
376 * network-change-related notifications coming in at
377 * G_PRIORITY_DEFAULT will get coalesced into one signal
378 * emission.
380 g_source_set_priority (source, G_PRIORITY_HIGH_IDLE);
381 g_source_set_callback (source, emit_network_changed, monitor, NULL);
382 g_source_set_name (source, "[gio] emit_network_changed");
383 g_source_attach (source, monitor->priv->context);
384 monitor->priv->network_changed_source = source;
387 /* Normally we wait to update is_available until we emit the signal,
388 * to keep things consistent. But when we're first creating the
389 * object, we want it to be correct right away.
391 if (monitor->priv->initializing)
393 monitor->priv->is_available = (monitor->priv->have_ipv4_default_route ||
394 monitor->priv->have_ipv6_default_route);
399 * g_network_monitor_base_add_network:
400 * @monitor: the #GNetworkMonitorBase
401 * @network: a #GInetAddressMask
403 * Adds @network to @monitor's list of available networks.
405 * Since: 2.32
407 void
408 g_network_monitor_base_add_network (GNetworkMonitorBase *monitor,
409 GInetAddressMask *network)
411 int i;
413 for (i = 0; i < monitor->priv->networks->len; i++)
415 if (g_inet_address_mask_equal (monitor->priv->networks->pdata[i], network))
416 return;
419 g_ptr_array_add (monitor->priv->networks, g_object_ref (network));
420 if (g_inet_address_mask_get_length (network) == 0)
422 switch (g_inet_address_mask_get_family (network))
424 case G_SOCKET_FAMILY_IPV4:
425 monitor->priv->have_ipv4_default_route = TRUE;
426 break;
427 case G_SOCKET_FAMILY_IPV6:
428 monitor->priv->have_ipv6_default_route = TRUE;
429 break;
430 default:
431 break;
435 /* Don't emit network-changed when multicast-link-local routing
436 * changes. This rather arbitrary decision is mostly because it
437 * seems to change quite often...
439 if (g_inet_address_get_is_mc_link_local (g_inet_address_mask_get_address (network)))
440 return;
442 queue_network_changed (monitor);
446 * g_network_monitor_base_remove_network:
447 * @monitor: the #GNetworkMonitorBase
448 * @network: a #GInetAddressMask
450 * Removes @network from @monitor's list of available networks.
452 * Since: 2.32
454 void
455 g_network_monitor_base_remove_network (GNetworkMonitorBase *monitor,
456 GInetAddressMask *network)
458 int i;
460 for (i = 0; i < monitor->priv->networks->len; i++)
462 if (g_inet_address_mask_equal (monitor->priv->networks->pdata[i], network))
464 g_ptr_array_remove_index_fast (monitor->priv->networks, i);
466 if (g_inet_address_mask_get_length (network) == 0)
468 switch (g_inet_address_mask_get_family (network))
470 case G_SOCKET_FAMILY_IPV4:
471 monitor->priv->have_ipv4_default_route = FALSE;
472 break;
473 case G_SOCKET_FAMILY_IPV6:
474 monitor->priv->have_ipv6_default_route = FALSE;
475 break;
476 default:
477 break;
481 queue_network_changed (monitor);
482 return;
488 * g_network_monitor_base_set_networks:
489 * @monitor: the #GNetworkMonitorBase
490 * @networks: (array length=length): an array of #GInetAddressMask
491 * @length: length of @networks
493 * Drops @monitor's current list of available networks and replaces
494 * it with @networks.
496 void
497 g_network_monitor_base_set_networks (GNetworkMonitorBase *monitor,
498 GInetAddressMask **networks,
499 gint length)
501 int i;
503 g_ptr_array_set_size (monitor->priv->networks, 0);
504 monitor->priv->have_ipv4_default_route = FALSE;
505 monitor->priv->have_ipv6_default_route = FALSE;
507 for (i = 0; i < length; i++)
508 g_network_monitor_base_add_network (monitor, networks[i]);