[kdbus] KDBUS_ITEM_PAYLOAD_OFF items are (once again) relative to msg header
[platform/upstream/glib.git] / gio / gnetworkmonitorbase.c
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 };
43
44 struct _GNetworkMonitorBasePrivate
45 {
46   GPtrArray    *networks;
47   gboolean      have_ipv4_default_route;
48   gboolean      have_ipv6_default_route;
49   gboolean      is_available;
50
51   GMainContext *context;
52   GSource      *network_changed_source;
53   gboolean      initializing;
54 };
55
56 static guint network_changed_signal = 0;
57
58 static void queue_network_changed (GNetworkMonitorBase *monitor);
59
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))
71
72 static void
73 g_network_monitor_base_init (GNetworkMonitorBase *monitor)
74 {
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);
80
81   monitor->priv->initializing = TRUE;
82   queue_network_changed (monitor);
83 }
84
85 static void
86 g_network_monitor_base_constructed (GObject *object)
87 {
88   GNetworkMonitorBase *monitor = G_NETWORK_MONITOR_BASE (object);
89
90   if (G_OBJECT_TYPE (monitor) == G_TYPE_NETWORK_MONITOR_BASE)
91     {
92       GInetAddressMask *mask;
93
94       /* We're the dumb base class, not a smarter subclass. So just
95        * assume that the network is available.
96        */
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);
100
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);
104     }
105 }
106
107 static void
108 g_network_monitor_base_get_property (GObject    *object,
109                                      guint       prop_id,
110                                      GValue     *value,
111                                      GParamSpec *pspec)
112 {
113   GNetworkMonitorBase *monitor = G_NETWORK_MONITOR_BASE (object);
114
115   switch (prop_id)
116     {
117       case PROP_NETWORK_AVAILABLE:
118         g_value_set_boolean (value, monitor->priv->is_available);
119         break;
120
121       default:
122         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
123     }
124
125 }
126
127 static void
128 g_network_monitor_base_finalize (GObject *object)
129 {
130   GNetworkMonitorBase *monitor = G_NETWORK_MONITOR_BASE (object);
131
132   g_ptr_array_free (monitor->priv->networks, TRUE);
133   if (monitor->priv->network_changed_source)
134     {
135       g_source_destroy (monitor->priv->network_changed_source);
136       g_source_unref (monitor->priv->network_changed_source);
137     }
138   if (monitor->priv->context)
139     g_main_context_unref (monitor->priv->context);
140
141   G_OBJECT_CLASS (g_network_monitor_base_parent_class)->finalize (object);
142 }
143
144 static void
145 g_network_monitor_base_class_init (GNetworkMonitorBaseClass *monitor_class)
146 {
147   GObjectClass *gobject_class = G_OBJECT_CLASS (monitor_class);
148
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;
152
153   g_object_class_override_property (gobject_class, PROP_NETWORK_AVAILABLE, "network-available");
154 }
155
156 static gboolean
157 g_network_monitor_base_can_reach_sockaddr (GNetworkMonitorBase *base,
158                                            GSocketAddress *sockaddr)
159 {
160   GInetAddress *iaddr;
161   int i;
162
163   if (!G_IS_INET_SOCKET_ADDRESS (sockaddr))
164     return FALSE;
165
166   iaddr = g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (sockaddr));
167   for (i = 0; i < base->priv->networks->len; i++)
168     {
169       if (g_inet_address_mask_matches (base->priv->networks->pdata[i], iaddr))
170         return TRUE;
171     }
172
173   return FALSE;
174 }
175
176 static gboolean
177 g_network_monitor_base_can_reach (GNetworkMonitor      *monitor,
178                                   GSocketConnectable   *connectable,
179                                   GCancellable         *cancellable,
180                                   GError              **error)
181 {
182   GNetworkMonitorBase *base = G_NETWORK_MONITOR_BASE (monitor);
183   GSocketAddressEnumerator *enumerator;
184   GSocketAddress *addr;
185
186   if (base->priv->networks->len == 0)
187     {
188       g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NETWORK_UNREACHABLE,
189                            _("Network unreachable"));
190       return FALSE;
191     }
192
193   enumerator = g_socket_connectable_proxy_enumerate (connectable);
194   addr = g_socket_address_enumerator_next (enumerator, cancellable, error);
195   if (!addr)
196     {
197       /* Either the user cancelled, or DNS resolution failed */
198       g_object_unref (enumerator);
199       return FALSE;
200     }
201
202   if (base->priv->have_ipv4_default_route &&
203       base->priv->have_ipv6_default_route)
204     {
205       g_object_unref (enumerator);
206       g_object_unref (addr);
207       return TRUE;
208     }
209
210   while (addr)
211     {
212       if (g_network_monitor_base_can_reach_sockaddr (base, addr))
213         {
214           g_object_unref (addr);
215           g_object_unref (enumerator);
216           return TRUE;
217         }
218
219       g_object_unref (addr);
220       addr = g_socket_address_enumerator_next (enumerator, cancellable, error);
221     }
222   g_object_unref (enumerator);
223
224   if (error && !*error)
225     {
226       g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_HOST_UNREACHABLE,
227                            _("Host unreachable"));
228     }
229   return FALSE;
230 }
231
232 static void
233 can_reach_async_got_address (GObject      *object,
234                              GAsyncResult *result,
235                              gpointer      user_data)
236 {
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;
242
243   addr = g_socket_address_enumerator_next_finish (enumerator, result, &error);
244   if (!addr)
245     {
246       if (error)
247         {
248           /* Either the user cancelled, or DNS resolution failed */
249           g_task_return_error (task, error);
250           g_object_unref (task);
251           return;
252         }
253       else
254         {
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;
260         }
261     }
262
263   if (g_network_monitor_base_can_reach_sockaddr (base, addr))
264     {
265       g_object_unref (addr);
266       g_task_return_boolean (task, TRUE);
267       g_object_unref (task);
268       return;
269     }
270   g_object_unref (addr);
271
272   g_socket_address_enumerator_next_async (enumerator,
273                                           g_task_get_cancellable (task),
274                                           can_reach_async_got_address, task);
275 }
276
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)
283 {
284   GTask *task;
285   GSocketAddressEnumerator *enumerator;
286
287   task = g_task_new (monitor, cancellable, callback, user_data);
288
289   if (G_NETWORK_MONITOR_BASE (monitor)->priv->networks->len == 0)
290     {
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;
295     }
296
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);
301 }
302
303 static gboolean
304 g_network_monitor_base_can_reach_finish (GNetworkMonitor  *monitor,
305                                          GAsyncResult     *result,
306                                          GError          **error)
307 {
308   g_return_val_if_fail (g_task_is_valid (result, monitor), FALSE);
309
310   return g_task_propagate_boolean (G_TASK (result), error);
311 }
312
313 static void
314 g_network_monitor_base_iface_init (GNetworkMonitorInterface *monitor_iface)
315 {
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;
319
320   network_changed_signal = g_signal_lookup ("network-changed", G_TYPE_NETWORK_MONITOR);
321 }
322
323 static gboolean
324 g_network_monitor_base_initable_init (GInitable     *initable,
325                                       GCancellable  *cancellable,
326                                       GError       **error)
327 {
328   return TRUE;
329 }
330
331 static void
332 g_network_monitor_base_initable_iface_init (GInitableIface *iface)
333 {
334   iface->init = g_network_monitor_base_initable_init;
335 }
336
337 static gboolean
338 emit_network_changed (gpointer user_data)
339 {
340   GNetworkMonitorBase *monitor = user_data;
341   gboolean is_available;
342
343   g_object_ref (monitor);
344
345   if (monitor->priv->initializing)
346     monitor->priv->initializing = FALSE;
347   else
348     {
349       is_available = (monitor->priv->have_ipv4_default_route ||
350                       monitor->priv->have_ipv6_default_route);
351       if (monitor->priv->is_available != is_available)
352         {
353           monitor->priv->is_available = is_available;
354           g_object_notify (G_OBJECT (monitor), "network-available");
355         }
356
357       g_signal_emit (monitor, network_changed_signal, 0, is_available);
358     }
359
360   g_source_unref (monitor->priv->network_changed_source);
361   monitor->priv->network_changed_source = NULL;
362
363   g_object_unref (monitor);
364   return FALSE;
365 }
366
367 static void
368 queue_network_changed (GNetworkMonitorBase *monitor)
369 {
370   if (!monitor->priv->network_changed_source)
371     {
372       GSource *source;
373
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.
379        */
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;
385     }
386
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.
390    */
391   if (monitor->priv->initializing)
392     {
393       monitor->priv->is_available = (monitor->priv->have_ipv4_default_route ||
394                                      monitor->priv->have_ipv6_default_route);
395     }
396 }
397
398 /**
399  * g_network_monitor_base_add_network:
400  * @monitor: the #GNetworkMonitorBase
401  * @network: a #GInetAddressMask
402  *
403  * Adds @network to @monitor's list of available networks.
404  *
405  * Since: 2.32
406  */
407 void
408 g_network_monitor_base_add_network (GNetworkMonitorBase *monitor,
409                                     GInetAddressMask    *network)
410 {
411   int i;
412
413   for (i = 0; i < monitor->priv->networks->len; i++)
414     {
415       if (g_inet_address_mask_equal (monitor->priv->networks->pdata[i], network))
416         return;
417     }
418
419   g_ptr_array_add (monitor->priv->networks, g_object_ref (network));
420   if (g_inet_address_mask_get_length (network) == 0)
421     {
422       switch (g_inet_address_mask_get_family (network))
423         {
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;
432         }
433     }
434
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...
438    */
439   if (g_inet_address_get_is_mc_link_local (g_inet_address_mask_get_address (network)))
440     return;
441
442   queue_network_changed (monitor);
443 }
444
445 /**
446  * g_network_monitor_base_remove_network:
447  * @monitor: the #GNetworkMonitorBase
448  * @network: a #GInetAddressMask
449  *
450  * Removes @network from @monitor's list of available networks.
451  *
452  * Since: 2.32
453  */
454 void
455 g_network_monitor_base_remove_network (GNetworkMonitorBase *monitor,
456                                        GInetAddressMask    *network)
457 {
458   int i;
459
460   for (i = 0; i < monitor->priv->networks->len; i++)
461     {
462       if (g_inet_address_mask_equal (monitor->priv->networks->pdata[i], network))
463         {
464           g_ptr_array_remove_index_fast (monitor->priv->networks, i);
465
466           if (g_inet_address_mask_get_length (network) == 0)
467             {
468               switch (g_inet_address_mask_get_family (network))
469                 {
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;
478                 }
479             }
480
481           queue_network_changed (monitor);
482           return;
483         }
484     }
485 }
486
487 /**
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
492  *
493  * Drops @monitor's current list of available networks and replaces
494  * it with @networks.
495  */
496 void
497 g_network_monitor_base_set_networks (GNetworkMonitorBase  *monitor,
498                                      GInetAddressMask    **networks,
499                                      gint                  length)
500 {
501   int i;
502
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;
506
507   for (i = 0; i < length; i++)
508     g_network_monitor_base_add_network (monitor, networks[i]);
509 }