nexmon – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 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 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 GPtrArray *networks;
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  
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,
70 g_define_type_id,
71 "base",
72 0))
73  
74 static void
75 g_network_monitor_base_init (GNetworkMonitorBase *monitor)
76 {
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);
82  
83 monitor->priv->initializing = TRUE;
84 queue_network_changed (monitor);
85 }
86  
87 static void
88 g_network_monitor_base_constructed (GObject *object)
89 {
90 GNetworkMonitorBase *monitor = G_NETWORK_MONITOR_BASE (object);
91  
92 if (G_OBJECT_TYPE (monitor) == G_TYPE_NETWORK_MONITOR_BASE)
93 {
94 GInetAddressMask *mask;
95  
96 /* We're the dumb base class, not a smarter subclass. So just
97 * assume that the network is available.
98 */
99 mask = g_inet_address_mask_new_from_string ("0.0.0.0/0", NULL);
100 g_network_monitor_base_add_network (monitor, mask);
101 g_object_unref (mask);
102  
103 mask = g_inet_address_mask_new_from_string ("::/0", NULL);
104 g_network_monitor_base_add_network (monitor, mask);
105 g_object_unref (mask);
106 }
107 }
108  
109 static void
110 g_network_monitor_base_get_property (GObject *object,
111 guint prop_id,
112 GValue *value,
113 GParamSpec *pspec)
114 {
115 GNetworkMonitorBase *monitor = G_NETWORK_MONITOR_BASE (object);
116  
117 switch (prop_id)
118 {
119 case PROP_NETWORK_AVAILABLE:
120 g_value_set_boolean (value, monitor->priv->is_available);
121 break;
122  
123 case PROP_NETWORK_METERED:
124 /* Default to FALSE in the unknown case. */
125 g_value_set_boolean (value, FALSE);
126 break;
127  
128 case PROP_CONNECTIVITY:
129 g_value_set_enum (value,
130 monitor->priv->is_available ?
131 G_NETWORK_CONNECTIVITY_FULL :
132 G_NETWORK_CONNECTIVITY_LOCAL);
133 break;
134  
135 default:
136 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
137 break;
138 }
139  
140 }
141  
142 static void
143 g_network_monitor_base_finalize (GObject *object)
144 {
145 GNetworkMonitorBase *monitor = G_NETWORK_MONITOR_BASE (object);
146  
147 g_ptr_array_free (monitor->priv->networks, TRUE);
148 if (monitor->priv->network_changed_source)
149 {
150 g_source_destroy (monitor->priv->network_changed_source);
151 g_source_unref (monitor->priv->network_changed_source);
152 }
153 if (monitor->priv->context)
154 g_main_context_unref (monitor->priv->context);
155  
156 G_OBJECT_CLASS (g_network_monitor_base_parent_class)->finalize (object);
157 }
158  
159 static void
160 g_network_monitor_base_class_init (GNetworkMonitorBaseClass *monitor_class)
161 {
162 GObjectClass *gobject_class = G_OBJECT_CLASS (monitor_class);
163  
164 gobject_class->constructed = g_network_monitor_base_constructed;
165 gobject_class->get_property = g_network_monitor_base_get_property;
166 gobject_class->finalize = g_network_monitor_base_finalize;
167  
168 g_object_class_override_property (gobject_class, PROP_NETWORK_AVAILABLE, "network-available");
169 g_object_class_override_property (gobject_class, PROP_NETWORK_METERED, "network-metered");
170 g_object_class_override_property (gobject_class, PROP_CONNECTIVITY, "connectivity");
171 }
172  
173 static gboolean
174 g_network_monitor_base_can_reach_sockaddr (GNetworkMonitorBase *base,
175 GSocketAddress *sockaddr)
176 {
177 GInetAddress *iaddr;
178 int i;
179  
180 if (!G_IS_INET_SOCKET_ADDRESS (sockaddr))
181 return FALSE;
182  
183 iaddr = g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (sockaddr));
184 for (i = 0; i < base->priv->networks->len; i++)
185 {
186 if (g_inet_address_mask_matches (base->priv->networks->pdata[i], iaddr))
187 return TRUE;
188 }
189  
190 return FALSE;
191 }
192  
193 static gboolean
194 g_network_monitor_base_can_reach (GNetworkMonitor *monitor,
195 GSocketConnectable *connectable,
196 GCancellable *cancellable,
197 GError **error)
198 {
199 GNetworkMonitorBase *base = G_NETWORK_MONITOR_BASE (monitor);
200 GSocketAddressEnumerator *enumerator;
201 GSocketAddress *addr;
202  
203 if (base->priv->networks->len == 0)
204 {
205 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NETWORK_UNREACHABLE,
206 _("Network unreachable"));
207 return FALSE;
208 }
209  
210 enumerator = g_socket_connectable_proxy_enumerate (connectable);
211 addr = g_socket_address_enumerator_next (enumerator, cancellable, error);
212 if (!addr)
213 {
214 /* Either the user cancelled, or DNS resolution failed */
215 g_object_unref (enumerator);
216 return FALSE;
217 }
218  
219 if (base->priv->have_ipv4_default_route &&
220 base->priv->have_ipv6_default_route)
221 {
222 g_object_unref (enumerator);
223 g_object_unref (addr);
224 return TRUE;
225 }
226  
227 while (addr)
228 {
229 if (g_network_monitor_base_can_reach_sockaddr (base, addr))
230 {
231 g_object_unref (addr);
232 g_object_unref (enumerator);
233 return TRUE;
234 }
235  
236 g_object_unref (addr);
237 addr = g_socket_address_enumerator_next (enumerator, cancellable, error);
238 }
239 g_object_unref (enumerator);
240  
241 if (error && !*error)
242 {
243 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_HOST_UNREACHABLE,
244 _("Host unreachable"));
245 }
246 return FALSE;
247 }
248  
249 static void
250 can_reach_async_got_address (GObject *object,
251 GAsyncResult *result,
252 gpointer user_data)
253 {
254 GSocketAddressEnumerator *enumerator = G_SOCKET_ADDRESS_ENUMERATOR (object);
255 GTask *task = user_data;
256 GNetworkMonitorBase *base = g_task_get_source_object (task);
257 GSocketAddress *addr;
258 GError *error = NULL;
259  
260 addr = g_socket_address_enumerator_next_finish (enumerator, result, &error);
261 if (!addr)
262 {
263 if (error)
264 {
265 /* Either the user cancelled, or DNS resolution failed */
266 g_task_return_error (task, error);
267 g_object_unref (task);
268 return;
269 }
270 else
271 {
272 /* Resolved all addresses, none matched */
273 g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_HOST_UNREACHABLE,
274 _("Host unreachable"));
275 g_object_unref (task);
276 return;
277 }
278 }
279  
280 if (g_network_monitor_base_can_reach_sockaddr (base, addr))
281 {
282 g_object_unref (addr);
283 g_task_return_boolean (task, TRUE);
284 g_object_unref (task);
285 return;
286 }
287 g_object_unref (addr);
288  
289 g_socket_address_enumerator_next_async (enumerator,
290 g_task_get_cancellable (task),
291 can_reach_async_got_address, task);
292 }
293  
294 static void
295 g_network_monitor_base_can_reach_async (GNetworkMonitor *monitor,
296 GSocketConnectable *connectable,
297 GCancellable *cancellable,
298 GAsyncReadyCallback callback,
299 gpointer user_data)
300 {
301 GTask *task;
302 GSocketAddressEnumerator *enumerator;
303  
304 task = g_task_new (monitor, cancellable, callback, user_data);
305  
306 if (G_NETWORK_MONITOR_BASE (monitor)->priv->networks->len == 0)
307 {
308 g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NETWORK_UNREACHABLE,
309 _("Network unreachable"));
310 g_object_unref (task);
311 return;
312 }
313  
314 enumerator = g_socket_connectable_proxy_enumerate (connectable);
315 g_socket_address_enumerator_next_async (enumerator, cancellable,
316 can_reach_async_got_address, task);
317 g_object_unref (enumerator);
318 }
319  
320 static gboolean
321 g_network_monitor_base_can_reach_finish (GNetworkMonitor *monitor,
322 GAsyncResult *result,
323 GError **error)
324 {
325 g_return_val_if_fail (g_task_is_valid (result, monitor), FALSE);
326  
327 return g_task_propagate_boolean (G_TASK (result), error);
328 }
329  
330 static void
331 g_network_monitor_base_iface_init (GNetworkMonitorInterface *monitor_iface)
332 {
333 monitor_iface->can_reach = g_network_monitor_base_can_reach;
334 monitor_iface->can_reach_async = g_network_monitor_base_can_reach_async;
335 monitor_iface->can_reach_finish = g_network_monitor_base_can_reach_finish;
336  
337 network_changed_signal = g_signal_lookup ("network-changed", G_TYPE_NETWORK_MONITOR);
338 }
339  
340 static gboolean
341 g_network_monitor_base_initable_init (GInitable *initable,
342 GCancellable *cancellable,
343 GError **error)
344 {
345 return TRUE;
346 }
347  
348 static void
349 g_network_monitor_base_initable_iface_init (GInitableIface *iface)
350 {
351 iface->init = g_network_monitor_base_initable_init;
352 }
353  
354 static gboolean
355 emit_network_changed (gpointer user_data)
356 {
357 GNetworkMonitorBase *monitor = user_data;
358 gboolean is_available;
359  
360 g_object_ref (monitor);
361  
362 if (monitor->priv->initializing)
363 monitor->priv->initializing = FALSE;
364 else
365 {
366 is_available = (monitor->priv->have_ipv4_default_route ||
367 monitor->priv->have_ipv6_default_route);
368 if (monitor->priv->is_available != is_available)
369 {
370 monitor->priv->is_available = is_available;
371 g_object_notify (G_OBJECT (monitor), "network-available");
372 }
373  
374 g_signal_emit (monitor, network_changed_signal, 0, is_available);
375 }
376  
377 g_source_unref (monitor->priv->network_changed_source);
378 monitor->priv->network_changed_source = NULL;
379  
380 g_object_unref (monitor);
381 return FALSE;
382 }
383  
384 static void
385 queue_network_changed (GNetworkMonitorBase *monitor)
386 {
387 if (!monitor->priv->network_changed_source)
388 {
389 GSource *source;
390  
391 source = g_idle_source_new ();
392 /* Use G_PRIORITY_HIGH_IDLE priority so that multiple
393 * network-change-related notifications coming in at
394 * G_PRIORITY_DEFAULT will get coalesced into one signal
395 * emission.
396 */
397 g_source_set_priority (source, G_PRIORITY_HIGH_IDLE);
398 g_source_set_callback (source, emit_network_changed, monitor, NULL);
399 g_source_set_name (source, "[gio] emit_network_changed");
400 g_source_attach (source, monitor->priv->context);
401 monitor->priv->network_changed_source = source;
402 }
403  
404 /* Normally we wait to update is_available until we emit the signal,
405 * to keep things consistent. But when we're first creating the
406 * object, we want it to be correct right away.
407 */
408 if (monitor->priv->initializing)
409 {
410 monitor->priv->is_available = (monitor->priv->have_ipv4_default_route ||
411 monitor->priv->have_ipv6_default_route);
412 }
413 }
414  
415 /**
416 * g_network_monitor_base_add_network:
417 * @monitor: the #GNetworkMonitorBase
418 * @network: a #GInetAddressMask
419 *
420 * Adds @network to @monitor's list of available networks.
421 *
422 * Since: 2.32
423 */
424 void
425 g_network_monitor_base_add_network (GNetworkMonitorBase *monitor,
426 GInetAddressMask *network)
427 {
428 int i;
429  
430 for (i = 0; i < monitor->priv->networks->len; i++)
431 {
432 if (g_inet_address_mask_equal (monitor->priv->networks->pdata[i], network))
433 return;
434 }
435  
436 g_ptr_array_add (monitor->priv->networks, g_object_ref (network));
437 if (g_inet_address_mask_get_length (network) == 0)
438 {
439 switch (g_inet_address_mask_get_family (network))
440 {
441 case G_SOCKET_FAMILY_IPV4:
442 monitor->priv->have_ipv4_default_route = TRUE;
443 break;
444 case G_SOCKET_FAMILY_IPV6:
445 monitor->priv->have_ipv6_default_route = TRUE;
446 break;
447 default:
448 break;
449 }
450 }
451  
452 /* Don't emit network-changed when multicast-link-local routing
453 * changes. This rather arbitrary decision is mostly because it
454 * seems to change quite often...
455 */
456 if (g_inet_address_get_is_mc_link_local (g_inet_address_mask_get_address (network)))
457 return;
458  
459 queue_network_changed (monitor);
460 }
461  
462 /**
463 * g_network_monitor_base_remove_network:
464 * @monitor: the #GNetworkMonitorBase
465 * @network: a #GInetAddressMask
466 *
467 * Removes @network from @monitor's list of available networks.
468 *
469 * Since: 2.32
470 */
471 void
472 g_network_monitor_base_remove_network (GNetworkMonitorBase *monitor,
473 GInetAddressMask *network)
474 {
475 int i;
476  
477 for (i = 0; i < monitor->priv->networks->len; i++)
478 {
479 if (g_inet_address_mask_equal (monitor->priv->networks->pdata[i], network))
480 {
481 g_ptr_array_remove_index_fast (monitor->priv->networks, i);
482  
483 if (g_inet_address_mask_get_length (network) == 0)
484 {
485 switch (g_inet_address_mask_get_family (network))
486 {
487 case G_SOCKET_FAMILY_IPV4:
488 monitor->priv->have_ipv4_default_route = FALSE;
489 break;
490 case G_SOCKET_FAMILY_IPV6:
491 monitor->priv->have_ipv6_default_route = FALSE;
492 break;
493 default:
494 break;
495 }
496 }
497  
498 queue_network_changed (monitor);
499 return;
500 }
501 }
502 }
503  
504 /**
505 * g_network_monitor_base_set_networks:
506 * @monitor: the #GNetworkMonitorBase
507 * @networks: (array length=length): an array of #GInetAddressMask
508 * @length: length of @networks
509 *
510 * Drops @monitor's current list of available networks and replaces
511 * it with @networks.
512 */
513 void
514 g_network_monitor_base_set_networks (GNetworkMonitorBase *monitor,
515 GInetAddressMask **networks,
516 gint length)
517 {
518 int i;
519  
520 g_ptr_array_set_size (monitor->priv->networks, 0);
521 monitor->priv->have_ipv4_default_route = FALSE;
522 monitor->priv->have_ipv6_default_route = FALSE;
523  
524 for (i = 0; i < length; i++)
525 g_network_monitor_base_add_network (monitor, networks[i]);
526 }