gatt-service.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. *
  4. * BlueZ - Bluetooth protocol stack for Linux
  5. *
  6. * Copyright (C) 2014 Instituto Nokia de Tecnologia - INdT
  7. *
  8. *
  9. */
  10. #ifdef HAVE_CONFIG_H
  11. #include <config.h>
  12. #endif
  13. #define _GNU_SOURCE
  14. #include <errno.h>
  15. #include <stdio.h>
  16. #include <stdbool.h>
  17. #include <unistd.h>
  18. #include <string.h>
  19. #include <sys/signalfd.h>
  20. #include <glib.h>
  21. #include <dbus/dbus.h>
  22. #include "gdbus/gdbus.h"
  23. #include "src/error.h"
  24. #define GATT_MGR_IFACE "org.bluez.GattManager1"
  25. #define GATT_SERVICE_IFACE "org.bluez.GattService1"
  26. #define GATT_CHR_IFACE "org.bluez.GattCharacteristic1"
  27. #define GATT_DESCRIPTOR_IFACE "org.bluez.GattDescriptor1"
  28. /* Immediate Alert Service UUID */
  29. #define IAS_UUID "00001802-0000-1000-8000-00805f9b34fb"
  30. #define ALERT_LEVEL_CHR_UUID "00002a06-0000-1000-8000-00805f9b34fb"
  31. #define IAS_UUID1 "A00B"
  32. #define IAS_UUID2 "A00C"
  33. #define IAS_UUID3 "A00D"
  34. #define ALERT_LEVEL_CHR_UUID1 "00002b06-0000-1000-8000-00805f9b34fb"
  35. #define ALERT_LEVEL_CHR_UUID2 "00002c07-0000-1000-8000-00805f9b34fb"
  36. /* Random UUID for testing purpose */
  37. /* Random UUID for testing purpose */
  38. #define READ_WRITE_DESCRIPTOR_UUID "8260c653-1a54-426b-9e36-e84c238bc669"
  39. #define READ_WRITE_DESCRIPTOR_UUID1 "0260c653-1a54-426b-9e36-e84c238bc669"
  40. #define READ_WRITE_DESCRIPTOR_UUID2 "FFFF"
  41. static GMainLoop *main_loop;
  42. static GSList *services;
  43. static DBusConnection *connection;
  44. struct characteristic {
  45. char *service;
  46. char *uuid;
  47. char *path;
  48. uint8_t *value;
  49. int vlen;
  50. const char **props;
  51. };
  52. struct descriptor {
  53. struct characteristic *chr;
  54. char *uuid;
  55. char *path;
  56. uint8_t *value;
  57. int vlen;
  58. const char **props;
  59. };
  60. /*
  61. * Alert Level support Write Without Response only. Supported
  62. * properties are defined at doc/gatt-api.txt. See "Flags"
  63. * property of the GattCharacteristic1.
  64. */
  65. static const char *ias_alert_level_props[] = { "write-without-response", NULL };
  66. static const char *desc_props[] = { "read", "write", NULL };
  67. static gboolean desc_get_uuid(const GDBusPropertyTable *property,
  68. DBusMessageIter *iter, void *user_data)
  69. {
  70. struct descriptor *desc = user_data;
  71. dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &desc->uuid);
  72. return TRUE;
  73. }
  74. static gboolean desc_get_characteristic(const GDBusPropertyTable *property,
  75. DBusMessageIter *iter, void *user_data)
  76. {
  77. struct descriptor *desc = user_data;
  78. dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
  79. &desc->chr->path);
  80. return TRUE;
  81. }
  82. static bool desc_read(struct descriptor *desc, DBusMessageIter *iter)
  83. {
  84. DBusMessageIter array;
  85. dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
  86. DBUS_TYPE_BYTE_AS_STRING, &array);
  87. if (desc->vlen && desc->value)
  88. dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE,
  89. &desc->value, desc->vlen);
  90. dbus_message_iter_close_container(iter, &array);
  91. return true;
  92. }
  93. static gboolean desc_get_value(const GDBusPropertyTable *property,
  94. DBusMessageIter *iter, void *user_data)
  95. {
  96. struct descriptor *desc = user_data;
  97. printf("Descriptor(%s): Get(\"Value\")\n", desc->uuid);
  98. return desc_read(desc, iter);
  99. }
  100. static void desc_write(struct descriptor *desc, const uint8_t *value, int len)
  101. {
  102. g_free(desc->value);
  103. desc->value = g_memdup(value, len);
  104. desc->vlen = len;
  105. g_dbus_emit_property_changed(connection, desc->path,
  106. GATT_DESCRIPTOR_IFACE, "Value");
  107. }
  108. static int parse_value(DBusMessageIter *iter, const uint8_t **value, int *len)
  109. {
  110. DBusMessageIter array;
  111. if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
  112. return -EINVAL;
  113. dbus_message_iter_recurse(iter, &array);
  114. dbus_message_iter_get_fixed_array(&array, value, len);
  115. return 0;
  116. }
  117. static void desc_set_value(const GDBusPropertyTable *property,
  118. DBusMessageIter *iter,
  119. GDBusPendingPropertySet id, void *user_data)
  120. {
  121. struct descriptor *desc = user_data;
  122. const uint8_t *value;
  123. int len;
  124. printf("Descriptor(%s): Set(\"Value\", ...)\n", desc->uuid);
  125. if (parse_value(iter, &value, &len)) {
  126. printf("Invalid value for Set('Value'...)\n");
  127. g_dbus_pending_property_error(id,
  128. ERROR_INTERFACE ".InvalidArguments",
  129. "Invalid arguments in method call");
  130. return;
  131. }
  132. desc_write(desc, value, len);
  133. g_dbus_pending_property_success(id);
  134. }
  135. static gboolean desc_get_props(const GDBusPropertyTable *property,
  136. DBusMessageIter *iter, void *data)
  137. {
  138. struct descriptor *desc = data;
  139. DBusMessageIter array;
  140. int i;
  141. dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
  142. DBUS_TYPE_STRING_AS_STRING, &array);
  143. for (i = 0; desc->props[i]; i++)
  144. dbus_message_iter_append_basic(&array,
  145. DBUS_TYPE_STRING, &desc->props[i]);
  146. dbus_message_iter_close_container(iter, &array);
  147. return TRUE;
  148. }
  149. static const GDBusPropertyTable desc_properties[] = {
  150. { "UUID", "s", desc_get_uuid },
  151. { "Characteristic", "o", desc_get_characteristic },
  152. { "Value", "ay", desc_get_value, desc_set_value, NULL },
  153. { "Flags", "as", desc_get_props, NULL, NULL },
  154. { }
  155. };
  156. static gboolean chr_get_uuid(const GDBusPropertyTable *property,
  157. DBusMessageIter *iter, void *user_data)
  158. {
  159. struct characteristic *chr = user_data;
  160. dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &chr->uuid);
  161. return TRUE;
  162. }
  163. static gboolean chr_get_service(const GDBusPropertyTable *property,
  164. DBusMessageIter *iter, void *user_data)
  165. {
  166. struct characteristic *chr = user_data;
  167. dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
  168. &chr->service);
  169. return TRUE;
  170. }
  171. static bool chr_read(struct characteristic *chr, DBusMessageIter *iter)
  172. {
  173. DBusMessageIter array;
  174. dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
  175. DBUS_TYPE_BYTE_AS_STRING, &array);
  176. dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE,
  177. &chr->value, chr->vlen);
  178. dbus_message_iter_close_container(iter, &array);
  179. return true;
  180. }
  181. static gboolean chr_get_value(const GDBusPropertyTable *property,
  182. DBusMessageIter *iter, void *user_data)
  183. {
  184. struct characteristic *chr = user_data;
  185. printf("Characteristic(%s): Get(\"Value\")\n", chr->uuid);
  186. return chr_read(chr, iter);
  187. }
  188. static gboolean chr_get_props(const GDBusPropertyTable *property,
  189. DBusMessageIter *iter, void *data)
  190. {
  191. struct characteristic *chr = data;
  192. DBusMessageIter array;
  193. int i;
  194. dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
  195. DBUS_TYPE_STRING_AS_STRING, &array);
  196. for (i = 0; chr->props[i]; i++)
  197. dbus_message_iter_append_basic(&array,
  198. DBUS_TYPE_STRING, &chr->props[i]);
  199. dbus_message_iter_close_container(iter, &array);
  200. return TRUE;
  201. }
  202. static void chr_write(struct characteristic *chr, const uint8_t *value, int len)
  203. {
  204. g_free(chr->value);
  205. chr->value = g_memdup(value, len);
  206. chr->vlen = len;
  207. g_dbus_emit_property_changed(connection, chr->path, GATT_CHR_IFACE,
  208. "Value");
  209. }
  210. static void chr_set_value(const GDBusPropertyTable *property,
  211. DBusMessageIter *iter,
  212. GDBusPendingPropertySet id, void *user_data)
  213. {
  214. struct characteristic *chr = user_data;
  215. const uint8_t *value;
  216. int len;
  217. printf("Characteristic(%s): Set('Value', ...)\n", chr->uuid);
  218. if (!parse_value(iter, &value, &len)) {
  219. printf("Invalid value for Set('Value'...)\n");
  220. g_dbus_pending_property_error(id,
  221. ERROR_INTERFACE ".InvalidArguments",
  222. "Invalid arguments in method call");
  223. return;
  224. }
  225. chr_write(chr, value, len);
  226. g_dbus_pending_property_success(id);
  227. }
  228. static const GDBusPropertyTable chr_properties[] = {
  229. { "UUID", "s", chr_get_uuid },
  230. { "Service", "o", chr_get_service },
  231. { "Value", "ay", chr_get_value, chr_set_value, NULL },
  232. { "Flags", "as", chr_get_props, NULL, NULL },
  233. { }
  234. };
  235. static gboolean service_get_primary(const GDBusPropertyTable *property,
  236. DBusMessageIter *iter, void *user_data)
  237. {
  238. dbus_bool_t primary = TRUE;
  239. printf("Get Primary: %s\n", primary ? "True" : "False");
  240. dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &primary);
  241. return TRUE;
  242. }
  243. static gboolean service_get_uuid(const GDBusPropertyTable *property,
  244. DBusMessageIter *iter, void *user_data)
  245. {
  246. const char *uuid = user_data;
  247. printf("Get UUID: %s\n", uuid);
  248. dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &uuid);
  249. return TRUE;
  250. }
  251. static gboolean service_get_includes(const GDBusPropertyTable *property,
  252. DBusMessageIter *iter, void *user_data)
  253. {
  254. const char *uuid = user_data;
  255. char service_path[100] = {0,};
  256. DBusMessageIter array;
  257. char *p = NULL;
  258. snprintf(service_path, 100, "/service3");
  259. printf("Get Includes: %s\n", uuid);
  260. p = service_path;
  261. printf("Includes path: %s\n", p);
  262. dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
  263. DBUS_TYPE_OBJECT_PATH_AS_STRING, &array);
  264. dbus_message_iter_append_basic(&array, DBUS_TYPE_OBJECT_PATH,
  265. &p);
  266. snprintf(service_path, 100, "/service2");
  267. p = service_path;
  268. printf("Get Includes: %s\n", p);
  269. dbus_message_iter_append_basic(&array, DBUS_TYPE_OBJECT_PATH,
  270. &p);
  271. dbus_message_iter_close_container(iter, &array);
  272. return TRUE;
  273. }
  274. static gboolean service_exist_includes(const GDBusPropertyTable *property,
  275. void *user_data)
  276. {
  277. const char *uuid = user_data;
  278. printf("Exist Includes: %s\n", uuid);
  279. if (strncmp(uuid, "00001802", 8) == 0)
  280. return TRUE;
  281. return FALSE;
  282. }
  283. static const GDBusPropertyTable service_properties[] = {
  284. { "Primary", "b", service_get_primary },
  285. { "UUID", "s", service_get_uuid },
  286. { "Includes", "ao", service_get_includes, NULL,
  287. service_exist_includes },
  288. { }
  289. };
  290. static void chr_iface_destroy(gpointer user_data)
  291. {
  292. struct characteristic *chr = user_data;
  293. g_free(chr->uuid);
  294. g_free(chr->service);
  295. g_free(chr->value);
  296. g_free(chr->path);
  297. g_free(chr);
  298. }
  299. static void desc_iface_destroy(gpointer user_data)
  300. {
  301. struct descriptor *desc = user_data;
  302. g_free(desc->uuid);
  303. g_free(desc->value);
  304. g_free(desc->path);
  305. g_free(desc);
  306. }
  307. static int parse_options(DBusMessageIter *iter, const char **device)
  308. {
  309. DBusMessageIter dict;
  310. if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
  311. return -EINVAL;
  312. dbus_message_iter_recurse(iter, &dict);
  313. while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
  314. const char *key;
  315. DBusMessageIter value, entry;
  316. int var;
  317. dbus_message_iter_recurse(&dict, &entry);
  318. dbus_message_iter_get_basic(&entry, &key);
  319. dbus_message_iter_next(&entry);
  320. dbus_message_iter_recurse(&entry, &value);
  321. var = dbus_message_iter_get_arg_type(&value);
  322. if (strcasecmp(key, "device") == 0) {
  323. if (var != DBUS_TYPE_OBJECT_PATH)
  324. return -EINVAL;
  325. dbus_message_iter_get_basic(&value, device);
  326. printf("Device: %s\n", *device);
  327. }
  328. dbus_message_iter_next(&dict);
  329. }
  330. return 0;
  331. }
  332. static DBusMessage *chr_read_value(DBusConnection *conn, DBusMessage *msg,
  333. void *user_data)
  334. {
  335. struct characteristic *chr = user_data;
  336. DBusMessage *reply;
  337. DBusMessageIter iter;
  338. const char *device;
  339. if (!dbus_message_iter_init(msg, &iter))
  340. return g_dbus_create_error(msg, DBUS_ERROR_INVALID_ARGS,
  341. "Invalid arguments");
  342. if (parse_options(&iter, &device))
  343. return g_dbus_create_error(msg, DBUS_ERROR_INVALID_ARGS,
  344. "Invalid arguments");
  345. reply = dbus_message_new_method_return(msg);
  346. if (!reply)
  347. return g_dbus_create_error(msg, DBUS_ERROR_NO_MEMORY,
  348. "No Memory");
  349. dbus_message_iter_init_append(reply, &iter);
  350. chr_read(chr, &iter);
  351. return reply;
  352. }
  353. static DBusMessage *chr_write_value(DBusConnection *conn, DBusMessage *msg,
  354. void *user_data)
  355. {
  356. struct characteristic *chr = user_data;
  357. DBusMessageIter iter;
  358. const uint8_t *value;
  359. int len;
  360. const char *device;
  361. dbus_message_iter_init(msg, &iter);
  362. if (parse_value(&iter, &value, &len))
  363. return g_dbus_create_error(msg, DBUS_ERROR_INVALID_ARGS,
  364. "Invalid arguments");
  365. if (parse_options(&iter, &device))
  366. return g_dbus_create_error(msg, DBUS_ERROR_INVALID_ARGS,
  367. "Invalid arguments");
  368. chr_write(chr, value, len);
  369. return dbus_message_new_method_return(msg);
  370. }
  371. static DBusMessage *chr_start_notify(DBusConnection *conn, DBusMessage *msg,
  372. void *user_data)
  373. {
  374. return g_dbus_create_error(msg, DBUS_ERROR_NOT_SUPPORTED,
  375. "Not Supported");
  376. }
  377. static DBusMessage *chr_stop_notify(DBusConnection *conn, DBusMessage *msg,
  378. void *user_data)
  379. {
  380. return g_dbus_create_error(msg, DBUS_ERROR_NOT_SUPPORTED,
  381. "Not Supported");
  382. }
  383. static const GDBusMethodTable chr_methods[] = {
  384. { GDBUS_ASYNC_METHOD("ReadValue", GDBUS_ARGS({ "options", "a{sv}" }),
  385. GDBUS_ARGS({ "value", "ay" }),
  386. chr_read_value) },
  387. { GDBUS_ASYNC_METHOD("WriteValue", GDBUS_ARGS({ "value", "ay" },
  388. { "options", "a{sv}" }),
  389. NULL, chr_write_value) },
  390. { GDBUS_ASYNC_METHOD("StartNotify", NULL, NULL, chr_start_notify) },
  391. { GDBUS_METHOD("StopNotify", NULL, NULL, chr_stop_notify) },
  392. { }
  393. };
  394. static DBusMessage *desc_read_value(DBusConnection *conn, DBusMessage *msg,
  395. void *user_data)
  396. {
  397. struct descriptor *desc = user_data;
  398. DBusMessage *reply;
  399. DBusMessageIter iter;
  400. const char *device;
  401. if (!dbus_message_iter_init(msg, &iter))
  402. return g_dbus_create_error(msg, DBUS_ERROR_INVALID_ARGS,
  403. "Invalid arguments");
  404. if (parse_options(&iter, &device))
  405. return g_dbus_create_error(msg, DBUS_ERROR_INVALID_ARGS,
  406. "Invalid arguments");
  407. reply = dbus_message_new_method_return(msg);
  408. if (!reply)
  409. return g_dbus_create_error(msg, DBUS_ERROR_NO_MEMORY,
  410. "No Memory");
  411. dbus_message_iter_init_append(reply, &iter);
  412. desc_read(desc, &iter);
  413. return reply;
  414. }
  415. static DBusMessage *desc_write_value(DBusConnection *conn, DBusMessage *msg,
  416. void *user_data)
  417. {
  418. struct descriptor *desc = user_data;
  419. DBusMessageIter iter;
  420. const char *device;
  421. const uint8_t *value;
  422. int len;
  423. if (!dbus_message_iter_init(msg, &iter))
  424. return g_dbus_create_error(msg, DBUS_ERROR_INVALID_ARGS,
  425. "Invalid arguments");
  426. if (parse_value(&iter, &value, &len))
  427. return g_dbus_create_error(msg, DBUS_ERROR_INVALID_ARGS,
  428. "Invalid arguments");
  429. if (parse_options(&iter, &device))
  430. return g_dbus_create_error(msg, DBUS_ERROR_INVALID_ARGS,
  431. "Invalid arguments");
  432. desc_write(desc, value, len);
  433. return dbus_message_new_method_return(msg);
  434. }
  435. static const GDBusMethodTable desc_methods[] = {
  436. { GDBUS_ASYNC_METHOD("ReadValue", GDBUS_ARGS({ "options", "a{sv}" }),
  437. GDBUS_ARGS({ "value", "ay" }),
  438. desc_read_value) },
  439. { GDBUS_ASYNC_METHOD("WriteValue", GDBUS_ARGS({ "value", "ay" },
  440. { "options", "a{sv}" }),
  441. NULL, desc_write_value) },
  442. { }
  443. };
  444. static gboolean register_characteristic(const char *chr_uuid,
  445. const uint8_t *value, int vlen,
  446. const char **props,
  447. const char *desc_uuid,
  448. const char **desc_props,
  449. const char *service_path)
  450. {
  451. struct characteristic *chr;
  452. struct descriptor *desc;
  453. static int id = 1;
  454. chr = g_new0(struct characteristic, 1);
  455. chr->uuid = g_strdup(chr_uuid);
  456. chr->value = g_memdup(value, vlen);
  457. chr->vlen = vlen;
  458. chr->props = props;
  459. chr->service = g_strdup(service_path);
  460. chr->path = g_strdup_printf("%s/characteristic%d", service_path, id++);
  461. if (!g_dbus_register_interface(connection, chr->path, GATT_CHR_IFACE,
  462. chr_methods, NULL, chr_properties,
  463. chr, chr_iface_destroy)) {
  464. printf("Couldn't register characteristic interface\n");
  465. chr_iface_destroy(chr);
  466. return FALSE;
  467. }
  468. if (!desc_uuid)
  469. return TRUE;
  470. desc = g_new0(struct descriptor, 1);
  471. desc->uuid = g_strdup(desc_uuid);
  472. desc->chr = chr;
  473. desc->props = desc_props;
  474. desc->path = g_strdup_printf("%s/descriptor%d", chr->path, id++);
  475. if (!g_dbus_register_interface(connection, desc->path,
  476. GATT_DESCRIPTOR_IFACE,
  477. desc_methods, NULL, desc_properties,
  478. desc, desc_iface_destroy)) {
  479. printf("Couldn't register descriptor interface\n");
  480. g_dbus_unregister_interface(connection, chr->path,
  481. GATT_CHR_IFACE);
  482. desc_iface_destroy(desc);
  483. return FALSE;
  484. }
  485. return TRUE;
  486. }
  487. static char *register_service(const char *uuid)
  488. {
  489. static int id = 1;
  490. char *path;
  491. path = g_strdup_printf("/service%d", id++);
  492. if (!g_dbus_register_interface(connection, path, GATT_SERVICE_IFACE,
  493. NULL, NULL, service_properties,
  494. g_strdup(uuid), g_free)) {
  495. printf("Couldn't register service interface\n");
  496. g_free(path);
  497. return NULL;
  498. }
  499. return path;
  500. }
  501. static void create_services_one(void)
  502. {
  503. char *service_path;
  504. uint8_t level = 0;
  505. service_path = register_service(IAS_UUID);
  506. if (!service_path)
  507. return;
  508. /* Add Alert Level Characteristic to Immediate Alert Service */
  509. if (!register_characteristic(ALERT_LEVEL_CHR_UUID,
  510. &level, sizeof(level),
  511. ias_alert_level_props,
  512. READ_WRITE_DESCRIPTOR_UUID,
  513. desc_props,
  514. service_path)) {
  515. printf("Couldn't register Alert Level characteristic (IAS)\n");
  516. g_dbus_unregister_interface(connection, service_path,
  517. GATT_SERVICE_IFACE);
  518. g_free(service_path);
  519. return;
  520. }
  521. services = g_slist_prepend(services, service_path);
  522. printf("Registered service: %s\n", service_path);
  523. }
  524. static void create_services_two(void)
  525. {
  526. char *service_path;
  527. uint8_t level = 0;
  528. service_path = register_service(IAS_UUID2);
  529. if (!service_path)
  530. return;
  531. if (!register_characteristic(ALERT_LEVEL_CHR_UUID2,
  532. &level, sizeof(level),
  533. ias_alert_level_props,
  534. READ_WRITE_DESCRIPTOR_UUID2,
  535. desc_props,
  536. service_path)) {
  537. printf("Couldn't register Alert Level characteristic (IAS)\n");
  538. g_dbus_unregister_interface(connection, service_path,
  539. GATT_SERVICE_IFACE);
  540. g_free(service_path);
  541. return;
  542. }
  543. services = g_slist_prepend(services, service_path);
  544. printf("Registered service: %s\n", service_path);
  545. }
  546. static void create_services_three(void)
  547. {
  548. char *service_path;
  549. uint8_t level = 0;
  550. service_path = register_service(IAS_UUID3);
  551. if (!service_path)
  552. return;
  553. if (!register_characteristic(ALERT_LEVEL_CHR_UUID1,
  554. &level, sizeof(level),
  555. ias_alert_level_props,
  556. READ_WRITE_DESCRIPTOR_UUID1,
  557. desc_props,
  558. service_path)) {
  559. printf("Couldn't register Alert Level characteristic (IAS)\n");
  560. g_dbus_unregister_interface(connection, service_path,
  561. GATT_SERVICE_IFACE);
  562. g_free(service_path);
  563. return;
  564. }
  565. services = g_slist_prepend(services, service_path);
  566. printf("Registered service: %s\n", service_path);
  567. }
  568. static void register_app_reply(DBusMessage *reply, void *user_data)
  569. {
  570. DBusError derr;
  571. dbus_error_init(&derr);
  572. dbus_set_error_from_message(&derr, reply);
  573. if (dbus_error_is_set(&derr))
  574. printf("RegisterApplication: %s\n", derr.message);
  575. else
  576. printf("RegisterApplication: OK\n");
  577. dbus_error_free(&derr);
  578. }
  579. static void register_app_setup(DBusMessageIter *iter, void *user_data)
  580. {
  581. const char *path = "/";
  582. DBusMessageIter dict;
  583. dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
  584. dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "{sv}", &dict);
  585. /* TODO: Add options dictionary */
  586. dbus_message_iter_close_container(iter, &dict);
  587. }
  588. static void register_app(GDBusProxy *proxy)
  589. {
  590. if (!g_dbus_proxy_method_call(proxy, "RegisterApplication",
  591. register_app_setup, register_app_reply,
  592. NULL, NULL)) {
  593. printf("Unable to call RegisterApplication\n");
  594. return;
  595. }
  596. }
  597. static void proxy_added_cb(GDBusProxy *proxy, void *user_data)
  598. {
  599. const char *iface;
  600. iface = g_dbus_proxy_get_interface(proxy);
  601. if (g_strcmp0(iface, GATT_MGR_IFACE))
  602. return;
  603. register_app(proxy);
  604. }
  605. static gboolean signal_handler(GIOChannel *channel, GIOCondition cond,
  606. gpointer user_data)
  607. {
  608. static bool __terminated = false;
  609. struct signalfd_siginfo si;
  610. ssize_t result;
  611. int fd;
  612. if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP))
  613. return FALSE;
  614. fd = g_io_channel_unix_get_fd(channel);
  615. result = read(fd, &si, sizeof(si));
  616. if (result != sizeof(si))
  617. return FALSE;
  618. switch (si.ssi_signo) {
  619. case SIGINT:
  620. case SIGTERM:
  621. if (!__terminated) {
  622. printf("Terminating\n");
  623. g_main_loop_quit(main_loop);
  624. }
  625. __terminated = true;
  626. break;
  627. }
  628. return TRUE;
  629. }
  630. static guint setup_signalfd(void)
  631. {
  632. GIOChannel *channel;
  633. guint source;
  634. sigset_t mask;
  635. int fd;
  636. sigemptyset(&mask);
  637. sigaddset(&mask, SIGINT);
  638. sigaddset(&mask, SIGTERM);
  639. if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0) {
  640. perror("Failed to set signal mask");
  641. return 0;
  642. }
  643. fd = signalfd(-1, &mask, 0);
  644. if (fd < 0) {
  645. perror("Failed to create signal descriptor");
  646. return 0;
  647. }
  648. channel = g_io_channel_unix_new(fd);
  649. g_io_channel_set_close_on_unref(channel, TRUE);
  650. g_io_channel_set_encoding(channel, NULL, NULL);
  651. g_io_channel_set_buffered(channel, FALSE);
  652. source = g_io_add_watch(channel,
  653. G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
  654. signal_handler, NULL);
  655. g_io_channel_unref(channel);
  656. return source;
  657. }
  658. int main(int argc, char *argv[])
  659. {
  660. GDBusClient *client;
  661. guint signal;
  662. signal = setup_signalfd();
  663. if (signal == 0)
  664. return -errno;
  665. connection = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, NULL);
  666. main_loop = g_main_loop_new(NULL, FALSE);
  667. g_dbus_attach_object_manager(connection);
  668. printf("gatt-service unique name: %s\n",
  669. dbus_bus_get_unique_name(connection));
  670. create_services_one();
  671. create_services_two();
  672. create_services_three();
  673. client = g_dbus_client_new(connection, "org.bluez", "/");
  674. g_dbus_client_set_proxy_handlers(client, proxy_added_cb, NULL, NULL,
  675. NULL);
  676. g_main_loop_run(main_loop);
  677. g_dbus_client_unref(client);
  678. g_source_remove(signal);
  679. g_slist_free_full(services, g_free);
  680. dbus_connection_unref(connection);
  681. return 0;
  682. }