2 * Copyright (C) 2009 Nokia Corporation.
4 * Author: Zeeshan Ali (Khattak) <zeeshanak@gnome.org>
5 * <zeeshan.ali@nokia.com>
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
24 * SECTION:gupnp-network-manager
25 * @short_description: NetworkManager-based implementation of
26 * #GUPnPContextManager.
37 #include "gupnp-network-manager.h"
38 #include "gupnp-context.h"
39 #include "gupnp-marshal.h"
41 #define DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH \
42 (dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_OBJECT_PATH))
44 #define DBUS_SERVICE_NM "org.freedesktop.NetworkManager"
45 #define MANAGER_PATH "/org/freedesktop/NetworkManager"
46 #define MANAGER_INTERFACE "org.freedesktop.NetworkManager"
47 #define AP_INTERFACE "org.freedesktop.NetworkManager.AccessPoint"
48 #define DEVICE_INTERFACE "org.freedesktop.NetworkManager.Device"
49 #define WIFI_INTERFACE "org.freedesktop.NetworkManager.Device.Wireless"
51 #define DBUS_SERVICE_DBUS "org.freedesktop.DBus"
52 #define DBUS_PATH_DBUS "/org/freedesktop/DBus"
53 #define DBUS_INTERFACE_DBUS "org.freedesktop.DBus"
55 G_DEFINE_TYPE (GUPnPNetworkManager,
56 gupnp_network_manager,
57 GUPNP_TYPE_CONTEXT_MANAGER);
61 NM_DEVICE_STATE_UNKNOWN = 0,
62 NM_OLD_DEVICE_STATE_UNMANAGED = 1,
63 NM_OLD_DEVICE_STATE_UNAVAILABLE = 2,
64 NM_OLD_DEVICE_STATE_DISCONNECTED = 3,
65 NM_OLD_DEVICE_STATE_PREPARE = 4,
66 NM_OLD_DEVICE_STATE_CONFIG = 5,
67 NM_OLD_DEVICE_STATE_NEED_AUTH = 6,
68 NM_OLD_DEVICE_STATE_IP_CONFIG = 7,
69 NM_OLD_DEVICE_STATE_ACTIVATED = 8,
70 NM_OLD_DEVICE_STATE_FAILED = 9,
71 NM_DEVICE_STATE_UNMANAGED = 10,
72 NM_DEVICE_STATE_UNAVAILABLE = 20,
73 NM_DEVICE_STATE_DISCONNECTED = 30,
74 NM_DEVICE_STATE_PREPARE = 40,
75 NM_DEVICE_STATE_CONFIG = 50,
76 NM_DEVICE_STATE_NEED_AUTH = 60,
77 NM_DEVICE_STATE_IP_CONFIG = 70,
78 NM_DEVICE_STATE_IP_CHECK = 80,
79 NM_DEVICE_STATE_SECONDARIES = 90,
80 NM_DEVICE_STATE_ACTIVATED = 100,
81 NM_DEVICE_STATE_DEACTIVATING = 110,
82 NM_DEVICE_STATE_FAILED = 120
87 NM_DEVICE_TYPE_UNKNOWN,
88 NM_DEVICE_TYPE_ETHERNET,
90 NM_OLD_DEVICE_TYPE_GSM,
91 NM_OLD_DEVICE_TYPE_CDMA,
93 NM_DEVICE_TYPE_OLPC_MESH,
102 GUPnPNetworkManager *manager;
104 GUPnPContext *context;
107 GDBusProxy *wifi_proxy;
108 GDBusProxy *ap_proxy;
111 struct _GUPnPNetworkManagerPrivate {
112 GDBusProxy *manager_proxy;
114 GSource *idle_context_creation_src;
118 GCancellable *cancellable;
120 GDBusConnection *system_bus;
124 nm_device_new (GUPnPNetworkManager *manager,
125 GDBusProxy *device_proxy)
129 nm_device = g_slice_new0 (NMDevice);
131 g_atomic_int_set (&nm_device->ref_count, 1);
132 nm_device->manager = g_object_ref (manager);
133 nm_device->proxy = g_object_ref (device_proxy);
139 nm_device_ref (NMDevice *nm_device)
141 g_atomic_int_inc (&nm_device->ref_count);
147 nm_device_unref (NMDevice *nm_device)
149 if (!g_atomic_int_dec_and_test (&nm_device->ref_count))
152 g_object_unref (nm_device->proxy);
153 if (nm_device->wifi_proxy != NULL)
154 g_object_unref (nm_device->wifi_proxy);
155 if (nm_device->ap_proxy != NULL)
156 g_object_unref (nm_device->ap_proxy);
158 if (nm_device->context != NULL) {
159 g_signal_emit_by_name (nm_device->manager,
160 "context-unavailable",
163 g_object_unref (nm_device->context);
166 g_object_unref (nm_device->proxy);
167 g_object_unref (nm_device->manager);
169 g_slice_free (NMDevice, nm_device);
172 #define LOOPBACK_IFACE "lo"
175 create_loopback_context (gpointer data)
177 GUPnPNetworkManager *manager = (GUPnPNetworkManager *) data;
178 GUPnPContext *context;
180 GError *error = NULL;
182 manager->priv->idle_context_creation_src = NULL;
184 g_object_get (manager,
188 context = g_initable_new (GUPNP_TYPE_CONTEXT,
191 "interface", LOOPBACK_IFACE,
195 g_warning ("Error creating GUPnP context: %s\n",
198 g_error_free (error);
202 g_signal_emit_by_name (manager, "context-available", context);
204 g_object_unref (context);
210 create_context_for_device (NMDevice *nm_device)
212 GError *error = NULL;
218 g_object_get (nm_device->manager,
222 value = g_dbus_proxy_get_cached_property (nm_device->proxy,
224 if (G_UNLIKELY (value == NULL))
227 if (G_UNLIKELY (!g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))) {
228 g_variant_unref (value);
233 iface = g_variant_dup_string (value, NULL);
234 g_variant_unref (value);
236 if (nm_device->ap_proxy != NULL) {
237 value = g_dbus_proxy_get_cached_property (nm_device->ap_proxy,
239 if (G_LIKELY (value != NULL)) {
240 ssid = g_strndup (g_variant_get_data (value),
241 g_variant_get_size (value));
242 g_variant_unref (value);
246 nm_device->context = g_initable_new (GUPNP_TYPE_CONTEXT,
257 g_warning ("Error creating GUPnP context: %s\n",
260 g_error_free (error);
265 g_signal_emit_by_name (nm_device->manager,
271 ap_proxy_new_cb (GObject *source_object,
278 nm_device = (NMDevice *) user_data;
281 nm_device->ap_proxy = g_dbus_proxy_new_for_bus_finish (res, &error);
282 if (G_UNLIKELY (error != NULL)) {
283 g_message ("Failed to create D-Bus proxy: %s", error->message);
284 g_error_free (error);
288 create_context_for_device (nm_device);
291 nm_device_unref (nm_device);
295 on_wifi_device_activated (NMDevice *nm_device)
300 value = g_dbus_proxy_get_cached_property (nm_device->wifi_proxy,
301 "ActiveAccessPoint");
302 if (G_UNLIKELY (value == NULL))
305 if (G_UNLIKELY (!g_variant_is_of_type (value,
306 G_VARIANT_TYPE_OBJECT_PATH))) {
307 g_variant_unref (value);
312 ap_path = g_variant_get_string (value, NULL);
313 if (G_UNLIKELY (ap_path == NULL))
314 create_context_for_device (nm_device);
316 g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM,
317 G_DBUS_PROXY_FLAGS_NONE,
322 nm_device->manager->priv->cancellable,
324 nm_device_ref (nm_device));
327 g_variant_unref (value);
331 on_device_activated (NMDevice *nm_device)
333 if (nm_device->wifi_proxy != NULL)
334 on_wifi_device_activated (nm_device);
336 create_context_for_device (nm_device);
340 on_device_signal (GDBusProxy *proxy,
343 GVariant *parameters,
347 unsigned int new_state;
349 if (g_strcmp0 (signal_name, "StateChanged") != 0)
352 nm_device = (NMDevice *) user_data;
353 g_variant_get_child (parameters, 0, "u", &new_state);
355 if (new_state == NM_OLD_DEVICE_STATE_ACTIVATED ||
356 new_state == NM_DEVICE_STATE_ACTIVATED)
357 on_device_activated (nm_device);
358 else if (nm_device->context != NULL) {
359 /* For all other states we just destroy the context */
360 g_signal_emit_by_name (nm_device->manager,
361 "context-unavailable",
364 g_object_unref (nm_device->context);
365 nm_device->context = NULL;
367 if (nm_device->ap_proxy != NULL) {
368 g_object_unref (nm_device->ap_proxy);
369 nm_device->ap_proxy = NULL;
375 use_new_device (GUPnPNetworkManager *manager,
381 manager->priv->nm_devices = g_list_append (manager->priv->nm_devices,
384 g_signal_connect (nm_device->proxy,
386 G_CALLBACK (on_device_signal),
389 value = g_dbus_proxy_get_cached_property (nm_device->proxy, "State");
390 if (G_UNLIKELY (value == NULL))
393 if (G_UNLIKELY (!g_variant_is_of_type (value, G_VARIANT_TYPE_UINT32))) {
394 g_variant_unref (value);
399 state = g_variant_get_uint32 (value);
400 g_variant_unref (value);
402 if (state == NM_OLD_DEVICE_STATE_ACTIVATED ||
403 state == NM_DEVICE_STATE_ACTIVATED)
404 on_device_activated (nm_device);
408 wifi_proxy_new_cb (GObject *source_object,
410 gpointer user_data) {
414 nm_device = (NMDevice *) user_data;
417 nm_device->wifi_proxy = g_dbus_proxy_new_for_bus_finish (res, &error);
418 if (G_UNLIKELY (error != NULL)) {
419 g_message ("Failed to create D-Bus proxy: %s", error->message);
420 g_error_free (error);
424 use_new_device (nm_device->manager, nm_device);
427 nm_device_unref (nm_device);
431 device_proxy_new_cb (GObject *source_object,
433 gpointer user_data) {
434 GUPnPNetworkManager *manager;
435 GDBusProxy *device_proxy;
441 manager = GUPNP_NETWORK_MANAGER (user_data);
444 device_proxy = g_dbus_proxy_new_for_bus_finish (res, &error);
445 if (G_UNLIKELY (error != NULL)) {
446 g_message ("Failed to create D-Bus proxy: %s", error->message);
447 g_error_free (error);
452 value = g_dbus_proxy_get_cached_property (device_proxy, "DeviceType");
453 if (G_UNLIKELY (value == NULL)) {
454 g_object_unref (device_proxy);
459 if (G_UNLIKELY (!g_variant_is_of_type (value, G_VARIANT_TYPE_UINT32))) {
460 g_variant_unref (value);
461 g_object_unref (device_proxy);
466 type = g_variant_get_uint32 (value);
467 g_variant_unref (value);
469 nm_device = nm_device_new (manager, device_proxy);
471 if (type == NM_DEVICE_TYPE_WIFI) {
474 path = g_dbus_proxy_get_object_path (nm_device->proxy);
475 g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM,
476 G_DBUS_PROXY_FLAGS_NONE,
481 manager->priv->cancellable,
483 nm_device_ref (nm_device));
485 use_new_device (manager, nm_device);
488 g_object_unref (manager);
492 compare_device_path (NMDevice *nm_device, char *device_path)
496 path = g_dbus_proxy_get_object_path (nm_device->proxy);
497 if (G_UNLIKELY (path == NULL))
500 return strcmp (path, device_path);
504 on_manager_signal (GDBusProxy *proxy,
507 GVariant *parameters,
510 GUPnPNetworkManager *manager;
512 manager = GUPNP_NETWORK_MANAGER (user_data);
514 if (g_strcmp0 (signal_name, "DeviceAdded") == 0) {
515 char *device_path = NULL;
517 g_variant_get_child (parameters, 0, "o", &device_path);
518 if (G_UNLIKELY (device_path == NULL))
522 g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM,
523 G_DBUS_PROXY_FLAGS_NONE,
528 manager->priv->cancellable,
530 g_object_ref (manager));
531 g_free (device_path);
532 } else if (g_strcmp0 (signal_name, "DeviceRemoved") == 0) {
535 GUPnPNetworkManagerPrivate *priv;
536 char *device_path = NULL;
538 g_variant_get_child (parameters, 0, "o", &device_path);
539 if (G_UNLIKELY (device_path == NULL))
542 priv = manager->priv;
544 device_node = g_list_find_custom (
547 (GCompareFunc) compare_device_path);
548 if (G_UNLIKELY (device_node == NULL)) {
549 g_free (device_path);
554 nm_device = (NMDevice *) device_node->data;
556 priv->nm_devices = g_list_remove (priv->nm_devices, nm_device);
557 nm_device_unref (nm_device);
558 g_free (device_path);
563 get_devices_cb (GObject *source_object,
567 GUPnPNetworkManager *manager;
569 GVariantIter *device_iter;
571 GError *error = NULL;
573 manager = GUPNP_NETWORK_MANAGER (user_data);
575 ret = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object),
579 g_warning ("Error fetching list of devices: %s",
582 g_error_free (error);
586 g_variant_get_child (ret, 0, "ao", &device_iter);
587 while (g_variant_iter_loop (device_iter, "o", &device_path))
588 g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM,
589 G_DBUS_PROXY_FLAGS_NONE,
594 manager->priv->cancellable,
596 g_object_ref (user_data));
597 g_variant_iter_free (device_iter);
599 g_variant_unref (ret);
602 g_object_unref (manager);
606 schedule_loopback_context_creation (GUPnPNetworkManager *manager)
608 /* Create contexts in mainloop so that is happens after user has hooked
609 * to the "context-available" signal.
611 manager->priv->idle_context_creation_src = g_idle_source_new ();
612 g_source_attach (manager->priv->idle_context_creation_src,
613 g_main_context_get_thread_default ());
614 g_source_set_callback (manager->priv->idle_context_creation_src,
615 create_loopback_context,
616 g_object_ref (manager),
617 (GDestroyNotify) g_object_unref);
618 g_source_unref (manager->priv->idle_context_creation_src);
622 init_network_manager (GUPnPNetworkManager *manager)
624 GUPnPNetworkManagerPrivate *priv;
627 priv = manager->priv;
630 priv->manager_proxy = g_dbus_proxy_new_for_bus_sync (
632 G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
640 g_message ("Failed to connect to NetworkManager: %s",
642 g_error_free (error);
647 g_signal_connect (priv->manager_proxy,
649 G_CALLBACK (on_manager_signal),
653 g_dbus_proxy_call (priv->manager_proxy,
656 G_DBUS_CALL_FLAGS_NONE,
660 g_object_ref (manager));
664 gupnp_network_manager_init (GUPnPNetworkManager *manager)
667 G_TYPE_INSTANCE_GET_PRIVATE (manager,
668 GUPNP_TYPE_NETWORK_MANAGER,
669 GUPnPNetworkManagerPrivate);
673 gupnp_network_manager_constructed (GObject *object)
675 GUPnPNetworkManager *manager;
676 GUPnPNetworkManagerPrivate *priv;
677 GObjectClass *object_class;
679 manager = GUPNP_NETWORK_MANAGER (object);
680 priv = manager->priv;
682 priv->cancellable = g_cancellable_new ();
683 priv->nm_devices = NULL;
684 priv->system_bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL);
686 init_network_manager (manager);
688 schedule_loopback_context_creation (manager);
691 object_class = G_OBJECT_CLASS (gupnp_network_manager_parent_class);
692 if (object_class->constructed != NULL) {
693 object_class->constructed (object);
698 gupnp_network_manager_dispose (GObject *object)
700 GUPnPNetworkManager *manager;
701 GUPnPNetworkManagerPrivate *priv;
702 GObjectClass *object_class;
704 manager = GUPNP_NETWORK_MANAGER (object);
705 priv = manager->priv;
707 if (manager->priv->idle_context_creation_src) {
708 g_source_destroy (manager->priv->idle_context_creation_src);
709 manager->priv->idle_context_creation_src = NULL;
712 if (priv->manager_proxy != NULL) {
713 g_object_unref (priv->manager_proxy);
714 priv->manager_proxy = NULL;
717 if (priv->nm_devices != NULL) {
718 g_list_foreach (priv->nm_devices, (GFunc) nm_device_unref,
720 g_list_free (priv->nm_devices);
721 priv->nm_devices = NULL;
724 if (priv->cancellable != NULL) {
725 g_object_unref (priv->cancellable);
726 priv->cancellable = NULL;
729 g_clear_object (&(priv->system_bus));
732 object_class = G_OBJECT_CLASS (gupnp_network_manager_parent_class);
733 object_class->dispose (object);
737 gupnp_network_manager_class_init (GUPnPNetworkManagerClass *klass)
739 GObjectClass *object_class;
741 object_class = G_OBJECT_CLASS (klass);
743 object_class->constructed = gupnp_network_manager_constructed;
744 object_class->dispose = gupnp_network_manager_dispose;
746 g_type_class_add_private (klass, sizeof (GUPnPNetworkManagerPrivate));
750 gupnp_network_manager_is_available ()
752 GDBusProxy *dbus_proxy;
753 GVariant *ret_values;
754 GError *error = NULL;
755 gboolean ret = FALSE;
757 dbus_proxy = g_dbus_proxy_new_for_bus_sync (
759 G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
767 g_message ("Failed to connect to NetworkManager: %s",
769 g_error_free (error);
774 ret_values = g_dbus_proxy_call_sync (dbus_proxy,
776 g_variant_new ("(s)",
778 G_DBUS_CALL_FLAGS_NONE,
783 g_warning ("%s.NameHasOwner() failed: %s",
786 g_error_free (error);
788 g_variant_get_child (ret_values, 0, "b", &ret);
789 g_variant_unref (ret_values);
792 g_object_unref (dbus_proxy);