2 * Copyright (C) 2009 Nokia Corporation, all rights reserved.
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., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
24 * SECTION:gupnp-network-manager
25 * @short_description: NetworkManager-based implementation of
26 * #GUPnPContextManager.
35 #include <dbus/dbus-glib.h>
36 #include <dbus/dbus-glib-lowlevel.h>
37 #include <dbus/dbus.h>
39 #include "gupnp-network-manager.h"
40 #include "gupnp-context.h"
41 #include "gupnp-marshal.h"
43 #define DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH \
44 (dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_OBJECT_PATH))
46 #define DBUS_SERVICE_NM "org.freedesktop.NetworkManager"
47 #define MANAGER_PATH "/org/freedesktop/NetworkManager"
48 #define MANAGER_INTERFACE "org.freedesktop.NetworkManager"
49 #define DEVICE_INTERFACE "org.freedesktop.NetworkManager.Device"
51 G_DEFINE_TYPE (GUPnPNetworkManager,
52 gupnp_network_manager,
53 GUPNP_TYPE_CONTEXT_MANAGER);
57 NM_DEVICE_STATE_UNKNOWN,
58 NM_DEVICE_STATE_UNMANAGED,
59 NM_DEVICE_STATE_UNAVAILABLE,
60 NM_DEVICE_STATE_DISCONNECTED,
61 NM_DEVICE_STATE_PREPARE,
62 NM_DEVICE_STATE_CONFIG,
63 NM_DEVICE_STATE_NEED_AUTH,
64 NM_DEVICE_STATE_IP_CONFIG,
65 NM_DEVICE_STATE_ACTIVATED,
66 NM_DEVICE_STATE_FAILED
71 GUPnPNetworkManager *manager;
73 GUPnPContext *context;
75 DBusGProxy *device_proxy;
76 DBusGProxy *prop_proxy;
79 struct _GUPnPNetworkManagerPrivate {
80 DBusConnection *dbus_connection;
81 DBusGConnection *connection;
82 DBusGProxy *manager_proxy;
84 GSource *idle_context_creation_src;
90 nm_device_new (GUPnPNetworkManager *manager,
91 const char *device_path)
95 nm_device = g_slice_new0 (NMDevice);
97 nm_device->manager = g_object_ref (manager);
99 nm_device->prop_proxy = dbus_g_proxy_new_for_name (
100 manager->priv->connection,
103 DBUS_INTERFACE_PROPERTIES);
105 nm_device->device_proxy = dbus_g_proxy_new_for_name (
106 manager->priv->connection,
115 nm_device_free (NMDevice *nm_device)
117 g_object_unref (nm_device->prop_proxy);
118 g_object_unref (nm_device->device_proxy);
120 if (nm_device->context != NULL) {
121 g_signal_emit_by_name (nm_device->manager,
122 "context-unavailable",
125 g_object_unref (nm_device->context);
128 g_object_unref (nm_device->manager);
130 g_slice_free (NMDevice, nm_device);
133 #define LOOPBACK_IFACE "lo"
136 create_loopback_context (gpointer data)
138 GUPnPNetworkManager *manager = (GUPnPNetworkManager *) data;
139 GUPnPContext *context;
140 GMainContext *main_context;
142 GError *error = NULL;
144 manager->priv->idle_context_creation_src = NULL;
146 g_object_get (manager,
147 "main-context", &main_context,
151 context = g_object_new (GUPNP_TYPE_CONTEXT,
152 "main-context", main_context,
153 "interface", LOOPBACK_IFACE,
158 g_warning ("Error creating GUPnP context: %s\n",
161 g_error_free (error);
165 g_signal_emit_by_name (manager, "context-available", context);
167 g_object_unref (context);
173 create_context_for_device (NMDevice *nm_device, const char *iface)
175 GError *error = NULL;
176 GMainContext *main_context;
179 g_object_get (nm_device->manager,
180 "main-context", &main_context,
184 nm_device->context = g_object_new (GUPNP_TYPE_CONTEXT,
185 "main-context", main_context,
191 g_warning ("Error creating GUPnP context: %s\n",
194 g_error_free (error);
199 g_signal_emit_by_name (nm_device->manager,
205 get_device_interface_cb (DBusGProxy *proxy,
206 DBusGProxyCall *call,
210 GError *error = NULL;
211 NMDevice *nm_device = (NMDevice *) user_data;
213 if (!dbus_g_proxy_end_call (nm_device->prop_proxy,
216 G_TYPE_VALUE, &value,
218 g_warning ("Error reading property from object: %s\n",
221 g_error_free (error);
225 create_context_for_device (nm_device, g_value_get_string (&value));
226 g_value_unset (&value);
230 get_device_state_cb (DBusGProxy *proxy,
231 DBusGProxyCall *call,
235 GError *error = NULL;
236 NMDevice *nm_device = (NMDevice *) user_data;
238 if (!dbus_g_proxy_end_call (proxy,
241 G_TYPE_VALUE, &value,
243 g_warning ("Error reading property: %s\n", error->message);
245 g_error_free (error);
249 NMDeviceState state = g_value_get_uint (&value);
251 if (state == NM_DEVICE_STATE_ACTIVATED) {
252 dbus_g_proxy_begin_call (nm_device->prop_proxy,
254 get_device_interface_cb,
257 G_TYPE_STRING, DEVICE_INTERFACE,
258 G_TYPE_STRING, "Interface",
262 g_value_unset (&value);
266 on_device_state_changed (DBusGProxy *proxy,
274 nm_device = (NMDevice *) user_data;
276 if (new_state == NM_DEVICE_STATE_ACTIVATED) {
277 dbus_g_proxy_begin_call (nm_device->prop_proxy,
279 get_device_interface_cb,
282 G_TYPE_STRING, DEVICE_INTERFACE,
283 G_TYPE_STRING, "Interface",
285 } else if (nm_device->context != NULL) {
286 /* For all other states we just destroy the context */
287 g_signal_emit_by_name (nm_device->manager,
288 "context-unavailable",
291 g_object_unref (nm_device->context);
292 nm_device->context = NULL;
297 add_device_from_path (char *device_path,
298 GUPnPNetworkManager *manager)
302 nm_device = nm_device_new (manager, device_path);
304 manager->priv->nm_devices = g_list_append (manager->priv->nm_devices,
307 dbus_g_proxy_add_signal (nm_device->device_proxy,
314 dbus_g_proxy_connect_signal (nm_device->device_proxy,
316 G_CALLBACK (on_device_state_changed),
320 dbus_g_proxy_begin_call (nm_device->prop_proxy,
325 G_TYPE_STRING, DEVICE_INTERFACE,
326 G_TYPE_STRING, "State",
331 on_device_added (DBusGProxy *proxy,
335 add_device_from_path (device_path, GUPNP_NETWORK_MANAGER (user_data));
339 compare_device_path (NMDevice *nm_device, char *device_path)
343 path = dbus_g_proxy_get_path (nm_device->device_proxy);
344 if (G_UNLIKELY (path == NULL))
347 return strcmp (path, device_path);
351 on_device_removed (DBusGProxy *proxy,
357 GUPnPNetworkManagerPrivate *priv;
359 priv = GUPNP_NETWORK_MANAGER (user_data)->priv;
361 device_node = g_list_find_custom (priv->nm_devices,
363 (GCompareFunc) compare_device_path);
364 if (G_UNLIKELY (device_node == NULL))
367 nm_device = (NMDevice *) device_node->data;
369 priv->nm_devices = g_list_remove (priv->nm_devices, nm_device);
370 nm_device_free (nm_device);
374 get_devices_cb (DBusGProxy *proxy,
375 DBusGProxyCall *call,
378 GPtrArray *device_paths;
379 GError *error = NULL;
381 if (!dbus_g_proxy_end_call (proxy,
384 DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH,
387 g_warning ("Error fetching list of devices: %s\n",
390 g_error_free (error);
394 g_ptr_array_foreach (device_paths,
395 (GFunc) add_device_from_path,
398 g_ptr_array_foreach (device_paths, (GFunc) g_free, NULL);
399 g_ptr_array_free (device_paths, TRUE);
403 schedule_loopback_context_creation (GUPnPNetworkManager *manager)
405 GMainContext *main_context;
407 g_object_get (manager,
408 "main-context", &main_context,
411 /* Create contexts in mainloop so that is happens after user has hooked
412 * to the "context-available" signal.
414 manager->priv->idle_context_creation_src = g_idle_source_new ();
415 g_source_attach (manager->priv->idle_context_creation_src,
417 g_source_set_callback (manager->priv->idle_context_creation_src,
418 create_loopback_context,
421 g_source_unref (manager->priv->idle_context_creation_src);
424 static DBusGConnection *
425 connect_to_system_bus (GMainContext *main_context,
426 DBusConnection **connection)
428 DBusGConnection *gconnection = NULL;
431 /* Do fake open to initialize types */
432 dbus_g_connection_open ("", NULL);
433 dbus_error_init (&derror);
434 *connection = dbus_bus_get_private (DBUS_BUS_SYSTEM, &derror);
435 if (*connection == NULL) {
436 g_message ("Failed to connect to System Bus: %s",
438 dbus_error_free (&derror);
443 dbus_connection_setup_with_g_main (*connection, main_context);
444 gconnection = dbus_connection_get_g_connection (*connection);
445 if (G_UNLIKELY (gconnection == NULL)) {
446 g_message ("Failed to connect to System Bus.");
455 init_network_manager (GUPnPNetworkManager *manager)
457 GUPnPNetworkManagerPrivate *priv;
458 GMainContext *main_context;
460 priv = manager->priv;
462 g_object_get (manager, "main-context", &main_context, NULL);
464 priv->connection = connect_to_system_bus (main_context,
465 &priv->dbus_connection);
466 if (G_UNLIKELY (priv->connection == NULL)) {
470 priv->manager_proxy = dbus_g_proxy_new_for_name (priv->connection,
475 dbus_g_proxy_add_signal (priv->manager_proxy,
477 DBUS_TYPE_G_OBJECT_PATH,
479 dbus_g_proxy_connect_signal (priv->manager_proxy,
481 G_CALLBACK (on_device_added),
485 dbus_g_proxy_add_signal (priv->manager_proxy,
487 DBUS_TYPE_G_OBJECT_PATH,
489 dbus_g_proxy_connect_signal (priv->manager_proxy,
491 G_CALLBACK (on_device_removed),
495 dbus_g_proxy_begin_call (priv->manager_proxy,
504 gupnp_network_manager_init (GUPnPNetworkManager *manager)
507 G_TYPE_INSTANCE_GET_PRIVATE (manager,
508 GUPNP_TYPE_NETWORK_MANAGER,
509 GUPnPNetworkManagerPrivate);
513 gupnp_network_manager_constructed (GObject *object)
515 GUPnPNetworkManager *manager;
516 GUPnPNetworkManagerPrivate *priv;
517 GObjectClass *object_class;
519 manager = GUPNP_NETWORK_MANAGER (object);
520 priv = manager->priv;
522 priv->nm_devices = NULL;
524 init_network_manager (manager);
526 schedule_loopback_context_creation (manager);
529 object_class = G_OBJECT_CLASS (gupnp_network_manager_parent_class);
530 if (object_class->constructed != NULL) {
531 object_class->constructed (object);
536 gupnp_network_manager_dispose (GObject *object)
538 GUPnPNetworkManager *manager;
539 GUPnPNetworkManagerPrivate *priv;
540 GObjectClass *object_class;
542 manager = GUPNP_NETWORK_MANAGER (object);
543 priv = manager->priv;
545 if (manager->priv->idle_context_creation_src) {
546 g_source_destroy (manager->priv->idle_context_creation_src);
547 manager->priv->idle_context_creation_src = NULL;
550 if (priv->manager_proxy != NULL) {
551 g_object_unref (priv->manager_proxy);
552 priv->manager_proxy = NULL;
555 if (priv->nm_devices != NULL) {
556 g_list_foreach (priv->nm_devices, (GFunc) nm_device_free, NULL);
557 g_list_free (priv->nm_devices);
558 priv->nm_devices = NULL;
561 if (priv->connection) {
562 dbus_connection_close (priv->dbus_connection);
563 dbus_g_connection_unref (priv->connection);
564 priv->connection = NULL;
568 object_class = G_OBJECT_CLASS (gupnp_network_manager_parent_class);
569 object_class->dispose (object);
573 gupnp_network_manager_class_init (GUPnPNetworkManagerClass *klass)
575 GObjectClass *object_class;
577 object_class = G_OBJECT_CLASS (klass);
579 object_class->constructed = gupnp_network_manager_constructed;
580 object_class->dispose = gupnp_network_manager_dispose;
582 dbus_g_object_register_marshaller (gupnp_marshal_VOID__UINT_UINT_UINT,
589 g_type_class_add_private (klass, sizeof (GUPnPNetworkManagerPrivate));
593 gupnp_network_manager_is_available (GMainContext *main_context)
595 DBusConnection *connection;
596 DBusGConnection *gconnection;
597 DBusGProxy *dbus_proxy;
598 GError *error = NULL;
599 gboolean ret = FALSE;
601 gconnection = connect_to_system_bus (main_context, &connection);
602 if (gconnection == NULL)
605 dbus_proxy = dbus_g_proxy_new_for_name (gconnection,
608 DBUS_INTERFACE_DBUS);
610 if (!dbus_g_proxy_call (dbus_proxy,
613 G_TYPE_STRING, DBUS_SERVICE_NM,
615 G_TYPE_BOOLEAN, &ret,
617 g_warning ("%s.NameHasOwner() failed: %s",
620 g_error_free (error);
623 g_object_unref (dbus_proxy);
624 dbus_connection_close (connection);
625 dbus_g_connection_unref (gconnection);