PageRenderTime 59ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/src/manager.c

https://github.com/heinervdm/bluez
C | 431 lines | 305 code | 101 blank | 25 comment | 34 complexity | 397322d6fc55f1af1dcd1ede48217a91 MD5 | raw file
Possible License(s): GPL-2.0
  1. /*
  2. *
  3. * BlueZ - Bluetooth protocol stack for Linux
  4. *
  5. * Copyright (C) 2006-2010 Nokia Corporation
  6. * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
  7. *
  8. *
  9. * This program is free software; you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License as published by
  11. * the Free Software Foundation; either version 2 of the License, or
  12. * (at your option) any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  22. *
  23. */
  24. #ifdef HAVE_CONFIG_H
  25. #include <config.h>
  26. #endif
  27. #include <stdlib.h>
  28. #include <stdio.h>
  29. #include <errno.h>
  30. #include <unistd.h>
  31. #include <sys/ioctl.h>
  32. #include <sys/socket.h>
  33. #include <bluetooth/bluetooth.h>
  34. #include <glib.h>
  35. #include <dbus/dbus.h>
  36. #include <gdbus.h>
  37. #include "hcid.h"
  38. #include "dbus-common.h"
  39. #include "log.h"
  40. #include "adapter.h"
  41. #include "error.h"
  42. #include "manager.h"
  43. static char base_path[50] = "/org/bluez";
  44. static DBusConnection *connection = NULL;
  45. static int default_adapter_id = -1;
  46. static GSList *adapters = NULL;
  47. const char *manager_get_base_path(void)
  48. {
  49. return base_path;
  50. }
  51. static DBusMessage *default_adapter(DBusConnection *conn,
  52. DBusMessage *msg, void *data)
  53. {
  54. DBusMessage *reply;
  55. struct btd_adapter *adapter;
  56. const gchar *path;
  57. adapter = manager_find_adapter_by_id(default_adapter_id);
  58. if (!adapter)
  59. return btd_error_no_such_adapter(msg);
  60. reply = dbus_message_new_method_return(msg);
  61. if (!reply)
  62. return NULL;
  63. path = adapter_get_path(adapter);
  64. dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
  65. DBUS_TYPE_INVALID);
  66. return reply;
  67. }
  68. static DBusMessage *find_adapter(DBusConnection *conn,
  69. DBusMessage *msg, void *data)
  70. {
  71. DBusMessage *reply;
  72. struct btd_adapter *adapter;
  73. const char *pattern;
  74. int dev_id;
  75. const gchar *path;
  76. if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &pattern,
  77. DBUS_TYPE_INVALID))
  78. return NULL;
  79. /* hci_devid() would make sense to use here, except it is
  80. * restricted to devices which are up */
  81. if (!strcmp(pattern, "any") || !strcmp(pattern, "00:00:00:00:00:00")) {
  82. path = adapter_any_get_path();
  83. if (path != NULL)
  84. goto done;
  85. return btd_error_no_such_adapter(msg);
  86. } else if (!strncmp(pattern, "hci", 3) && strlen(pattern) >= 4) {
  87. dev_id = atoi(pattern + 3);
  88. adapter = manager_find_adapter_by_id(dev_id);
  89. } else {
  90. bdaddr_t bdaddr;
  91. str2ba(pattern, &bdaddr);
  92. adapter = manager_find_adapter(&bdaddr);
  93. }
  94. if (!adapter)
  95. return btd_error_no_such_adapter(msg);
  96. path = adapter_get_path(adapter);
  97. done:
  98. reply = dbus_message_new_method_return(msg);
  99. if (!reply)
  100. return NULL;
  101. dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
  102. DBUS_TYPE_INVALID);
  103. return reply;
  104. }
  105. static DBusMessage *list_adapters(DBusConnection *conn,
  106. DBusMessage *msg, void *data)
  107. {
  108. DBusMessageIter iter;
  109. DBusMessageIter array_iter;
  110. DBusMessage *reply;
  111. GSList *l;
  112. reply = dbus_message_new_method_return(msg);
  113. if (!reply)
  114. return NULL;
  115. dbus_message_iter_init_append(reply, &iter);
  116. dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
  117. DBUS_TYPE_OBJECT_PATH_AS_STRING, &array_iter);
  118. for (l = adapters; l; l = l->next) {
  119. struct btd_adapter *adapter = l->data;
  120. const gchar *path = adapter_get_path(adapter);
  121. dbus_message_iter_append_basic(&array_iter,
  122. DBUS_TYPE_OBJECT_PATH, &path);
  123. }
  124. dbus_message_iter_close_container(&iter, &array_iter);
  125. return reply;
  126. }
  127. static DBusMessage *get_properties(DBusConnection *conn,
  128. DBusMessage *msg, void *data)
  129. {
  130. DBusMessage *reply;
  131. DBusMessageIter iter;
  132. DBusMessageIter dict;
  133. GSList *list;
  134. char **array;
  135. int i;
  136. reply = dbus_message_new_method_return(msg);
  137. if (!reply)
  138. return NULL;
  139. dbus_message_iter_init_append(reply, &iter);
  140. dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
  141. DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
  142. DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
  143. DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
  144. array = g_new0(char *, g_slist_length(adapters) + 1);
  145. for (i = 0, list = adapters; list; list = list->next) {
  146. struct btd_adapter *adapter = list->data;
  147. array[i] = (char *) adapter_get_path(adapter);
  148. i++;
  149. }
  150. dict_append_array(&dict, "Adapters", DBUS_TYPE_OBJECT_PATH, &array, i);
  151. g_free(array);
  152. dbus_message_iter_close_container(&iter, &dict);
  153. return reply;
  154. }
  155. static GDBusMethodTable manager_methods[] = {
  156. { "GetProperties", "", "a{sv}",get_properties },
  157. { "DefaultAdapter", "", "o", default_adapter },
  158. { "FindAdapter", "s", "o", find_adapter },
  159. { "ListAdapters", "", "ao", list_adapters,
  160. G_DBUS_METHOD_FLAG_DEPRECATED},
  161. { }
  162. };
  163. static GDBusSignalTable manager_signals[] = {
  164. { "PropertyChanged", "sv" },
  165. { "AdapterAdded", "o" },
  166. { "AdapterRemoved", "o" },
  167. { "DefaultAdapterChanged", "o" },
  168. { }
  169. };
  170. dbus_bool_t manager_init(DBusConnection *conn, const char *path)
  171. {
  172. connection = conn;
  173. snprintf(base_path, sizeof(base_path), "/org/bluez/%d", getpid());
  174. return g_dbus_register_interface(conn, "/", MANAGER_INTERFACE,
  175. manager_methods, manager_signals,
  176. NULL, NULL, NULL);
  177. }
  178. static void manager_update_adapters(void)
  179. {
  180. GSList *list;
  181. char **array;
  182. int i;
  183. array = g_new0(char *, g_slist_length(adapters) + 1);
  184. for (i = 0, list = adapters; list; list = list->next) {
  185. struct btd_adapter *adapter = list->data;
  186. array[i] = (char *) adapter_get_path(adapter);
  187. i++;
  188. }
  189. emit_array_property_changed(connection, "/",
  190. MANAGER_INTERFACE, "Adapters",
  191. DBUS_TYPE_OBJECT_PATH, &array, i);
  192. g_free(array);
  193. }
  194. static void manager_set_default_adapter(int id)
  195. {
  196. struct btd_adapter *adapter;
  197. const gchar *path;
  198. default_adapter_id = id;
  199. adapter = manager_find_adapter_by_id(id);
  200. if (!adapter)
  201. return;
  202. path = adapter_get_path(adapter);
  203. g_dbus_emit_signal(connection, "/",
  204. MANAGER_INTERFACE,
  205. "DefaultAdapterChanged",
  206. DBUS_TYPE_OBJECT_PATH, &path,
  207. DBUS_TYPE_INVALID);
  208. }
  209. static void manager_remove_adapter(struct btd_adapter *adapter)
  210. {
  211. uint16_t dev_id = adapter_get_dev_id(adapter);
  212. const gchar *path = adapter_get_path(adapter);
  213. adapters = g_slist_remove(adapters, adapter);
  214. manager_update_adapters();
  215. if (default_adapter_id == dev_id || default_adapter_id < 0) {
  216. int new_default = hci_get_route(NULL);
  217. manager_set_default_adapter(new_default);
  218. }
  219. g_dbus_emit_signal(connection, "/",
  220. MANAGER_INTERFACE, "AdapterRemoved",
  221. DBUS_TYPE_OBJECT_PATH, &path,
  222. DBUS_TYPE_INVALID);
  223. adapter_remove(adapter);
  224. if (adapters == NULL)
  225. btd_start_exit_timer();
  226. }
  227. void manager_cleanup(DBusConnection *conn, const char *path)
  228. {
  229. g_slist_foreach(adapters, (GFunc) manager_remove_adapter, NULL);
  230. g_slist_free(adapters);
  231. g_dbus_unregister_interface(conn, "/", MANAGER_INTERFACE);
  232. }
  233. static gint adapter_id_cmp(gconstpointer a, gconstpointer b)
  234. {
  235. struct btd_adapter *adapter = (struct btd_adapter *) a;
  236. uint16_t id = GPOINTER_TO_UINT(b);
  237. uint16_t dev_id = adapter_get_dev_id(adapter);
  238. return dev_id == id ? 0 : -1;
  239. }
  240. static gint adapter_cmp(gconstpointer a, gconstpointer b)
  241. {
  242. struct btd_adapter *adapter = (struct btd_adapter *) a;
  243. const bdaddr_t *bdaddr = b;
  244. bdaddr_t src;
  245. adapter_get_address(adapter, &src);
  246. return bacmp(&src, bdaddr);
  247. }
  248. struct btd_adapter *manager_find_adapter(const bdaddr_t *sba)
  249. {
  250. GSList *match;
  251. match = g_slist_find_custom(adapters, sba, adapter_cmp);
  252. if (!match)
  253. return NULL;
  254. return match->data;
  255. }
  256. struct btd_adapter *manager_find_adapter_by_id(int id)
  257. {
  258. GSList *match;
  259. match = g_slist_find_custom(adapters, GINT_TO_POINTER(id),
  260. adapter_id_cmp);
  261. if (!match)
  262. return NULL;
  263. return match->data;
  264. }
  265. void manager_foreach_adapter(adapter_cb func, gpointer user_data)
  266. {
  267. g_slist_foreach(adapters, (GFunc) func, user_data);
  268. }
  269. GSList *manager_get_adapters(void)
  270. {
  271. return adapters;
  272. }
  273. void manager_add_adapter(const char *path)
  274. {
  275. g_dbus_emit_signal(connection, "/",
  276. MANAGER_INTERFACE, "AdapterAdded",
  277. DBUS_TYPE_OBJECT_PATH, &path,
  278. DBUS_TYPE_INVALID);
  279. manager_update_adapters();
  280. btd_stop_exit_timer();
  281. }
  282. struct btd_adapter *btd_manager_register_adapter(int id)
  283. {
  284. struct btd_adapter *adapter;
  285. const char *path;
  286. adapter = manager_find_adapter_by_id(id);
  287. if (adapter) {
  288. error("Unable to register adapter: hci%d already exist", id);
  289. return NULL;
  290. }
  291. adapter = adapter_create(connection, id);
  292. if (!adapter)
  293. return NULL;
  294. adapters = g_slist_append(adapters, adapter);
  295. if (!adapter_init(adapter)) {
  296. btd_adapter_unref(adapter);
  297. return NULL;
  298. }
  299. path = adapter_get_path(adapter);
  300. g_dbus_emit_signal(connection, "/",
  301. MANAGER_INTERFACE, "AdapterAdded",
  302. DBUS_TYPE_OBJECT_PATH, &path,
  303. DBUS_TYPE_INVALID);
  304. manager_update_adapters();
  305. btd_stop_exit_timer();
  306. if (default_adapter_id < 0)
  307. manager_set_default_adapter(id);
  308. DBG("Adapter %s registered", path);
  309. return btd_adapter_ref(adapter);
  310. }
  311. int btd_manager_unregister_adapter(int id)
  312. {
  313. struct btd_adapter *adapter;
  314. const gchar *path;
  315. adapter = manager_find_adapter_by_id(id);
  316. if (!adapter)
  317. return -1;
  318. path = adapter_get_path(adapter);
  319. info("Unregister path: %s", path);
  320. manager_remove_adapter(adapter);
  321. return 0;
  322. }
  323. void btd_manager_set_did(uint16_t vendor, uint16_t product, uint16_t version)
  324. {
  325. GSList *l;
  326. for (l = adapters; l != NULL; l = g_slist_next(l)) {
  327. struct btd_adapter *adapter = l->data;
  328. btd_adapter_set_did(adapter, vendor, product, version);
  329. }
  330. }