Upgrade bluez5_37 :Merge the code from private
[platform/upstream/bluez.git] / tools / gatt-service.c
1 /*
2  *
3  *  BlueZ - Bluetooth protocol stack for Linux
4  *
5  *  Copyright (C) 2014  Instituto Nokia de Tecnologia - INdT
6  *
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software
20  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21  *
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <errno.h>
29 #include <stdio.h>
30 #include <stdbool.h>
31 #include <unistd.h>
32 #include <sys/signalfd.h>
33
34 #include <glib.h>
35 #include <dbus/dbus.h>
36
37 #include "gdbus/gdbus.h"
38
39 #include "src/error.h"
40
41 #define GATT_MGR_IFACE                  "org.bluez.GattManager1"
42 #define GATT_SERVICE_IFACE              "org.bluez.GattService1"
43 #define GATT_CHR_IFACE                  "org.bluez.GattCharacteristic1"
44 #define GATT_DESCRIPTOR_IFACE           "org.bluez.GattDescriptor1"
45
46 /* Immediate Alert Service UUID */
47 #define IAS_UUID                        "00001802-0000-1000-8000-00805f9b34fb"
48 #define ALERT_LEVEL_CHR_UUID            "00002a06-0000-1000-8000-00805f9b34fb"
49
50 /* Random UUID for testing purpose */
51 #define READ_WRITE_DESCRIPTOR_UUID      "8260c653-1a54-426b-9e36-e84c238bc669"
52
53 static GMainLoop *main_loop;
54 static GSList *services;
55 static DBusConnection *connection;
56
57 struct characteristic {
58         char *uuid;
59         char *path;
60         uint8_t *value;
61         int vlen;
62         const char **props;
63 };
64
65 struct descriptor {
66         char *uuid;
67         char *path;
68         uint8_t *value;
69         int vlen;
70 };
71
72 /*
73  * Alert Level support Write Without Response only. Supported
74  * properties are defined at doc/gatt-api.txt. See "Flags"
75  * property of the GattCharacteristic1.
76  */
77 static const char *ias_alert_level_props[] = { "write-without-response", NULL };
78
79 static gboolean desc_get_uuid(const GDBusPropertyTable *property,
80                                         DBusMessageIter *iter, void *user_data)
81 {
82         struct descriptor *desc = user_data;
83
84         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &desc->uuid);
85
86         return TRUE;
87 }
88
89 static gboolean desc_get_value(const GDBusPropertyTable *property,
90                                         DBusMessageIter *iter, void *user_data)
91 {
92         struct descriptor *desc = user_data;
93         DBusMessageIter array;
94
95         printf("Descriptor(%s): Get(\"Value\")\n", desc->uuid);
96
97         dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
98                                         DBUS_TYPE_BYTE_AS_STRING, &array);
99
100         if (desc->vlen && desc->value)
101                 dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE,
102                                                 &desc->value, desc->vlen);
103
104         dbus_message_iter_close_container(iter, &array);
105
106         return TRUE;
107 }
108
109 static void desc_set_value(const GDBusPropertyTable *property,
110                                 DBusMessageIter *iter,
111                                 GDBusPendingPropertySet id, void *user_data)
112 {
113         struct descriptor *desc = user_data;
114         DBusMessageIter array;
115         const uint8_t *value;
116         int vlen;
117
118         printf("Descriptor(%s): Set(\"Value\", ...)\n", desc->uuid);
119
120         dbus_message_iter_recurse(iter, &array);
121         dbus_message_iter_get_fixed_array(&array, &value, &vlen);
122
123         g_free(desc->value);
124         desc->value = g_memdup(value, vlen);
125         desc->vlen = vlen;
126
127         g_dbus_pending_property_success(id);
128
129         g_dbus_emit_property_changed(connection, desc->path,
130                                         GATT_DESCRIPTOR_IFACE, "Value");
131
132 }
133
134 static const GDBusPropertyTable desc_properties[] = {
135         { "UUID",               "s",    desc_get_uuid },
136         { "Value",              "ay",   desc_get_value, desc_set_value, NULL },
137         { }
138 };
139
140 static gboolean chr_get_uuid(const GDBusPropertyTable *property,
141                                         DBusMessageIter *iter, void *user_data)
142 {
143         struct characteristic *chr = user_data;
144
145         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &chr->uuid);
146
147         return TRUE;
148 }
149
150 static gboolean chr_get_value(const GDBusPropertyTable *property,
151                                         DBusMessageIter *iter, void *user_data)
152 {
153         struct characteristic *chr = user_data;
154         DBusMessageIter array;
155
156         printf("Characteristic(%s): Get(\"Value\")\n", chr->uuid);
157
158         dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
159                                         DBUS_TYPE_BYTE_AS_STRING, &array);
160
161         dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE,
162                                                 &chr->value, chr->vlen);
163
164         dbus_message_iter_close_container(iter, &array);
165
166         return TRUE;
167 }
168
169 static gboolean chr_get_props(const GDBusPropertyTable *property,
170                                         DBusMessageIter *iter, void *data)
171 {
172         struct characteristic *chr = data;
173         DBusMessageIter array;
174         int i;
175
176         dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
177                                         DBUS_TYPE_STRING_AS_STRING, &array);
178
179         for (i = 0; chr->props[i]; i++)
180                 dbus_message_iter_append_basic(&array,
181                                         DBUS_TYPE_STRING, &chr->props[i]);
182
183         dbus_message_iter_close_container(iter, &array);
184
185         return TRUE;
186 }
187
188 static void chr_set_value(const GDBusPropertyTable *property,
189                                 DBusMessageIter *iter,
190                                 GDBusPendingPropertySet id, void *user_data)
191 {
192         struct characteristic *chr = user_data;
193         DBusMessageIter array;
194         uint8_t *value;
195         int len;
196
197         printf("Characteristic(%s): Set('Value', ...)\n", chr->uuid);
198
199         if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY) {
200                 printf("Invalid value for Set('Value'...)\n");
201                 g_dbus_pending_property_error(id,
202                                         ERROR_INTERFACE ".InvalidArguments",
203                                         "Invalid arguments in method call");
204                 return;
205         }
206
207         dbus_message_iter_recurse(iter, &array);
208         dbus_message_iter_get_fixed_array(&array, &value, &len);
209
210         g_free(chr->value);
211         chr->value = g_memdup(value, len);
212         chr->vlen = len;
213
214         g_dbus_pending_property_success(id);
215         g_dbus_emit_property_changed(connection, chr->path,
216                                                 GATT_CHR_IFACE, "Value");
217 }
218
219 static const GDBusPropertyTable chr_properties[] = {
220         { "UUID",       "s",    chr_get_uuid },
221         { "Value", "ay", chr_get_value, chr_set_value, NULL },
222         { "Flags", "as", chr_get_props, NULL, NULL },
223         { }
224 };
225
226 static gboolean service_get_uuid(const GDBusPropertyTable *property,
227                                         DBusMessageIter *iter, void *user_data)
228 {
229         const char *uuid = user_data;
230
231         printf("Get UUID: %s\n", uuid);
232
233         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &uuid);
234
235         return TRUE;
236 }
237
238 static gboolean service_get_includes(const GDBusPropertyTable *property,
239                                         DBusMessageIter *iter, void *user_data)
240 {
241         const char *uuid = user_data;
242
243         printf("Get Includes: %s\n", uuid);
244
245         return TRUE;
246 }
247
248 static gboolean service_exist_includes(const GDBusPropertyTable *property,
249                                                         void *user_data)
250 {
251         const char *uuid = user_data;
252
253         printf("Exist Includes: %s\n", uuid);
254
255         return FALSE;
256 }
257
258 static const GDBusPropertyTable service_properties[] = {
259         { "UUID", "s", service_get_uuid },
260         { "Includes", "ao", service_get_includes, NULL,
261                                         service_exist_includes },
262         { }
263 };
264
265 static void chr_iface_destroy(gpointer user_data)
266 {
267         struct characteristic *chr = user_data;
268
269         g_free(chr->uuid);
270         g_free(chr->value);
271         g_free(chr->path);
272         g_free(chr);
273 }
274
275 static void desc_iface_destroy(gpointer user_data)
276 {
277         struct descriptor *desc = user_data;
278
279         g_free(desc->uuid);
280         g_free(desc->value);
281         g_free(desc->path);
282         g_free(desc);
283 }
284
285 static gboolean register_characteristic(const char *chr_uuid,
286                                                 const uint8_t *value, int vlen,
287                                                 const char **props,
288                                                 const char *desc_uuid,
289                                                 const char *service_path)
290 {
291         struct characteristic *chr;
292         struct descriptor *desc;
293         static int id = 1;
294
295         chr = g_new0(struct characteristic, 1);
296         chr->uuid = g_strdup(chr_uuid);
297         chr->value = g_memdup(value, vlen);
298         chr->vlen = vlen;
299         chr->props = props;
300         chr->path = g_strdup_printf("%s/characteristic%d", service_path, id++);
301
302         if (!g_dbus_register_interface(connection, chr->path, GATT_CHR_IFACE,
303                                         NULL, NULL, chr_properties,
304                                         chr, chr_iface_destroy)) {
305                 printf("Couldn't register characteristic interface\n");
306                 chr_iface_destroy(chr);
307                 return FALSE;
308         }
309
310         if (!desc_uuid)
311                 return TRUE;
312
313         desc = g_new0(struct descriptor, 1);
314         desc->uuid = g_strdup(desc_uuid);
315         desc->path = g_strdup_printf("%s/descriptor%d", chr->path, id++);
316
317         if (!g_dbus_register_interface(connection, desc->path,
318                                         GATT_DESCRIPTOR_IFACE,
319                                         NULL, NULL, desc_properties,
320                                         desc, desc_iface_destroy)) {
321                 printf("Couldn't register descriptor interface\n");
322                 g_dbus_unregister_interface(connection, chr->path,
323                                                         GATT_CHR_IFACE);
324
325                 desc_iface_destroy(desc);
326                 return FALSE;
327         }
328
329         return TRUE;
330 }
331
332 static char *register_service(const char *uuid)
333 {
334         static int id = 1;
335         char *path;
336
337         path = g_strdup_printf("/service%d", id++);
338         if (!g_dbus_register_interface(connection, path, GATT_SERVICE_IFACE,
339                                 NULL, NULL, service_properties,
340                                 g_strdup(uuid), g_free)) {
341                 printf("Couldn't register service interface\n");
342                 g_free(path);
343                 return NULL;
344         }
345
346         return path;
347 }
348
349 static void create_services()
350 {
351         char *service_path;
352         uint8_t level = 0;
353
354         service_path = register_service(IAS_UUID);
355         if (!service_path)
356                 return;
357
358         /* Add Alert Level Characteristic to Immediate Alert Service */
359         if (!register_characteristic(ALERT_LEVEL_CHR_UUID,
360                                                 &level, sizeof(level),
361                                                 ias_alert_level_props,
362                                                 READ_WRITE_DESCRIPTOR_UUID,
363                                                 service_path)) {
364                 printf("Couldn't register Alert Level characteristic (IAS)\n");
365                 g_dbus_unregister_interface(connection, service_path,
366                                                         GATT_SERVICE_IFACE);
367                 g_free(service_path);
368                 return;
369         }
370
371         services = g_slist_prepend(services, service_path);
372         printf("Registered service: %s\n", service_path);
373 }
374
375 static void register_external_service_reply(DBusPendingCall *call,
376                                                         void *user_data)
377 {
378         DBusMessage *reply = dbus_pending_call_steal_reply(call);
379         DBusError derr;
380
381         dbus_error_init(&derr);
382         dbus_set_error_from_message(&derr, reply);
383
384         if (dbus_error_is_set(&derr))
385                 printf("RegisterService: %s\n", derr.message);
386         else
387                 printf("RegisterService: OK\n");
388
389         dbus_message_unref(reply);
390         dbus_error_free(&derr);
391 }
392
393 static void register_external_service(gpointer a, gpointer b)
394 {
395         DBusConnection *conn = b;
396         const char *path = a;
397         DBusMessage *msg;
398         DBusPendingCall *call;
399         DBusMessageIter iter, dict;
400
401         msg = dbus_message_new_method_call("org.bluez", "/org/bluez",
402                                         GATT_MGR_IFACE, "RegisterService");
403         if (!msg) {
404                 printf("Couldn't allocate D-Bus message\n");
405                 return;
406         }
407
408         dbus_message_iter_init_append(msg, &iter);
409
410         dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, &path);
411
412         dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &dict);
413
414         /* TODO: Add options dictionary */
415
416         dbus_message_iter_close_container(&iter, &dict);
417
418         if (!g_dbus_send_message_with_reply(conn, msg, &call, -1)) {
419                 dbus_message_unref(msg);
420                 return;
421         }
422
423         dbus_pending_call_set_notify(call, register_external_service_reply,
424                                                                 NULL, NULL);
425
426         dbus_pending_call_unref(call);
427 }
428
429 static void connect_handler(DBusConnection *conn, void *user_data)
430 {
431         g_slist_foreach(services, register_external_service, conn);
432 }
433
434 static gboolean signal_handler(GIOChannel *channel, GIOCondition cond,
435                                                         gpointer user_data)
436 {
437         static bool __terminated = false;
438         struct signalfd_siginfo si;
439         ssize_t result;
440         int fd;
441
442         if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP))
443                 return FALSE;
444
445         fd = g_io_channel_unix_get_fd(channel);
446
447         result = read(fd, &si, sizeof(si));
448         if (result != sizeof(si))
449                 return FALSE;
450
451         switch (si.ssi_signo) {
452         case SIGINT:
453         case SIGTERM:
454                 if (!__terminated) {
455                         printf("Terminating\n");
456                         g_main_loop_quit(main_loop);
457                 }
458
459                 __terminated = true;
460                 break;
461         }
462
463         return TRUE;
464 }
465
466 static guint setup_signalfd(void)
467 {
468         GIOChannel *channel;
469         guint source;
470         sigset_t mask;
471         int fd;
472
473         sigemptyset(&mask);
474         sigaddset(&mask, SIGINT);
475         sigaddset(&mask, SIGTERM);
476
477         if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0) {
478                 perror("Failed to set signal mask");
479                 return 0;
480         }
481
482         fd = signalfd(-1, &mask, 0);
483         if (fd < 0) {
484                 perror("Failed to create signal descriptor");
485                 return 0;
486         }
487
488         channel = g_io_channel_unix_new(fd);
489
490         g_io_channel_set_close_on_unref(channel, TRUE);
491         g_io_channel_set_encoding(channel, NULL, NULL);
492         g_io_channel_set_buffered(channel, FALSE);
493
494         source = g_io_add_watch(channel,
495                                 G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
496                                 signal_handler, NULL);
497
498         g_io_channel_unref(channel);
499
500         return source;
501 }
502
503 int main(int argc, char *argv[])
504 {
505         GDBusClient *client;
506         guint signal;
507
508         signal = setup_signalfd();
509         if (signal == 0)
510                 return -errno;
511
512         connection = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, NULL);
513
514         main_loop = g_main_loop_new(NULL, FALSE);
515
516         g_dbus_attach_object_manager(connection);
517
518         printf("gatt-service unique name: %s\n",
519                                 dbus_bus_get_unique_name(connection));
520
521         create_services();
522
523         client = g_dbus_client_new(connection, "org.bluez", "/org/bluez");
524
525         g_dbus_client_set_connect_watch(client, connect_handler, NULL);
526
527         g_main_loop_run(main_loop);
528
529         g_dbus_client_unref(client);
530
531         g_source_remove(signal);
532
533         g_slist_free_full(services, g_free);
534         dbus_connection_unref(connection);
535
536         return 0;
537 }