/src/manager.c
C | 431 lines | 305 code | 101 blank | 25 comment | 34 complexity | 397322d6fc55f1af1dcd1ede48217a91 MD5 | raw file
Possible License(s): GPL-2.0
- /*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2006-2010 Nokia Corporation
- * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
- *
- *
- * 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 St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
- #ifdef HAVE_CONFIG_H
- #include <config.h>
- #endif
- #include <stdlib.h>
- #include <stdio.h>
- #include <errno.h>
- #include <unistd.h>
- #include <sys/ioctl.h>
- #include <sys/socket.h>
- #include <bluetooth/bluetooth.h>
- #include <glib.h>
- #include <dbus/dbus.h>
- #include <gdbus.h>
- #include "hcid.h"
- #include "dbus-common.h"
- #include "log.h"
- #include "adapter.h"
- #include "error.h"
- #include "manager.h"
- static char base_path[50] = "/org/bluez";
- static DBusConnection *connection = NULL;
- static int default_adapter_id = -1;
- static GSList *adapters = NULL;
- const char *manager_get_base_path(void)
- {
- return base_path;
- }
- static DBusMessage *default_adapter(DBusConnection *conn,
- DBusMessage *msg, void *data)
- {
- DBusMessage *reply;
- struct btd_adapter *adapter;
- const gchar *path;
- adapter = manager_find_adapter_by_id(default_adapter_id);
- if (!adapter)
- return btd_error_no_such_adapter(msg);
- reply = dbus_message_new_method_return(msg);
- if (!reply)
- return NULL;
- path = adapter_get_path(adapter);
- dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
- DBUS_TYPE_INVALID);
- return reply;
- }
- static DBusMessage *find_adapter(DBusConnection *conn,
- DBusMessage *msg, void *data)
- {
- DBusMessage *reply;
- struct btd_adapter *adapter;
- const char *pattern;
- int dev_id;
- const gchar *path;
- if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &pattern,
- DBUS_TYPE_INVALID))
- return NULL;
- /* hci_devid() would make sense to use here, except it is
- * restricted to devices which are up */
- if (!strcmp(pattern, "any") || !strcmp(pattern, "00:00:00:00:00:00")) {
- path = adapter_any_get_path();
- if (path != NULL)
- goto done;
- return btd_error_no_such_adapter(msg);
- } else if (!strncmp(pattern, "hci", 3) && strlen(pattern) >= 4) {
- dev_id = atoi(pattern + 3);
- adapter = manager_find_adapter_by_id(dev_id);
- } else {
- bdaddr_t bdaddr;
- str2ba(pattern, &bdaddr);
- adapter = manager_find_adapter(&bdaddr);
- }
- if (!adapter)
- return btd_error_no_such_adapter(msg);
- path = adapter_get_path(adapter);
- done:
- reply = dbus_message_new_method_return(msg);
- if (!reply)
- return NULL;
- dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
- DBUS_TYPE_INVALID);
- return reply;
- }
- static DBusMessage *list_adapters(DBusConnection *conn,
- DBusMessage *msg, void *data)
- {
- DBusMessageIter iter;
- DBusMessageIter array_iter;
- DBusMessage *reply;
- GSList *l;
- reply = dbus_message_new_method_return(msg);
- if (!reply)
- return NULL;
- dbus_message_iter_init_append(reply, &iter);
- dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
- DBUS_TYPE_OBJECT_PATH_AS_STRING, &array_iter);
- for (l = adapters; l; l = l->next) {
- struct btd_adapter *adapter = l->data;
- const gchar *path = adapter_get_path(adapter);
- dbus_message_iter_append_basic(&array_iter,
- DBUS_TYPE_OBJECT_PATH, &path);
- }
- dbus_message_iter_close_container(&iter, &array_iter);
- return reply;
- }
- static DBusMessage *get_properties(DBusConnection *conn,
- DBusMessage *msg, void *data)
- {
- DBusMessage *reply;
- DBusMessageIter iter;
- DBusMessageIter dict;
- GSList *list;
- char **array;
- int i;
- reply = dbus_message_new_method_return(msg);
- if (!reply)
- return NULL;
- dbus_message_iter_init_append(reply, &iter);
- dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
- DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
- DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
- DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
- array = g_new0(char *, g_slist_length(adapters) + 1);
- for (i = 0, list = adapters; list; list = list->next) {
- struct btd_adapter *adapter = list->data;
- array[i] = (char *) adapter_get_path(adapter);
- i++;
- }
- dict_append_array(&dict, "Adapters", DBUS_TYPE_OBJECT_PATH, &array, i);
- g_free(array);
- dbus_message_iter_close_container(&iter, &dict);
- return reply;
- }
- static GDBusMethodTable manager_methods[] = {
- { "GetProperties", "", "a{sv}",get_properties },
- { "DefaultAdapter", "", "o", default_adapter },
- { "FindAdapter", "s", "o", find_adapter },
- { "ListAdapters", "", "ao", list_adapters,
- G_DBUS_METHOD_FLAG_DEPRECATED},
- { }
- };
- static GDBusSignalTable manager_signals[] = {
- { "PropertyChanged", "sv" },
- { "AdapterAdded", "o" },
- { "AdapterRemoved", "o" },
- { "DefaultAdapterChanged", "o" },
- { }
- };
- dbus_bool_t manager_init(DBusConnection *conn, const char *path)
- {
- connection = conn;
- snprintf(base_path, sizeof(base_path), "/org/bluez/%d", getpid());
- return g_dbus_register_interface(conn, "/", MANAGER_INTERFACE,
- manager_methods, manager_signals,
- NULL, NULL, NULL);
- }
- static void manager_update_adapters(void)
- {
- GSList *list;
- char **array;
- int i;
- array = g_new0(char *, g_slist_length(adapters) + 1);
- for (i = 0, list = adapters; list; list = list->next) {
- struct btd_adapter *adapter = list->data;
- array[i] = (char *) adapter_get_path(adapter);
- i++;
- }
- emit_array_property_changed(connection, "/",
- MANAGER_INTERFACE, "Adapters",
- DBUS_TYPE_OBJECT_PATH, &array, i);
- g_free(array);
- }
- static void manager_set_default_adapter(int id)
- {
- struct btd_adapter *adapter;
- const gchar *path;
- default_adapter_id = id;
- adapter = manager_find_adapter_by_id(id);
- if (!adapter)
- return;
- path = adapter_get_path(adapter);
- g_dbus_emit_signal(connection, "/",
- MANAGER_INTERFACE,
- "DefaultAdapterChanged",
- DBUS_TYPE_OBJECT_PATH, &path,
- DBUS_TYPE_INVALID);
- }
- static void manager_remove_adapter(struct btd_adapter *adapter)
- {
- uint16_t dev_id = adapter_get_dev_id(adapter);
- const gchar *path = adapter_get_path(adapter);
- adapters = g_slist_remove(adapters, adapter);
- manager_update_adapters();
- if (default_adapter_id == dev_id || default_adapter_id < 0) {
- int new_default = hci_get_route(NULL);
- manager_set_default_adapter(new_default);
- }
- g_dbus_emit_signal(connection, "/",
- MANAGER_INTERFACE, "AdapterRemoved",
- DBUS_TYPE_OBJECT_PATH, &path,
- DBUS_TYPE_INVALID);
- adapter_remove(adapter);
- if (adapters == NULL)
- btd_start_exit_timer();
- }
- void manager_cleanup(DBusConnection *conn, const char *path)
- {
- g_slist_foreach(adapters, (GFunc) manager_remove_adapter, NULL);
- g_slist_free(adapters);
- g_dbus_unregister_interface(conn, "/", MANAGER_INTERFACE);
- }
- static gint adapter_id_cmp(gconstpointer a, gconstpointer b)
- {
- struct btd_adapter *adapter = (struct btd_adapter *) a;
- uint16_t id = GPOINTER_TO_UINT(b);
- uint16_t dev_id = adapter_get_dev_id(adapter);
- return dev_id == id ? 0 : -1;
- }
- static gint adapter_cmp(gconstpointer a, gconstpointer b)
- {
- struct btd_adapter *adapter = (struct btd_adapter *) a;
- const bdaddr_t *bdaddr = b;
- bdaddr_t src;
- adapter_get_address(adapter, &src);
- return bacmp(&src, bdaddr);
- }
- struct btd_adapter *manager_find_adapter(const bdaddr_t *sba)
- {
- GSList *match;
- match = g_slist_find_custom(adapters, sba, adapter_cmp);
- if (!match)
- return NULL;
- return match->data;
- }
- struct btd_adapter *manager_find_adapter_by_id(int id)
- {
- GSList *match;
- match = g_slist_find_custom(adapters, GINT_TO_POINTER(id),
- adapter_id_cmp);
- if (!match)
- return NULL;
- return match->data;
- }
- void manager_foreach_adapter(adapter_cb func, gpointer user_data)
- {
- g_slist_foreach(adapters, (GFunc) func, user_data);
- }
- GSList *manager_get_adapters(void)
- {
- return adapters;
- }
- void manager_add_adapter(const char *path)
- {
- g_dbus_emit_signal(connection, "/",
- MANAGER_INTERFACE, "AdapterAdded",
- DBUS_TYPE_OBJECT_PATH, &path,
- DBUS_TYPE_INVALID);
- manager_update_adapters();
- btd_stop_exit_timer();
- }
- struct btd_adapter *btd_manager_register_adapter(int id)
- {
- struct btd_adapter *adapter;
- const char *path;
- adapter = manager_find_adapter_by_id(id);
- if (adapter) {
- error("Unable to register adapter: hci%d already exist", id);
- return NULL;
- }
- adapter = adapter_create(connection, id);
- if (!adapter)
- return NULL;
- adapters = g_slist_append(adapters, adapter);
- if (!adapter_init(adapter)) {
- btd_adapter_unref(adapter);
- return NULL;
- }
- path = adapter_get_path(adapter);
- g_dbus_emit_signal(connection, "/",
- MANAGER_INTERFACE, "AdapterAdded",
- DBUS_TYPE_OBJECT_PATH, &path,
- DBUS_TYPE_INVALID);
- manager_update_adapters();
- btd_stop_exit_timer();
- if (default_adapter_id < 0)
- manager_set_default_adapter(id);
- DBG("Adapter %s registered", path);
- return btd_adapter_ref(adapter);
- }
- int btd_manager_unregister_adapter(int id)
- {
- struct btd_adapter *adapter;
- const gchar *path;
- adapter = manager_find_adapter_by_id(id);
- if (!adapter)
- return -1;
- path = adapter_get_path(adapter);
- info("Unregister path: %s", path);
- manager_remove_adapter(adapter);
- return 0;
- }
- void btd_manager_set_did(uint16_t vendor, uint16_t product, uint16_t version)
- {
- GSList *l;
- for (l = adapters; l != NULL; l = g_slist_next(l)) {
- struct btd_adapter *adapter = l->data;
- btd_adapter_set_did(adapter, vendor, product, version);
- }
- }