From f4aa499c4ca051ecfb71c8b548cc6ac1ccaede71 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 13 May 2009 21:32:56 -0400 Subject: [PATCH] bluetooth: add bluetooth manager --- configure.ac | 1 + marshallers/nm-marshal.list | 1 + src/Makefile.am | 87 ++--- src/bluez-manager/Makefile.am | 36 ++ src/bluez-manager/nm-bluez-adapter.c | 369 +++++++++++++++++++++ src/bluez-manager/nm-bluez-adapter.h | 67 ++++ src/bluez-manager/nm-bluez-common.h | 37 +++ src/bluez-manager/nm-bluez-device.c | 473 +++++++++++++++++++++++++++ src/bluez-manager/nm-bluez-device.h | 75 +++++ src/bluez-manager/nm-bluez-manager.c | 370 +++++++++++++++++++++ src/bluez-manager/nm-bluez-manager.h | 57 ++++ src/nm-manager.c | 53 +++ 12 files changed, 1584 insertions(+), 42 deletions(-) create mode 100644 src/bluez-manager/Makefile.am create mode 100644 src/bluez-manager/nm-bluez-adapter.c create mode 100644 src/bluez-manager/nm-bluez-adapter.h create mode 100644 src/bluez-manager/nm-bluez-common.h create mode 100644 src/bluez-manager/nm-bluez-device.c create mode 100644 src/bluez-manager/nm-bluez-device.h create mode 100644 src/bluez-manager/nm-bluez-manager.c create mode 100644 src/bluez-manager/nm-bluez-manager.h diff --git a/configure.ac b/configure.ac index 20d02034a..446e0aa0a 100644 --- a/configure.ac +++ b/configure.ac @@ -442,6 +442,7 @@ src/supplicant-manager/tests/Makefile src/ppp-manager/Makefile src/dnsmasq-manager/Makefile src/modem-manager/Makefile +src/bluez-manager/Makefile src/backends/Makefile libnm-util/libnm-util.pc libnm-util/Makefile diff --git a/marshallers/nm-marshal.list b/marshallers/nm-marshal.list index ec3cf45ce..419716c61 100644 --- a/marshallers/nm-marshal.list +++ b/marshallers/nm-marshal.list @@ -18,3 +18,4 @@ VOID:STRING,UINT VOID:OBJECT,OBJECT,ENUM VOID:POINTER,STRING POINTER:POINTER +VOID:STRING,BOXED diff --git a/src/Makefile.am b/src/Makefile.am index be4431a27..ee6218bd8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -7,6 +7,7 @@ SUBDIRS= \ backends \ dnsmasq-manager \ modem-manager \ + bluez-manager \ . \ tests @@ -19,6 +20,7 @@ INCLUDES = -I${top_srcdir} \ -I${top_srcdir}/src/supplicant-manager \ -I${top_srcdir}/src/dnsmasq-manager \ -I${top_srcdir}/src/modem-manager \ + -I$(top_srcdir)/src/bluez-manager \ -I${top_srcdir}/libnm-util \ -I${top_srcdir}/callouts @@ -123,47 +125,48 @@ nm-active-connection-glue.h: $(top_srcdir)/introspection/nm-active-connection.xm nm-dhcp4-config-glue.h: $(top_srcdir)/introspection/nm-dhcp4-config.xml dbus-binding-tool --prefix=nm_dhcp4_config --mode=glib-server --output=$@ $< -BUILT_SOURCES = \ - nm-access-point-glue.h \ - nm-manager-glue.h \ - nm-device-interface-glue.h \ - nm-device-ethernet-glue.h \ - nm-device-wifi-glue.h \ - nm-ip4-config-glue.h \ +BUILT_SOURCES = \ + nm-access-point-glue.h \ + nm-manager-glue.h \ + nm-device-interface-glue.h \ + nm-device-ethernet-glue.h \ + nm-device-wifi-glue.h \ + nm-ip4-config-glue.h \ nm-active-connection-glue.h \ nm-dhcp4-config-glue.h -NetworkManager_CPPFLAGS = \ - $(DBUS_CFLAGS) \ - $(GLIB_CFLAGS) \ - $(HAL_CFLAGS) \ - $(OPENSSL_CFLAGS) \ - $(LIBNL_CFLAGS) \ - -DG_DISABLE_DEPRECATED \ - -DBINDIR=\"$(bindir)\" \ - -DSBINDIR=\"$(sbindir)\" \ - -DLIBEXECDIR=\"$(libexecdir)\" \ - -DDATADIR=\"$(datadir)\" \ - -DSYSCONFDIR=\"$(sysconfdir)\" \ - -DLOCALSTATEDIR=\"$(localstatedir)\" \ - -DNM_RUN_DIR=\"$(rundir)\" \ - -DNMLOCALEDIR=\"$(datadir)/locale\" \ +NetworkManager_CPPFLAGS = \ + $(DBUS_CFLAGS) \ + $(GLIB_CFLAGS) \ + $(HAL_CFLAGS) \ + $(OPENSSL_CFLAGS) \ + $(LIBNL_CFLAGS) \ + -DG_DISABLE_DEPRECATED \ + -DBINDIR=\"$(bindir)\" \ + -DSBINDIR=\"$(sbindir)\" \ + -DLIBEXECDIR=\"$(libexecdir)\" \ + -DDATADIR=\"$(datadir)\" \ + -DSYSCONFDIR=\"$(sysconfdir)\" \ + -DLOCALSTATEDIR=\"$(localstatedir)\" \ + -DNM_RUN_DIR=\"$(rundir)\" \ + -DNMLOCALEDIR=\"$(datadir)/locale\" \ -DARP_DEBUG -NetworkManager_LDADD = \ - $(DBUS_LIBS) \ - $(GLIB_LIBS) \ - $(HAL_LIBS) \ - $(LIBNL_LIBS) \ - $(top_builddir)/marshallers/libmarshallers.la \ - ./named-manager/libnamed-manager.la \ - ./vpn-manager/libvpn-manager.la \ - ./dhcp-manager/libdhcp-manager.la \ - ./supplicant-manager/libsupplicant-manager.la \ - ./dnsmasq-manager/libdnsmasq-manager.la \ - ./ppp-manager/libppp-manager.la \ - ./modem-manager/libmodem-manager.la \ - ./backends/libnmbackend.la \ +NetworkManager_LDADD = \ + $(DBUS_LIBS) \ + $(GLIB_LIBS) \ + $(HAL_LIBS) \ + $(LIBNL_LIBS) \ + $(top_builddir)/marshallers/libmarshallers.la \ + ./named-manager/libnamed-manager.la \ + ./vpn-manager/libvpn-manager.la \ + ./dhcp-manager/libdhcp-manager.la \ + ./supplicant-manager/libsupplicant-manager.la \ + ./dnsmasq-manager/libdnsmasq-manager.la \ + ./ppp-manager/libppp-manager.la \ + ./modem-manager/libmodem-manager.la \ + ./bluez-manager/libbluez-manager.la \ + ./backends/libnmbackend.la \ $(top_builddir)/libnm-util/libnm-util.la NetworkManager_LDFLAGS = -rdynamic @@ -171,12 +174,12 @@ NetworkManager_LDFLAGS = -rdynamic libexec_PROGRAMS = nm-crash-logger nm_crash_logger_SOURCES = nm-crash-logger.c nm_crash_logger_CPPFLAGS = \ - $(GLIB_CFLAGS) \ - -DG_DISABLE_DEPRECATED \ - -DBINDIR=\"$(bindir)\" \ - -DSBINDIR=\"$(sbindir)\" \ - -DDATADIR=\"$(datadir)\" \ - -DSYSCONFDIR=\"$(sysconfdir)\" \ + $(GLIB_CFLAGS) \ + -DG_DISABLE_DEPRECATED \ + -DBINDIR=\"$(bindir)\" \ + -DSBINDIR=\"$(sbindir)\" \ + -DDATADIR=\"$(datadir)\" \ + -DSYSCONFDIR=\"$(sysconfdir)\" \ -DLOCALSTATEDIR=\"$(localstatedir)\" nm_crash_logger_LDADD = $(GLIB_LIBS) diff --git a/src/bluez-manager/Makefile.am b/src/bluez-manager/Makefile.am new file mode 100644 index 000000000..17d149a68 --- /dev/null +++ b/src/bluez-manager/Makefile.am @@ -0,0 +1,36 @@ +INCLUDES = \ + -I${top_srcdir} \ + -I${top_srcdir}/include \ + -I${top_srcdir}/libnm-util \ + -I${top_srcdir}/src \ + -I${top_builddir}/marshallers \ + -I$(top_srcdir)/src/nm-bluez-manager + +noinst_LTLIBRARIES = libbluez-manager.la + +libbluez_manager_la_SOURCES = \ + nm-bluez-manager.c \ + nm-bluez-manager.h \ + nm-bluez-adapter.c \ + nm-bluez-adapter.h \ + nm-bluez-device.c \ + nm-bluez-device.h \ + nm-bluez-common.h + +libbluez_manager_la_CPPFLAGS = \ + $(DBUS_CFLAGS) \ + $(GLIB_CFLAGS) \ + $(BLUEZ_CFLAGS) \ + -DG_DISABLE_DEPRECATED \ + -DBINDIR=\"$(bindir)\" \ + -DDATADIR=\"$(datadir)\" \ + -DSYSCONFDIR=\"$(sysconfdir)\" \ + -DLIBEXECDIR=\"$(libexecdir)\" \ + -DLOCALSTATEDIR=\"$(localstatedir)\" + +libbluez_manager_la_LIBADD = \ + $(DBUS_LIBS) \ + $(GLIB_LIBS) \ + $(BLUEZ_LIBS) \ + $(top_builddir)/marshallers/libmarshallers.la + diff --git a/src/bluez-manager/nm-bluez-adapter.c b/src/bluez-manager/nm-bluez-adapter.c new file mode 100644 index 000000000..903dfc3ee --- /dev/null +++ b/src/bluez-manager/nm-bluez-adapter.c @@ -0,0 +1,369 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager -- Network link manager + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2009 Red Hat, Inc. + */ + +#include +#include + +#include "NetworkManager.h" +#include "nm-dbus-manager.h" +#include "nm-bluez-adapter.h" +#include "nm-bluez-device.h" +#include "nm-bluez-common.h" +#include "nm-dbus-glib-types.h" +#include "nm-utils.h" + + +G_DEFINE_TYPE (NMBluezAdapter, nm_bluez_adapter, G_TYPE_OBJECT) + +#define NM_BLUEZ_ADAPTER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_BLUEZ_ADAPTER, NMBluezAdapterPrivate)) + +typedef struct { + char *path; + DBusGProxy *proxy; + gboolean initialized; + + char *address; + GHashTable *devices; +} NMBluezAdapterPrivate; + + +enum { + PROP_0, + PROP_PATH, + PROP_ADDRESS, + + LAST_PROP +}; + +/* Signals */ +enum { + INITIALIZED, + DEVICE_ADDED, + DEVICE_REMOVED, + LAST_SIGNAL +}; +static guint signals[LAST_SIGNAL] = { 0 }; + +const char * +nm_bluez_adapter_get_path (NMBluezAdapter *self) +{ + g_return_val_if_fail (NM_IS_BLUEZ_ADAPTER (self), NULL); + + return NM_BLUEZ_ADAPTER_GET_PRIVATE (self)->path; +} + +const char * +nm_bluez_adapter_get_address (NMBluezAdapter *self) +{ + g_return_val_if_fail (NM_IS_BLUEZ_ADAPTER (self), NULL); + + return NM_BLUEZ_ADAPTER_GET_PRIVATE (self)->address; +} + +gboolean +nm_bluez_adapter_get_initialized (NMBluezAdapter *self) +{ + g_return_val_if_fail (NM_IS_BLUEZ_ADAPTER (self), FALSE); + + return NM_BLUEZ_ADAPTER_GET_PRIVATE (self)->initialized; +} + +static void +devices_to_list (gpointer key, gpointer data, gpointer user_data) +{ + NMBluezDevice *device = NM_BLUEZ_DEVICE (data); + GSList **list = user_data; + + if (nm_bluez_device_get_usable (device)) + *list = g_slist_append (*list, data); +} + +GSList * +nm_bluez_adapter_get_devices (NMBluezAdapter *self) +{ + NMBluezAdapterPrivate *priv = NM_BLUEZ_ADAPTER_GET_PRIVATE (self); + GSList *devices = NULL; + + g_hash_table_foreach (priv->devices, devices_to_list, &devices); + return devices; +} + +static void +device_usable (NMBluezDevice *device, GParamSpec *pspec, gpointer user_data) +{ + NMBluezAdapter *self = NM_BLUEZ_ADAPTER (user_data); + NMBluezAdapterPrivate *priv = NM_BLUEZ_ADAPTER_GET_PRIVATE (self); + + if (nm_bluez_device_get_usable (device)) + g_signal_emit (self, signals[DEVICE_ADDED], 0, device); + else { + g_object_ref (device); + g_hash_table_remove (priv->devices, nm_bluez_device_get_path (device)); + g_signal_emit (self, signals[DEVICE_REMOVED], 0, device); + g_object_unref (device); + } +} + +static void +device_initialized (NMBluezDevice *device, gboolean success, gpointer user_data) +{ + NMBluezAdapter *self = NM_BLUEZ_ADAPTER (user_data); + NMBluezAdapterPrivate *priv = NM_BLUEZ_ADAPTER_GET_PRIVATE (self); + + if (!success) + g_hash_table_remove (priv->devices, nm_bluez_device_get_path (device)); + else + device_usable (device, NULL, self); +} + +static void +device_created (DBusGProxy *proxy, const char *path, gpointer user_data) +{ + NMBluezAdapter *self = NM_BLUEZ_ADAPTER (user_data); + NMBluezAdapterPrivate *priv = NM_BLUEZ_ADAPTER_GET_PRIVATE (self); + NMBluezDevice *device; + + device = nm_bluez_device_new (path); + g_signal_connect (device, "initialized", G_CALLBACK (device_initialized), self); + g_signal_connect (device, "notify::usable", G_CALLBACK (device_usable), self); + g_hash_table_insert (priv->devices, g_strdup (path), device); +} + +static void +device_removed (DBusGProxy *proxy, const char *path, gpointer user_data) +{ + NMBluezAdapter *self = NM_BLUEZ_ADAPTER (user_data); + NMBluezAdapterPrivate *priv = NM_BLUEZ_ADAPTER_GET_PRIVATE (self); + NMBluezDevice *device; + + device = g_hash_table_lookup (priv->devices, path); + if (device) { + g_object_ref (device); + g_hash_table_remove (priv->devices, path); + g_signal_emit (self, signals[DEVICE_REMOVED], 0, device); + g_object_unref (device); + } +} + + +static void +get_properties_cb (DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data) +{ + NMBluezAdapter *self = NM_BLUEZ_ADAPTER (user_data); + NMBluezAdapterPrivate *priv = NM_BLUEZ_ADAPTER_GET_PRIVATE (self); + GHashTable *properties = NULL; + GError *err = NULL; + GValue *value; + GPtrArray *devices; + int i; + + if (!dbus_g_proxy_end_call (proxy, call, &err, + DBUS_TYPE_G_MAP_OF_VARIANT, &properties, + G_TYPE_INVALID)) { + nm_warning ("bluez error getting adapter properties: %s", + err && err->message ? err->message : "(unknown)"); + g_error_free (err); + goto done; + } + + value = g_hash_table_lookup (properties, "Address"); + priv->address = value ? g_value_dup_string (value) : NULL; + + value = g_hash_table_lookup (properties, "Devices"); + devices = value ? g_value_get_boxed (value) : NULL; + + for (i = 0; devices && i < devices->len; i++) + device_created (priv->proxy, g_ptr_array_index (devices, i), self); + + g_hash_table_unref (properties); + + priv->initialized = TRUE; + +done: + g_signal_emit (self, signals[INITIALIZED], 0, priv->initialized); +} + +static void +query_properties (NMBluezAdapter *self) +{ + NMBluezAdapterPrivate *priv = NM_BLUEZ_ADAPTER_GET_PRIVATE (self); + DBusGProxyCall *call; + + call = dbus_g_proxy_begin_call (priv->proxy, "GetProperties", + get_properties_cb, + self, + NULL, G_TYPE_INVALID); + if (!call) { + nm_warning ("failed to request Bluetooth adapter properties for %s.", + priv->path); + } +} + +NMBluezAdapter * +nm_bluez_adapter_new (const char *path) +{ + NMBluezAdapter *self; + NMBluezAdapterPrivate *priv; + NMDBusManager *dbus_mgr; + DBusGConnection *connection; + + self = (NMBluezAdapter *) g_object_new (NM_TYPE_BLUEZ_ADAPTER, + NM_BLUEZ_ADAPTER_PATH, path, + NULL); + if (!self) + return NULL; + + priv = NM_BLUEZ_ADAPTER_GET_PRIVATE (self); + dbus_mgr = nm_dbus_manager_get (); + connection = nm_dbus_manager_get_connection (dbus_mgr); + + priv->proxy = dbus_g_proxy_new_for_name (connection, + BLUEZ_SERVICE, + priv->path, + BLUEZ_ADAPTER_INTERFACE); + g_object_unref (dbus_mgr); + + dbus_g_proxy_add_signal (priv->proxy, "DeviceCreated", + DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID); + dbus_g_proxy_connect_signal (priv->proxy, "DeviceCreated", + G_CALLBACK (device_created), self, NULL); + + dbus_g_proxy_add_signal (priv->proxy, "DeviceRemoved", + DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID); + dbus_g_proxy_connect_signal (priv->proxy, "DeviceRemoved", + G_CALLBACK (device_removed), self, NULL); + + query_properties (self); + return self; +} + +static void +nm_bluez_adapter_init (NMBluezAdapter *self) +{ + NMBluezAdapterPrivate *priv = NM_BLUEZ_ADAPTER_GET_PRIVATE (self); + + priv->devices = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, g_object_unref); +} + +static void +finalize (GObject *object) +{ + NMBluezAdapterPrivate *priv = NM_BLUEZ_ADAPTER_GET_PRIVATE (object); + + g_hash_table_destroy (priv->devices); + g_free (priv->address); + g_free (priv->path); + g_object_unref (priv->proxy); + + G_OBJECT_CLASS (nm_bluez_adapter_parent_class)->finalize (object); +} + +static void +get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + NMBluezAdapterPrivate *priv = NM_BLUEZ_ADAPTER_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_PATH: + g_value_set_string (value, priv->path); + break; + case PROP_ADDRESS: + g_value_set_string (value, priv->address); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +set_property (GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec) +{ + NMBluezAdapterPrivate *priv = NM_BLUEZ_ADAPTER_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_PATH: + /* construct only */ + priv->path = g_value_dup_string (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nm_bluez_adapter_class_init (NMBluezAdapterClass *config_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (config_class); + + g_type_class_add_private (config_class, sizeof (NMBluezAdapterPrivate)); + + /* virtual methods */ + object_class->get_property = get_property; + object_class->set_property = set_property; + object_class->finalize = finalize; + + /* Properties */ + g_object_class_install_property + (object_class, PROP_PATH, + g_param_spec_string (NM_BLUEZ_ADAPTER_PATH, + "DBus Path", + "DBus Path", + NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + + g_object_class_install_property + (object_class, PROP_ADDRESS, + g_param_spec_string (NM_BLUEZ_ADAPTER_ADDRESS, + "Address", + "Address", + NULL, + G_PARAM_READABLE)); + + /* Signals */ + signals[INITIALIZED] = g_signal_new ("initialized", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (NMBluezAdapterClass, initialized), + NULL, NULL, + g_cclosure_marshal_VOID__BOOLEAN, + G_TYPE_NONE, 1, G_TYPE_BOOLEAN); + + signals[DEVICE_ADDED] = g_signal_new ("device-added", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (NMBluezAdapterClass, device_added), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, G_TYPE_OBJECT); + + signals[DEVICE_REMOVED] = g_signal_new ("device-removed", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (NMBluezAdapterClass, device_removed), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, G_TYPE_OBJECT); +} + diff --git a/src/bluez-manager/nm-bluez-adapter.h b/src/bluez-manager/nm-bluez-adapter.h new file mode 100644 index 000000000..c552e9890 --- /dev/null +++ b/src/bluez-manager/nm-bluez-adapter.h @@ -0,0 +1,67 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager -- Network link manager + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2009 Red Hat, Inc. + */ + +#ifndef NM_BLUEZ_ADAPTER_H +#define NM_BLUEZ_ADAPTER_H + +#include +#include + +#include "nm-bluez-device.h" + +#define NM_TYPE_BLUEZ_ADAPTER (nm_bluez_adapter_get_type ()) +#define NM_BLUEZ_ADAPTER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_BLUEZ_ADAPTER, NMBluezAdapter)) +#define NM_BLUEZ_ADAPTER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_BLUEZ_ADAPTER, NMBluezAdapterClass)) +#define NM_IS_BLUEZ_ADAPTER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_BLUEZ_ADAPTER)) +#define NM_IS_BLUEZ_ADAPTER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_BLUEZ_ADAPTER)) +#define NM_BLUEZ_ADAPTER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_BLUEZ_ADAPTER, NMBluezAdapterClass)) + +#define NM_BLUEZ_ADAPTER_PATH "path" +#define NM_BLUEZ_ADAPTER_ADDRESS "address" + +typedef struct { + GObject parent; +} NMBluezAdapter; + +typedef struct { + GObjectClass parent; + + /* virtual functions */ + void (*initialized) (NMBluezAdapter *self, gboolean success); + + void (*device_added) (NMBluezAdapter *self, NMBluezDevice *device); + + void (*device_removed) (NMBluezAdapter *self, NMBluezDevice *device); +} NMBluezAdapterClass; + +GType nm_bluez_adapter_get_type (void); + +NMBluezAdapter *nm_bluez_adapter_new (const char *path); + +const char *nm_bluez_adapter_get_path (NMBluezAdapter *self); + +const char *nm_bluez_adapter_get_address (NMBluezAdapter *self); + +gboolean nm_bluez_adapter_get_initialized (NMBluezAdapter *self); + +GSList *nm_bluez_adapter_get_devices (NMBluezAdapter *self); + +#endif /* NM_BLUEZ_ADAPTER_H */ + diff --git a/src/bluez-manager/nm-bluez-common.h b/src/bluez-manager/nm-bluez-common.h new file mode 100644 index 000000000..b908f4785 --- /dev/null +++ b/src/bluez-manager/nm-bluez-common.h @@ -0,0 +1,37 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager -- Network link manager + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2009 Red Hat, Inc. + */ + +#ifndef NM_BLUEZ_COMMON_H +#define NM_BLUEZ_COMMON_H + +enum { + NM_BLUEZ_TYPE_DUN = 1 << 1, + NM_BLUEZ_TYPE_PANU = 1 << 2, +}; + +#define BLUEZ_SERVICE "org.bluez" + +#define BLUEZ_MANAGER_PATH "/" +#define BLUEZ_MANAGER_INTERFACE "org.bluez.Manager" +#define BLUEZ_ADAPTER_INTERFACE "org.bluez.Adapter" +#define BLUEZ_DEVICE_INTERFACE "org.bluez.Device" + +#endif /* NM_BLUEZ_COMMON_H */ + diff --git a/src/bluez-manager/nm-bluez-device.c b/src/bluez-manager/nm-bluez-device.c new file mode 100644 index 000000000..e209504ad --- /dev/null +++ b/src/bluez-manager/nm-bluez-device.c @@ -0,0 +1,473 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager -- Network link manager + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2009 Red Hat, Inc. + */ + +#include +#include + +#include "NetworkManager.h" +#include "nm-dbus-manager.h" +#include "nm-bluez-device.h" +#include "nm-bluez-common.h" +#include "nm-dbus-glib-types.h" +#include "nm-utils.h" +#include "nm-marshal.h" + + +G_DEFINE_TYPE (NMBluezDevice, nm_bluez_device, G_TYPE_OBJECT) + +#define NM_BLUEZ_DEVICE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_BLUEZ_DEVICE, NMBluezDevicePrivate)) + +typedef struct { + char *path; + DBusGProxy *proxy; + gboolean initialized; + gboolean usable; + + gboolean paired; + guint32 class; + + char *address; + char *name; + guint32 uuids; + gint rssi; +} NMBluezDevicePrivate; + + +enum { + PROP_0, + PROP_PATH, + PROP_ADDRESS, + PROP_NAME, + PROP_UUIDS, + PROP_RSSI, + PROP_PAIRED, + PROP_USABLE, + + LAST_PROP +}; + +/* Signals */ +enum { + INITIALIZED, + LAST_SIGNAL +}; +static guint signals[LAST_SIGNAL] = { 0 }; + +const char * +nm_bluez_device_get_path (NMBluezDevice *self) +{ + g_return_val_if_fail (NM_IS_BLUEZ_DEVICE (self), NULL); + + return NM_BLUEZ_DEVICE_GET_PRIVATE (self)->path; +} + +const char * +nm_bluez_device_get_address (NMBluezDevice *self) +{ + g_return_val_if_fail (NM_IS_BLUEZ_DEVICE (self), NULL); + + return NM_BLUEZ_DEVICE_GET_PRIVATE (self)->address; +} + +gboolean +nm_bluez_device_get_initialized (NMBluezDevice *self) +{ + g_return_val_if_fail (NM_IS_BLUEZ_DEVICE (self), FALSE); + + return NM_BLUEZ_DEVICE_GET_PRIVATE (self)->initialized; +} + +gboolean +nm_bluez_device_get_usable (NMBluezDevice *self) +{ + g_return_val_if_fail (NM_IS_BLUEZ_DEVICE (self), FALSE); + + return NM_BLUEZ_DEVICE_GET_PRIVATE (self)->usable; +} + +const char * +nm_bluez_device_get_name (NMBluezDevice *self) +{ + g_return_val_if_fail (NM_IS_BLUEZ_DEVICE (self), NULL); + + return NM_BLUEZ_DEVICE_GET_PRIVATE (self)->name; +} + +guint32 +nm_bluez_device_get_uuids (NMBluezDevice *self) +{ + g_return_val_if_fail (NM_IS_BLUEZ_DEVICE (self), 0); + + return NM_BLUEZ_DEVICE_GET_PRIVATE (self)->uuids; +} + +gint +nm_bluez_device_get_rssi (NMBluezDevice *self) +{ + g_return_val_if_fail (NM_IS_BLUEZ_DEVICE (self), 0); + + return NM_BLUEZ_DEVICE_GET_PRIVATE (self)->rssi; +} + +static gboolean is_phone_or_modem (guint32 class) +{ + switch ((class & 0x1f00) >> 8) { + case 0x02: + switch ((class & 0xfc) >> 2) { + case 0x01: + case 0x02: + case 0x03: + case 0x05: + case 0x04: + return TRUE; + } + break; + default: + break; + } + return FALSE; +} + +static guint32 +convert_uuids (const char **strings) +{ + const char **iter; + guint32 uuids = 0; + + for (iter = strings; iter && *iter; iter++) { + if (!strcmp (*iter, "DialupNetworking")) + uuids |= NM_BLUEZ_TYPE_DUN; + else if (!strcmp (*iter, "PANU")) + uuids |= NM_BLUEZ_TYPE_PANU; + } + + return uuids; +} + +static void +check_emit_usable (NMBluezDevice *self) +{ + NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self); + + if ( priv->initialized + && priv->uuids + && is_phone_or_modem (priv->class) + && priv->paired + && priv->name + && priv->address) { + if (!priv->usable) { + priv->usable = TRUE; + g_object_notify (G_OBJECT (self), NM_BLUEZ_DEVICE_USABLE); + } + } else { + if (priv->usable) { + priv->usable = FALSE; + g_object_notify (G_OBJECT (self), NM_BLUEZ_DEVICE_USABLE); + } + } +} + +static void +property_changed (DBusGProxy *proxy, + const char *property, + GValue *value, + gpointer user_data) +{ + NMBluezDevice *self = NM_BLUEZ_DEVICE (user_data); + NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self); + const char *str; + guint32 uint_val; + gint int_val; + gboolean bool_val; + + if (!strcmp (property, "Name")) { + str = g_value_get_string (value); + if ( (!priv->name && str) + || (priv->name && !str) + || (priv->name && str && strcmp (priv->name, str))) { + g_free (priv->name); + priv->name = str ? g_strdup (str) : NULL; + g_object_notify (G_OBJECT (self), NM_BLUEZ_DEVICE_NAME); + check_emit_usable (self); + } + } else if (!strcmp (property, "Class")) { + uint_val = g_value_get_uint (value); + if (priv->class != uint_val) { + priv->class = uint_val; + check_emit_usable (self); + } + } else if (!strcmp (property, "RSSI")) { + int_val = g_value_get_int (value); + if (priv->rssi != int_val) { + priv->rssi = int_val; + g_object_notify (G_OBJECT (self), NM_BLUEZ_DEVICE_RSSI); + } + } else if (!strcmp (property, "UUIDs")) { + uint_val = convert_uuids ((const char **) g_value_get_boxed (value)); + if (priv->uuids != uint_val) { + priv->uuids = uint_val; + g_object_notify (G_OBJECT (self), NM_BLUEZ_DEVICE_UUIDS); + check_emit_usable (self); + } + } else if (!strcmp (property, "Paired")) { + bool_val = g_value_get_boolean (value); + if (priv->paired != bool_val) { + priv->paired = bool_val; + check_emit_usable (self); + } + } +} + +static void +get_properties_cb (DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data) +{ + NMBluezDevice *self = NM_BLUEZ_DEVICE (user_data); + NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self); + GHashTable *properties = NULL; + GError *err = NULL; + GValue *value; + + if (!dbus_g_proxy_end_call (proxy, call, &err, + DBUS_TYPE_G_MAP_OF_VARIANT, &properties, + G_TYPE_INVALID)) { + nm_warning ("bluez error getting adapter properties: %s", + err && err->message ? err->message : "(unknown)"); + g_error_free (err); + g_signal_emit (self, signals[INITIALIZED], 0, FALSE); + return; + } + + value = g_hash_table_lookup (properties, "Address"); + priv->address = value ? g_value_dup_string (value) : NULL; + + value = g_hash_table_lookup (properties, "Name"); + priv->name = value ? g_value_dup_string (value) : NULL; + + value = g_hash_table_lookup (properties, "Class"); + priv->class = value ? g_value_get_uint (value) : 0; + + value = g_hash_table_lookup (properties, "RSSI"); + priv->rssi = value ? g_value_get_int (value) : 0; + + value = g_hash_table_lookup (properties, "UUIDs"); + priv->uuids = value ? convert_uuids ((const char **) g_value_get_boxed (value)) : 0; + + g_hash_table_unref (properties); + + priv->initialized = TRUE; + g_signal_emit (self, signals[INITIALIZED], 0, TRUE); + + check_emit_usable (self); +} + +static void +query_properties (NMBluezDevice *self) +{ + NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self); + DBusGProxyCall *call; + + call = dbus_g_proxy_begin_call (priv->proxy, "GetProperties", + get_properties_cb, + self, + NULL, G_TYPE_INVALID); + if (!call) { + nm_warning ("failed to request Bluetooth device properties for %s.", + priv->path); + } +} + +NMBluezDevice * +nm_bluez_device_new (const char *path) +{ + NMBluezDevice *self; + NMBluezDevicePrivate *priv; + NMDBusManager *dbus_mgr; + DBusGConnection *connection; + + + self = (NMBluezDevice *) g_object_new (NM_TYPE_BLUEZ_DEVICE, + NM_BLUEZ_DEVICE_PATH, path, + NULL); + if (!self) + return NULL; + + priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self); + dbus_mgr = nm_dbus_manager_get (); + connection = nm_dbus_manager_get_connection (dbus_mgr); + + priv->proxy = dbus_g_proxy_new_for_name (connection, + BLUEZ_SERVICE, + priv->path, + BLUEZ_DEVICE_INTERFACE); + g_object_unref (dbus_mgr); + + dbus_g_object_register_marshaller (_nm_marshal_VOID__STRING_BOXED, + G_TYPE_NONE, + G_TYPE_STRING, G_TYPE_VALUE, + G_TYPE_INVALID); + dbus_g_proxy_add_signal (priv->proxy, "PropertyChanged", + G_TYPE_STRING, G_TYPE_VALUE, G_TYPE_INVALID); + dbus_g_proxy_connect_signal (priv->proxy, "PropertyChanged", + G_CALLBACK (property_changed), self, NULL); + + query_properties (self); + return self; +} + +static void +nm_bluez_device_init (NMBluezDevice *self) +{ +} + +static void +finalize (GObject *object) +{ + NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (object); + + g_free (priv->path); + g_free (priv->address); + g_free (priv->name); + g_object_unref (priv->proxy); + + G_OBJECT_CLASS (nm_bluez_device_parent_class)->finalize (object); +} + +static void +get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_PATH: + g_value_set_string (value, priv->path); + break; + case PROP_ADDRESS: + g_value_set_string (value, priv->address); + break; + case PROP_NAME: + g_value_set_string (value, priv->name); + break; + case PROP_UUIDS: + g_value_set_uint (value, priv->uuids); + break; + case PROP_RSSI: + g_value_set_int (value, priv->rssi); + break; + case PROP_PAIRED: + g_value_set_boolean (value, priv->paired); + break; + case PROP_USABLE: + g_value_set_boolean (value, priv->usable); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +set_property (GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec) +{ + NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_PATH: + /* construct only */ + priv->path = g_value_dup_string (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nm_bluez_device_class_init (NMBluezDeviceClass *config_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (config_class); + + g_type_class_add_private (config_class, sizeof (NMBluezDevicePrivate)); + + /* virtual methods */ + object_class->get_property = get_property; + object_class->set_property = set_property; + object_class->finalize = finalize; + + /* Properties */ + g_object_class_install_property + (object_class, PROP_PATH, + g_param_spec_string (NM_BLUEZ_DEVICE_PATH, + "DBus Path", + "DBus Path", + NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + + g_object_class_install_property + (object_class, PROP_ADDRESS, + g_param_spec_string (NM_BLUEZ_DEVICE_ADDRESS, + "Address", + "Address", + NULL, + G_PARAM_READABLE)); + + g_object_class_install_property + (object_class, PROP_NAME, + g_param_spec_string (NM_BLUEZ_DEVICE_NAME, + "Name", + "Name", + NULL, + G_PARAM_READABLE)); + + g_object_class_install_property + (object_class, PROP_UUIDS, + g_param_spec_uint (NM_BLUEZ_DEVICE_UUIDS, + "UUIDs", + "UUIDs", + 0, G_MAXUINT, 0, + G_PARAM_READABLE)); + + g_object_class_install_property + (object_class, PROP_RSSI, + g_param_spec_int (NM_BLUEZ_DEVICE_RSSI, + "RSSI", + "RSSI", + G_MININT, G_MAXINT, 0, + G_PARAM_READABLE)); + + g_object_class_install_property + (object_class, PROP_USABLE, + g_param_spec_boolean (NM_BLUEZ_DEVICE_USABLE, + "Usable", + "Usable", + FALSE, + G_PARAM_READABLE)); + + /* Signals */ + signals[INITIALIZED] = g_signal_new ("initialized", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (NMBluezDeviceClass, initialized), + NULL, NULL, + g_cclosure_marshal_VOID__BOOLEAN, + G_TYPE_NONE, 1, G_TYPE_BOOLEAN); +} + diff --git a/src/bluez-manager/nm-bluez-device.h b/src/bluez-manager/nm-bluez-device.h new file mode 100644 index 000000000..7996393c4 --- /dev/null +++ b/src/bluez-manager/nm-bluez-device.h @@ -0,0 +1,75 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager -- Network link manager + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2009 Red Hat, Inc. + */ + +#ifndef NM_BLUEZ_DEVICE_H +#define NM_BLUEZ_DEVICE_H + +#include +#include + +#define NM_TYPE_BLUEZ_DEVICE (nm_bluez_device_get_type ()) +#define NM_BLUEZ_DEVICE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_BLUEZ_DEVICE, NMBluezDevice)) +#define NM_BLUEZ_DEVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_BLUEZ_DEVICE, NMBluezDeviceClass)) +#define NM_IS_BLUEZ_DEVICE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_BLUEZ_DEVICE)) +#define NM_IS_BLUEZ_DEVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_BLUEZ_DEVICE)) +#define NM_BLUEZ_DEVICE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_BLUEZ_DEVICE, NMBluezDeviceClass)) + +#define NM_BLUEZ_DEVICE_PATH "path" +#define NM_BLUEZ_DEVICE_ADDRESS "address" +#define NM_BLUEZ_DEVICE_NAME "name" +#define NM_BLUEZ_DEVICE_UUIDS "uuids" +#define NM_BLUEZ_DEVICE_RSSI "rssi" +#define NM_BLUEZ_DEVICE_USABLE "usable" + +typedef struct { + GObject parent; +} NMBluezDevice; + +typedef struct { + GObjectClass parent; + + /* virtual functions */ + void (*initialized) (NMBluezDevice *self, gboolean success); + + void (*invalid) (NMBluezDevice *self); +} NMBluezDeviceClass; + +GType nm_bluez_device_get_type (void); + +NMBluezDevice *nm_bluez_device_new (const char *path); + +const char *nm_bluez_device_get_path (NMBluezDevice *self); + +gboolean nm_bluez_device_get_initialized (NMBluezDevice *self); + +gboolean nm_bluez_device_get_usable (NMBluezDevice *self); + +const char *nm_bluez_device_get_address (NMBluezDevice *self); + +const char *nm_bluez_device_get_name (NMBluezDevice *self); + +guint32 nm_bluez_device_get_class (NMBluezDevice *self); + +guint32 nm_bluez_device_get_uuids (NMBluezDevice *self); + +gint nm_bluez_device_get_rssi (NMBluezDevice *self); + +#endif /* NM_BLUEZ_DEVICE_H */ + diff --git a/src/bluez-manager/nm-bluez-manager.c b/src/bluez-manager/nm-bluez-manager.c new file mode 100644 index 000000000..20c6b358a --- /dev/null +++ b/src/bluez-manager/nm-bluez-manager.c @@ -0,0 +1,370 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager -- Network link manager + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2007 - 2008 Novell, Inc. + * Copyright (C) 2007 - 2009 Red Hat, Inc. + */ + +#include +#include +#include +#include + +#include "nm-utils.h" +#include "nm-dbus-glib-types.h" +#include "nm-marshal.h" +#include "nm-bluez-manager.h" +#include "nm-bluez-adapter.h" +#include "nm-dbus-manager.h" +#include "nm-bluez-common.h" + + +typedef struct { + NMDBusManager *dbus_mgr; + gulong name_owner_changed_id; + + DBusGProxy *proxy; + + NMBluezAdapter *adapter; +} NMBluezManagerPrivate; + +#define NM_BLUEZ_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_BLUEZ_MANAGER, NMBluezManagerPrivate)) + +G_DEFINE_TYPE (NMBluezManager, nm_bluez_manager, G_TYPE_OBJECT) + +enum { + BDADDR_ADDED, + BDADDR_REMOVED, + + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +void +nm_bluez_manager_query_devices (NMBluezManager *self) +{ + NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE (self); + GSList *devices, *iter; + + if (!priv->adapter) + return; + + devices = nm_bluez_adapter_get_devices (priv->adapter); + for (iter = devices; iter; iter = g_slist_next (iter)) { + NMBluezDevice *device = NM_BLUEZ_DEVICE (iter->data); + + g_signal_emit (self, signals[BDADDR_ADDED], 0, + nm_bluez_device_get_address (device), + nm_bluez_device_get_uuids (device)); + } + g_slist_free (devices); +} + +static void +device_added (NMBluezAdapter *adapter, NMBluezDevice *device, gpointer user_data) +{ + NMBluezManager *self = NM_BLUEZ_MANAGER (user_data); + + g_signal_emit (self, signals[BDADDR_ADDED], 0, + nm_bluez_device_get_address (device), + nm_bluez_device_get_uuids (device)); +} + +static void +device_removed (NMBluezAdapter *adapter, NMBluezDevice *device, gpointer user_data) +{ + NMBluezManager *self = NM_BLUEZ_MANAGER (user_data); + + g_signal_emit (self, signals[BDADDR_REMOVED], 0, + nm_bluez_device_get_address (device)); +} + +static void +adapter_initialized (NMBluezAdapter *adapter, gboolean success, gpointer user_data) +{ + NMBluezManager *self = NM_BLUEZ_MANAGER (user_data); + NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE (self); + + if (success) { + GSList *devices, *iter; + + devices = nm_bluez_adapter_get_devices (adapter); + for (iter = devices; iter; iter = g_slist_next (iter)) { + NMBluezDevice *device = NM_BLUEZ_DEVICE (iter->data); + + g_signal_emit (self, signals[BDADDR_ADDED], 0, + nm_bluez_device_get_address (device), + nm_bluez_device_get_uuids (device)); + } + g_slist_free (devices); + + g_signal_connect (adapter, "device-added", G_CALLBACK (device_added), self); + g_signal_connect (adapter, "device-removed", G_CALLBACK (device_removed), self); + } else { + g_object_unref (priv->adapter); + priv->adapter = NULL; + } +} + +static void +adapter_removed (DBusGProxy *proxy, const char *path, NMBluezManager *self) +{ + NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE (self); + + if (priv->adapter && !strcmp (path, nm_bluez_adapter_get_path (priv->adapter))) { + if (nm_bluez_adapter_get_initialized (priv->adapter)) { + GSList *devices, *iter; + + devices = nm_bluez_adapter_get_devices (priv->adapter); + for (iter = devices; iter; iter = g_slist_next (iter)) { + NMBluezDevice *device = NM_BLUEZ_DEVICE (iter->data); + + g_signal_emit (self, signals[BDADDR_REMOVED], 0, + nm_bluez_device_get_address (device)); + } + g_slist_free (devices); + } + + g_object_unref (priv->adapter); + priv->adapter = NULL; + } +} + +static void +default_adapter_changed (DBusGProxy *proxy, const char *path, NMBluezManager *self) +{ + NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE (self); + const char *cur_path = NULL; + + if (priv->adapter) + cur_path = nm_bluez_adapter_get_path (priv->adapter); + + if (cur_path) { + if (!path || strcmp (path, cur_path)) { + /* Default adapter changed */ + adapter_removed (priv->proxy, cur_path, self); + } else { + /* This adapter is already the default */ + return; + } + } + + /* Add the new default adapter */ + if (path) { + priv->adapter = nm_bluez_adapter_new (path); + g_signal_connect (priv->adapter, "initialized", G_CALLBACK (adapter_initialized), self); + } +} + +static void +default_adapter_cb (DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data) +{ + NMBluezManager *self = NM_BLUEZ_MANAGER (user_data); + NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE (self); + const char *default_adapter = NULL; + GError *err = NULL; + + if (!dbus_g_proxy_end_call (proxy, call, &err, + DBUS_TYPE_G_OBJECT_PATH, &default_adapter, + G_TYPE_INVALID)) { + nm_warning ("bluez error getting default adapter: %s", + err && err->message ? err->message : "(unknown)"); + g_error_free (err); + return; + } + + default_adapter_changed (priv->proxy, default_adapter, self); +} + +static void +query_default_adapter (NMBluezManager *self) +{ + NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE (self); + DBusGProxyCall *call; + + call = dbus_g_proxy_begin_call (priv->proxy, "DefaultAdapter", + default_adapter_cb, + self, + NULL, G_TYPE_INVALID); + if (!call) + nm_warning ("failed to request default Bluetooth adapter."); +} + +static void +bluez_connect (NMBluezManager *self) +{ + NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE (self); + DBusGConnection *connection; + + g_return_if_fail (priv->proxy == NULL); + + connection = nm_dbus_manager_get_connection (priv->dbus_mgr); + if (!connection) + return; + + priv->proxy = dbus_g_proxy_new_for_name (connection, + BLUEZ_SERVICE, + BLUEZ_MANAGER_PATH, + BLUEZ_MANAGER_INTERFACE); + + dbus_g_proxy_add_signal (priv->proxy, "AdapterRemoved", + DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID); + dbus_g_proxy_connect_signal (priv->proxy, "AdapterRemoved", + G_CALLBACK (adapter_removed), self, NULL); + + dbus_g_proxy_add_signal (priv->proxy, "DefaultAdapterChanged", + DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID); + dbus_g_proxy_connect_signal (priv->proxy, "DefaultAdapterChanged", + G_CALLBACK (default_adapter_changed), self, NULL); + + query_default_adapter (self); +} + +static void +remove_all_devices (NMBluezManager *self, gboolean do_signal) +{ + /* FIXME: do something */ +} + +static void +name_owner_changed_cb (NMDBusManager *dbus_mgr, + const char *name, + const char *old_owner, + const char *new_owner, + gpointer user_data) +{ + NMBluezManager *self = NM_BLUEZ_MANAGER (user_data); + gboolean old_owner_good = (old_owner && strlen (old_owner)); + gboolean new_owner_good = (new_owner && strlen (new_owner)); + + /* Can't handle the signal if its not from the supplicant service */ + if (strcmp (BLUEZ_SERVICE, name)) + return; + + if (old_owner_good && !new_owner_good) + remove_all_devices (self, TRUE); +} + +static void +bluez_cleanup (NMBluezManager *self, gboolean do_signal) +{ + NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE (self); + + if (priv->proxy) { + g_object_unref (priv->proxy); + priv->proxy = NULL; + } + + remove_all_devices (self, do_signal); +} + +static void +dbus_connection_changed_cb (NMDBusManager *dbus_mgr, + DBusGConnection *connection, + gpointer user_data) +{ + NMBluezManager *self = NM_BLUEZ_MANAGER (user_data); + + if (!connection) + bluez_cleanup (self, TRUE); + else + bluez_connect (self); +} + + +NMBluezManager * +nm_bluez_manager_new (void) +{ + return NM_BLUEZ_MANAGER (g_object_new (NM_TYPE_BLUEZ_MANAGER, NULL)); +} + +NMBluezManager * +nm_bluez_manager_get (void) +{ + static NMBluezManager *singleton = NULL; + + if (!singleton) + singleton = nm_bluez_manager_new (); + else + g_object_ref (singleton); + + g_assert (singleton); + return singleton; +} + +static void +nm_bluez_manager_init (NMBluezManager *self) +{ + NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE (self); + + priv->dbus_mgr = nm_dbus_manager_get (); + g_assert (priv->dbus_mgr); + + g_signal_connect (priv->dbus_mgr, + "name-owner-changed", + G_CALLBACK (name_owner_changed_cb), + self); + + g_signal_connect (priv->dbus_mgr, + "dbus-connection-changed", + G_CALLBACK (dbus_connection_changed_cb), + self); + + bluez_connect (self); +} + +static void +finalize (GObject *object) +{ + NMBluezManager *self = NM_BLUEZ_MANAGER (object); + + bluez_cleanup (self, FALSE); + + G_OBJECT_CLASS (nm_bluez_manager_parent_class)->finalize (object); +} + +static void +nm_bluez_manager_class_init (NMBluezManagerClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (klass, sizeof (NMBluezManagerPrivate)); + + /* virtual methods */ + object_class->finalize = finalize; + + /* Signals */ + signals[BDADDR_ADDED] = + g_signal_new ("bdaddr-added", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMBluezManagerClass, bdaddr_added), + NULL, NULL, + _nm_marshal_VOID__STRING_UINT, + G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_UINT); + + signals[BDADDR_REMOVED] = + g_signal_new ("bdaddr-removed", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMBluezManagerClass, bdaddr_removed), + NULL, NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, 1, G_TYPE_STRING); +} + diff --git a/src/bluez-manager/nm-bluez-manager.h b/src/bluez-manager/nm-bluez-manager.h new file mode 100644 index 000000000..d7513fa30 --- /dev/null +++ b/src/bluez-manager/nm-bluez-manager.h @@ -0,0 +1,57 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager -- Network link manager + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2007 - 2008 Novell, Inc. + * Copyright (C) 2007 - 2009 Red Hat, Inc. + */ + +#ifndef NM_BLUEZ_MANAGER_H +#define NM_BLUEZ_MANAGER_H + +#include +#include + +G_BEGIN_DECLS + +#define NM_TYPE_BLUEZ_MANAGER (nm_bluez_manager_get_type ()) +#define NM_BLUEZ_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_BLUEZ_MANAGER, NMBluezManager)) +#define NM_BLUEZ_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_BLUEZ_MANAGER, NMBluezManagerClass)) +#define NM_IS_BLUEZ_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_BLUEZ_MANAGER)) +#define NM_IS_BLUEZ_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_BLUEZ_MANAGER)) +#define NM_BLUEZ_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_BLUEZ_MANAGER, NMBluezManagerClass)) + +typedef struct { + GObject parent; +} NMBluezManager; + +typedef struct { + GObjectClass parent; + + /* Virtual functions */ + void (*bdaddr_added) (NMBluezManager *manager, const char *bdaddr, guint uuids); + + void (*bdaddr_removed) (NMBluezManager *manager, const char *bdaddr); +} NMBluezManagerClass; + +GType nm_bluez_manager_get_type (void); + +NMBluezManager *nm_bluez_manager_new (void); +NMBluezManager *nm_bluez_manager_get (void); +void nm_bluez_manager_query_devices (NMBluezManager *manager); + +#endif /* NM_BLUEZ_MANAGER_H */ + diff --git a/src/nm-manager.c b/src/nm-manager.c index 8382944da..7c5b08ee6 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -43,6 +43,8 @@ #include "nm-dbus-glib-types.h" #include "nm-hal-manager.h" #include "nm-hostname-provider.h" +#include "nm-bluez-manager.h" +#include "nm-bluez-common.h" #define NM_AUTOIP_DBUS_SERVICE "org.freedesktop.nm_avahi_autoipd" #define NM_AUTOIP_DBUS_IFACE "org.freedesktop.nm_avahi_autoipd" @@ -96,6 +98,15 @@ static void hal_manager_rfkill_changed_cb (NMHalManager *hal_mgr, static void hal_manager_hal_reappeared_cb (NMHalManager *hal_mgr, gpointer user_data); +static void bluez_manager_bdaddr_added_cb (NMBluezManager *bluez_mgr, + const char *bdaddr, + guint type, + gpointer user_data); + +static void bluez_manager_bdaddr_removed_cb (NMBluezManager *bluez_mgr, + const char *bdaddr, + gpointer user_data); + static void system_settings_properties_changed_cb (DBusGProxy *proxy, GHashTable *properties, gpointer user_data); @@ -123,6 +134,7 @@ typedef struct { NMDBusManager *dbus_mgr; NMHalManager *hal_mgr; + NMBluezManager *bluez_mgr; GHashTable *user_connections; DBusGProxy *user_proxy; @@ -579,6 +591,7 @@ dispose (GObject *object) g_object_unref (priv->dbus_mgr); g_object_unref (priv->hal_mgr); + g_object_unref (priv->bluez_mgr); G_OBJECT_CLASS (nm_manager_parent_class)->dispose (object); } @@ -1522,6 +1535,9 @@ sync_devices (NMManager *self) /* Ask HAL for new devices */ nm_hal_manager_query_devices (priv->hal_mgr); + + /* Ask for new bluetooth devices */ + nm_bluez_manager_query_devices (priv->bluez_mgr); } static gboolean @@ -1584,6 +1600,18 @@ nm_manager_get (void) G_CALLBACK (hal_manager_hal_reappeared_cb), singleton); + priv->bluez_mgr = nm_bluez_manager_get (); + + g_signal_connect (priv->bluez_mgr, + "bdaddr-added", + G_CALLBACK (bluez_manager_bdaddr_added_cb), + singleton); + + g_signal_connect (priv->bluez_mgr, + "bdaddr-removed", + G_CALLBACK (bluez_manager_bdaddr_removed_cb), + singleton); + return singleton; } @@ -1768,6 +1796,31 @@ add_device (NMManager *self, NMDevice *device) g_signal_emit (self, signals[DEVICE_ADDED], 0, device); } +static void +bluez_manager_bdaddr_added_cb (NMBluezManager *bluez_mgr, + const char *bdaddr, + guint32 uuids, + gpointer user_data) +{ + gboolean has_dun = (uuids & NM_BLUEZ_TYPE_DUN); + gboolean has_pan = (uuids & NM_BLUEZ_TYPE_PANU); + + g_message ("%s: BT device %s added (%s%s%s)", + __func__, + bdaddr, + has_dun ? "DUN" : "", + has_dun ? " " : "", + has_pan ? "PANU" : ""); +} + +static void +bluez_manager_bdaddr_removed_cb (NMBluezManager *bluez_mgr, + const char *bdaddr, + gpointer user_data) +{ + g_message ("%s: BT device %s removed", __func__, bdaddr); +} + static void hal_manager_udi_added_cb (NMHalManager *hal_mgr, const char *udi,