2 * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
20 #include<glib/gprintf.h>
26 #include "bt-common.h"
27 #include "bt-internal-types.h"
29 #define NUMBER_OF_FLAGS 10
31 GDBusConnection *g_conn;
34 static gboolean new_service = FALSE;
35 static gboolean new_char = FALSE;
36 static int serv_id = 1;
37 static int register_pending_cnt = 0;
38 static bool is_server_started = false;
40 /* Introspection data for the service we are exporting */
41 static const gchar service_introspection_xml[] =
43 " <interface name='org.freedesktop.DBus.Properties'>"
44 " <property type='s' name='UUID' access='read'>"
46 " <property type='b' name='primary' access='read'>"
48 " <property type='o' name='Device' access='read'>"
50 " <property type='ao' name='Characteristics' access='read'>"
52 " <property type='s' name='Includes' access='read'>"
57 /* Introspection data for the characteristics we are exporting */
58 static const gchar characteristics_introspection_xml[] =
60 " <interface name='org.bluez.GattCharacteristic1'>"
61 " <method name='ReadValue'>"
62 " <arg type='s' name='address' direction='in'/>"
63 " <arg type='y' name='id' direction='in'/>"
64 " <arg type='q' name='offset' direction='in'/>"
65 " <arg type='ay' name='Value' direction='out'/>"
67 " <method name='WriteValue'>"
68 " <arg type='s' name='address' direction='in'/>"
69 " <arg type='y' name='id' direction='in'/>"
70 " <arg type='q' name='offset' direction='in'/>"
71 " <arg type='ay' name='value' direction='in'/>"
73 " <method name='StartNotify'>"
75 " <method name='StopNotify'>"
77 " <method name='IndicateConfirm'>"
78 " <arg type='s' name='address' direction='in'/>"
79 " <arg type='b' name='complete' direction='in'/>"
82 " <interface name='org.freedesktop.DBus.Properties'>"
83 " <property type='s' name='UUID' access='read'>"
85 " <property type='o' name='Service' access='read'>"
87 " <property type='ay' name='Value' access='readwrite'>"
89 " <property type='b' name='Notifying' access='read'>"
91 " <property type='as' name='Flags' access='read'>"
93 " <property type='s' name='Unicast' access='read'>"
95 " <property type='ao' name='Descriptors' access='read'>"
100 /* Introspection data for the descriptor we are exporting */
101 static const gchar descriptor_introspection_xml[] =
103 " <interface name='org.bluez.GattDescriptor1'>"
104 " <method name='ReadValue'>"
105 " <arg type='s' name='address' direction='in'/>"
106 " <arg type='y' name='id' direction='in'/>"
107 " <arg type='q' name='offset' direction='in'/>"
108 " <arg type='ay' name='Value' direction='out'/>"
110 " <method name='WriteValue'>"
111 " <arg type='s' name='address' direction='in'/>"
112 " <arg type='y' name='id' direction='in'/>"
113 " <arg type='q' name='offset' direction='in'/>"
114 " <arg type='ay' name='value' direction='in'/>"
117 " <interface name='org.freedesktop.DBus.Properties'>"
118 " <property type='s' name='UUID' access='read'>"
120 " <property type='o' name='Characteristic' access='read'>"
122 " <property type='ay' name='Value' access='read'>"
124 " <property type='as' name='Flags' access='read'>"
129 static const gchar manager_introspection_xml[] =
131 " <interface name='org.freedesktop.DBus.ObjectManager'>"
132 " <method name='GetManagedObjects'>"
133 " <arg type='a{oa{sa{sv}}}' name='object_paths_interfaces_and_properties' direction='out'/>"
138 struct gatt_service_info {
145 gboolean is_svc_registered;
146 gboolean is_svc_primary;
149 struct gatt_char_info {
154 gchar *char_flags[NUMBER_OF_FLAGS];
160 struct gatt_desc_info {
165 gchar *desc_flags[NUMBER_OF_FLAGS];
170 struct gatt_req_info {
175 GDBusMethodInvocation *context;
178 static GSList *gatt_services = NULL;
179 static GSList *gatt_requests = NULL;
180 static gchar *app_path = NULL;
182 #define BT_GATT_SERVICE_NAME "org.frwk.gatt_service"
183 #define BT_GATT_SERVICE_PATH "/org/frwk/gatt_service"
185 #define GATT_SERV_OBJECT_PATH "/service"
187 #define GATT_MNGR_INTERFACE "org.bluez.GattManager1"
188 #define GATT_SERV_INTERFACE "org.bluez.GattService1"
189 #define GATT_CHAR_INTERFACE "org.bluez.GattCharacteristic1"
190 #define GATT_DESC_INTERFACE "org.bluez.GattDescriptor1"
193 #define BT_HPS_OBJECT_PATH "/org/projectx/httpproxy"
194 #define BT_HPS_INTERFACE_NAME "org.projectx.httpproxy_service"
195 #define PROPERTIES_CHANGED "PropertiesChanged"
196 #define BT_HPS_PROPERTIES_INTERFACE "org.freedesktop.DBus.Properties"
199 static GDBusProxy *manager_gproxy = NULL;
201 static struct gatt_char_info *__bt_gatt_find_gatt_char_info(
202 const char *service_path, const char *char_path);
203 static struct gatt_desc_info *__bt_gatt_find_gatt_desc_info(
204 const char *serv_path, const char *char_path,
205 const char *desc_path);
207 static struct gatt_req_info *__bt_gatt_find_request_info(guint request_id);
210 static int __bt_send_event_to_hps(int event, GVariant *var)
212 GError *error = NULL;
213 GVariant *parameters;
214 GDBusMessage *msg = NULL;
218 retv_if(g_conn == NULL, BLUETOOTH_ERROR_INTERNAL);
220 if (event == BLUETOOTH_EVENT_GATT_SERVER_VALUE_CHANGED) {
221 GVariantBuilder *inner_builder;
222 GVariantBuilder *invalidated_builder;
224 BT_DBG("BLUETOOTH_EVENT_GATT_SERVER_VALUE_CHANGED");
225 inner_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
227 g_variant_builder_add(inner_builder, "{sv}", "WriteValue", var);
229 invalidated_builder = g_variant_builder_new(G_VARIANT_TYPE("as"));
231 parameters = g_variant_new("(a{sv}as)", inner_builder, invalidated_builder);
232 g_variant_builder_unref(invalidated_builder);
233 g_variant_builder_unref(inner_builder);
234 } else if (BLUETOOTH_EVENT_GATT_SERVER_READ_REQUESTED) {
235 GVariantBuilder *inner_builder;
236 GVariantBuilder *invalidated_builder;
238 BT_DBG("BLUETOOTH_EVENT_GATT_SERVER_VALUE_CHANGED");
239 inner_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
241 g_variant_builder_add(inner_builder, "{sv}", "ReadValue", var);
243 invalidated_builder = g_variant_builder_new(G_VARIANT_TYPE("as"));
245 parameters = g_variant_new("(a{sv}as)", inner_builder, invalidated_builder);
246 g_variant_builder_unref(invalidated_builder);
247 g_variant_builder_unref(inner_builder);
250 msg = g_dbus_message_new_signal(BT_HPS_OBJECT_PATH, BT_HPS_INTERFACE_NAME, PROPERTIES_CHANGED);
251 g_dbus_message_set_body(msg, parameters);
252 if (!g_dbus_connection_send_message(g_conn, msg, G_DBUS_SEND_MESSAGE_FLAGS_NONE, 0, NULL)) {
254 BT_ERR("D-Bus API failure: errCode[%x], \
256 error->code, error->message);
257 g_clear_error(&error);
259 return BLUETOOTH_ERROR_INTERNAL;
261 return BLUETOOTH_ERROR_NONE;
265 static void __bt_gatt_manager_method_call(GDBusConnection *connection,
267 const gchar *object_path,
268 const gchar *interface_name,
269 const gchar *method_name,
270 GVariant *parameters,
271 GDBusMethodInvocation *invocation,
278 if (g_strcmp0(method_name, "GetManagedObjects") == 0) {
279 BT_DBG("Getting values for service, chars and descriptors");
281 GVariantBuilder *builder;
282 GVariantBuilder *inner_builder1 = NULL;
283 GVariant *svc_char = NULL;
286 builder = g_variant_builder_new(
287 G_VARIANT_TYPE("a{oa{sa{sv}}}"));
289 /* Prepare inner builder for GattService1 interface */
291 len = g_slist_length(gatt_services);
293 for (i = 0; i <= len; i++) {
294 GVariantBuilder *svc_builder = NULL;
295 GVariantBuilder *inner_builder = NULL;
297 if (register_pending_cnt > 1) {
298 l1 = g_slist_nth(gatt_services, len - register_pending_cnt);
300 l1 = g_slist_last(gatt_services);
302 register_pending_cnt--;
304 struct gatt_service_info *serv_info = l1->data;
305 if (serv_info == NULL) {
306 BT_ERR("service info value is NULL");
307 g_dbus_method_invocation_return_value(invocation, NULL);
311 /* Prepare inner builder for GattService1 interface */
312 BT_DBG("Creating builder for service");
313 svc_builder = g_variant_builder_new(
314 G_VARIANT_TYPE("a{sa{sv}}"));
315 inner_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
317 g_variant_builder_add(inner_builder, "{sv}", "UUID",
318 g_variant_new_string(serv_info->service_uuid));
320 g_variant_builder_add(inner_builder, "{sv}", "Primary",
321 g_variant_new_boolean(serv_info->is_svc_primary));
324 inner_builder1 = g_variant_builder_new(G_VARIANT_TYPE("ao"));
325 BT_DBG("Adding Charatarisitcs list");
326 for (l4 = serv_info->char_data; l4 != NULL; l4 = l4->next) {
327 struct gatt_char_info *char_info = l4->data;
328 g_variant_builder_add(inner_builder1, "o",
329 char_info->char_path);
330 BT_DBG("%s", char_info->char_path);
333 svc_char = g_variant_new("ao", inner_builder1);
334 g_variant_builder_add(inner_builder, "{sv}", "Characteristics",
337 g_variant_builder_add(svc_builder, "{sa{sv}}",
341 g_variant_builder_add(builder, "{oa{sa{sv}}}",
342 serv_info->serv_path,
345 g_variant_builder_unref(inner_builder1);
347 /* Prepare inner builder for GattCharacteristic1 interface */
349 GSList *l2 = serv_info->char_data;
350 BT_DBG("Creating builder for characteristics \n");
353 BT_DBG("characteristic data is NULL");
355 for (l2 = serv_info->char_data; l2 != NULL; l2 = l2->next) {
357 GVariantBuilder *char_builder = NULL;
358 GVariantBuilder *inner_builder = NULL;
359 GVariantBuilder *builder1 = NULL;
360 GVariantBuilder *builder2 = NULL;
361 GVariantBuilder *builder3 = NULL;
362 GVariant *char_val = NULL;
363 GVariant *flags_val = NULL;
364 GVariant *char_desc = NULL;
365 char *unicast = NULL;
366 gboolean notify = FALSE;
369 char_builder = g_variant_builder_new(
372 inner_builder = g_variant_builder_new(
376 struct gatt_char_info *char_info = l2->data;
377 if (char_info == NULL) {
378 BT_ERR("char_info is NULL");
383 g_variant_builder_add(inner_builder, "{sv}", "UUID",
384 g_variant_new_string(char_info->char_uuid));
386 g_variant_builder_add(inner_builder, "{sv}", "Service",
387 g_variant_new("o", serv_info->serv_path));
389 builder1 = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
391 if (char_info->char_value != NULL) {
392 for (i = 0; i < char_info->value_length; i++) {
393 g_variant_builder_add(builder1, "y",
394 char_info->char_value[i]);
396 char_val = g_variant_new("ay", builder1);
397 g_variant_builder_add(inner_builder, "{sv}",
401 builder2 = g_variant_builder_new(G_VARIANT_TYPE("as"));
403 for (i = 0; i < char_info->flags_length; i++) {
404 g_variant_builder_add(builder2, "s",
405 char_info->char_flags[i]);
408 flags_val = g_variant_new("as", builder2);
409 g_variant_builder_add(inner_builder, "{sv}", "Flags",
413 g_variant_builder_add(inner_builder, "{sv}", "Notifying",
414 g_variant_new("b", notify));
417 unicast = g_strdup("00:00:00:00:00:00");
418 g_variant_builder_add(inner_builder, "{sv}", "Unicast",
419 g_variant_new("s", unicast));
422 builder3 = g_variant_builder_new(G_VARIANT_TYPE("ao"));
423 BT_DBG("Adding Descriptors list");
425 for (l4 = char_info->desc_data; l4 != NULL; l4 = l4->next) {
426 struct gatt_desc_info *desc_info = l4->data;
427 g_variant_builder_add(builder3, "o",
428 desc_info->desc_path);
429 BT_DBG("%s", desc_info->desc_path);
432 char_desc = g_variant_new("ao", builder3);
433 g_variant_builder_add(inner_builder, "{sv}", "Descriptors",
436 g_variant_builder_add(char_builder, "{sa{sv}}",
437 GATT_CHAR_INTERFACE , inner_builder);
438 g_variant_builder_add(builder, "{oa{sa{sv}}}",
439 char_info->char_path, char_builder);
441 /*Prepare inner builder for GattDescriptor1 interface*/
443 GSList *l3 = char_info->desc_data;
446 BT_DBG("descriptor data is NULL");
448 for (l3 = char_info->desc_data; l3 != NULL; l3 = l3->next) {
450 BT_DBG("Creating builder for descriptor \n");
452 GVariantBuilder *desc_builder = NULL;
453 GVariantBuilder *inner_builder = NULL;
454 GVariantBuilder *builder1 = NULL;
455 GVariantBuilder *builder2 = NULL;
456 GVariant *desc_val = NULL;
458 desc_builder = g_variant_builder_new(
461 inner_builder = g_variant_builder_new(
465 struct gatt_desc_info *desc_info = l3->data;
466 if (desc_info == NULL) {
467 BT_ERR("desc_info is NULL");
472 g_variant_builder_add(inner_builder,
474 g_variant_new_string(
475 desc_info->desc_uuid));
478 g_variant_builder_add(inner_builder, "{sv}",
481 char_info->char_path));
484 builder1 = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
486 if (desc_info->desc_value != NULL) {
487 for (i = 0; i < desc_info->value_length; i++) {
488 g_variant_builder_add(builder1, "y",
489 desc_info->desc_value[i]);
491 desc_val = g_variant_new("ay", builder1);
492 g_variant_builder_add(inner_builder, "{sv}",
497 builder2 = g_variant_builder_new(G_VARIANT_TYPE("as"));
499 for (i = 0; i < desc_info->flags_length; i++) {
500 g_variant_builder_add(builder2, "s",
501 desc_info->desc_flags[i]);
504 flags_val = g_variant_new("as", builder2);
505 g_variant_builder_add(inner_builder, "{sv}", "Flags",
508 g_variant_builder_add(desc_builder, "{sa{sv}}",
512 g_variant_builder_add(builder, "{oa{sa{sv}}}",
513 desc_info->desc_path,
516 /*unref descriptor builder pointers*/
517 g_variant_builder_unref(builder1);
518 g_variant_builder_unref(builder2);
519 g_variant_builder_unref(inner_builder);
520 g_variant_builder_unref(desc_builder);
525 /*unref char builder pointers*/
526 g_variant_builder_unref(builder1);
527 g_variant_builder_unref(builder2);
528 g_variant_builder_unref(builder3);
529 g_variant_builder_unref(inner_builder);
530 g_variant_builder_unref(char_builder);
533 /*unref service builder pointers*/
534 g_variant_builder_unref(inner_builder);
535 g_variant_builder_unref(svc_builder);
538 /* Return builder as method reply */
539 BT_DBG("Sending gatt service builder values to Bluez");
540 g_dbus_method_invocation_return_value(invocation,
547 static struct gatt_service_info *__bt_gatt_find_gatt_service_from_char(const char *char_path)
551 for (l1 = gatt_services; l1 != NULL; l1 = l1->next) {
552 struct gatt_service_info *serv_info = l1->data;
554 for (l2 = serv_info->char_data; l2 != NULL; l2 = l2->next) {
555 struct gatt_char_info *char_info = l2->data;
557 if (g_strcmp0(char_info->char_path, char_path)
562 BT_ERR("Gatt service not found");
566 static struct gatt_service_info *__bt_gatt_find_gatt_service_from_desc(const char *desc_path)
568 GSList *l1, *l2, *l3;
570 for (l1 = gatt_services; l1 != NULL; l1 = l1->next) {
571 struct gatt_service_info *serv_info = l1->data;
573 for (l2 = serv_info->char_data; l2 != NULL; l2 = l2->next) {
574 struct gatt_char_info *char_info = l2->data;
576 for (l3 = char_info->desc_data; l3 != NULL; l3 = l3->next) {
577 struct gatt_desc_info *desc_info = l3->data;
579 if (g_strcmp0(desc_info->desc_path, desc_path)
585 BT_ERR("Gatt service not found");
589 static void __bt_gatt_char_method_call(GDBusConnection *connection,
591 const gchar *object_path,
592 const gchar *interface_name,
593 const gchar *method_name,
594 GVariant *parameters,
595 GDBusMethodInvocation *invocation,
599 if (g_strcmp0(method_name, "ReadValue") == 0) {
603 bt_gatt_read_req_t read_req = {0, };
604 bt_user_info_t *user_info = NULL;
605 struct gatt_req_info *req_info = NULL;
606 struct gatt_service_info *svc_info = NULL;
610 g_variant_get(parameters, "(&syq)", &addr, &req_id, &offset);
612 BT_DBG("Application path = %s", object_path);
614 BT_DBG("Remote Device address number = %s", addr);
615 BT_DBG("Request id = %d, Offset = %d", req_id, offset);
617 BT_DBG("Sender = %s", sender);
619 read_req.att_handle = g_strdup(object_path);
620 read_req.address = g_strdup(addr);
621 read_req.req_id = req_id;
622 read_req.offset = offset;
623 svc_info = __bt_gatt_find_gatt_service_from_char(object_path);
624 if (svc_info != NULL) {
625 read_req.service_handle = g_strdup(svc_info->serv_path);
626 user_info = _bt_get_user_data(BT_COMMON);
628 GVariant *param = NULL;
631 /* Store requets information */
632 req_info = g_new0(struct gatt_req_info, 1);
633 req_info->attr_path = g_strdup(object_path);
634 req_info->svc_path = g_strdup(read_req.service_handle);
635 req_info->request_id = req_id;
636 req_info->offset = offset;
637 req_info->context = invocation;
638 gatt_requests = g_slist_append(gatt_requests, req_info);
640 if (user_info != NULL) {
642 BLUETOOTH_EVENT_GATT_SERVER_READ_REQUESTED,
643 BLUETOOTH_ERROR_NONE, &read_req,
644 user_info->cb, user_info->user_data);
647 param = g_variant_new("(sssyq)",
649 read_req.service_handle,
653 __bt_send_event_to_hps(BLUETOOTH_EVENT_GATT_SERVER_READ_REQUESTED, param);
657 if (read_req.att_handle)
658 g_free(read_req.att_handle);
659 if (read_req.address)
660 g_free(read_req.address);
661 if (read_req.service_handle)
662 g_free(read_req.service_handle);
664 } else if (g_strcmp0(method_name, "WriteValue") == 0) {
665 GVariant *var = NULL;
669 bt_gatt_value_change_t value_change = {0, };
670 bt_user_info_t *user_info = NULL;
672 struct gatt_service_info *svc_info = NULL;
673 struct gatt_req_info *req_info = NULL;
675 GVariant *param = NULL;
678 BT_DBG("WriteValue");
679 BT_DBG("Application path = %s", object_path);
680 BT_DBG("Sender = %s", sender);
682 g_variant_get(parameters, "(&syq@ay)", &addr, &req_id, &offset, &var);
684 value_change.att_handle = g_strdup(object_path);
685 value_change.address = g_strdup(addr);
686 svc_info = __bt_gatt_find_gatt_service_from_char(object_path);
687 if (svc_info == NULL) {
688 g_variant_unref(var);
689 g_dbus_method_invocation_return_value(invocation, NULL);
693 value_change.service_handle = g_strdup(svc_info->serv_path);
694 value_change.offset = offset;
695 value_change.req_id = req_id;
697 len = g_variant_get_size(var);
701 value_change.att_value = (guint8 *)malloc(len);
702 if (!value_change.att_value) {
703 BT_ERR("att_value is NULL");
704 g_variant_unref(var);
705 g_dbus_method_invocation_return_value(invocation, NULL);
709 data = (char *)g_variant_get_data(var);
710 memcpy(value_change.att_value, data, len);
713 value_change.val_len = len;
715 /* Store requets information */
716 req_info = g_new0(struct gatt_req_info, 1);
717 req_info->attr_path = g_strdup(object_path);
718 req_info->svc_path = g_strdup(value_change.service_handle);
719 req_info->request_id = req_id;
720 req_info->offset = offset;
721 req_info->context = invocation;
722 gatt_requests = g_slist_append(gatt_requests, req_info);
724 user_info = _bt_get_user_data(BT_COMMON);
725 if (user_info != NULL) {
727 BLUETOOTH_EVENT_GATT_SERVER_VALUE_CHANGED,
728 BLUETOOTH_ERROR_NONE, &value_change,
729 user_info->cb, user_info->user_data);
734 svc_path = g_strdup(svc_info->serv_path);
735 param = g_variant_new("(sssyq@ay)",
742 __bt_send_event_to_hps(BLUETOOTH_EVENT_GATT_SERVER_VALUE_CHANGED, param);
747 g_variant_unref(var);
749 } else if (g_strcmp0(method_name, "StartNotify") == 0) {
750 bt_user_info_t *user_info = NULL;
751 bt_gatt_char_notify_change_t notify_change = {0, };
752 BT_DBG("StartNotify");
753 user_info = _bt_get_user_data(BT_COMMON);
754 if (user_info != NULL) {
755 struct gatt_service_info *svc_info = NULL;
756 svc_info = __bt_gatt_find_gatt_service_from_char(object_path);
758 notify_change.service_handle = g_strdup(svc_info->serv_path);
759 notify_change.att_handle = g_strdup(object_path);
760 notify_change.att_notify = TRUE;
762 BLUETOOTH_EVENT_GATT_SERVER_NOTIFICATION_STATE_CHANGED,
763 BLUETOOTH_ERROR_NONE, ¬ify_change,
764 user_info->cb, user_info->user_data);
767 } else if (g_strcmp0(method_name, "StopNotify") == 0) {
768 bt_user_info_t *user_info = NULL;
769 bt_gatt_char_notify_change_t notify_change = {0, };
770 BT_DBG("StopNotify");
771 user_info = _bt_get_user_data(BT_COMMON);
772 if (user_info != NULL) {
773 struct gatt_service_info *svc_info = NULL;
774 svc_info = __bt_gatt_find_gatt_service_from_char(object_path);
776 notify_change.service_handle = g_strdup(svc_info->serv_path);
777 notify_change.att_handle = g_strdup(object_path);
778 notify_change.att_notify = FALSE;
780 BLUETOOTH_EVENT_GATT_SERVER_NOTIFICATION_STATE_CHANGED,
781 BLUETOOTH_ERROR_NONE, ¬ify_change,
782 user_info->cb, user_info->user_data);
785 } else if (g_strcmp0(method_name, "IndicateConfirm") == 0) {
787 bt_gatt_indicate_confirm_t confirm = {0, };
788 bt_user_info_t *user_info = NULL;
789 gboolean complete = 0;
790 struct gatt_service_info *svc_info = NULL;
792 BT_DBG("IndicateConfirm");
793 BT_DBG("Application path = %s", object_path);
794 BT_DBG("Sender = %s", sender);
796 g_variant_get(parameters, "(&sb)", &addr, &complete);
798 BT_DBG("Remote Device address number = %s", addr);
799 confirm.att_handle = g_strdup(object_path);
800 confirm.address = g_strdup(addr);
801 confirm.complete = complete;
803 svc_info = __bt_gatt_find_gatt_service_from_char(object_path);
804 if (svc_info != NULL) {
805 confirm.service_handle = g_strdup(svc_info->serv_path);
806 user_info = _bt_get_user_data(BT_COMMON);
808 if (user_info != NULL) {
810 BLUETOOTH_EVENT_GATT_SERVER_NOTIFICATION_COMPLETED,
811 BLUETOOTH_ERROR_NONE, &confirm,
812 user_info->cb, user_info->user_data);
816 g_dbus_method_invocation_return_value(invocation, NULL);
819 static void __bt_gatt_desc_method_call(GDBusConnection *connection,
821 const gchar *object_path,
822 const gchar *interface_name,
823 const gchar *method_name,
824 GVariant *parameters,
825 GDBusMethodInvocation *invocation,
828 if (g_strcmp0(method_name, "ReadValue") == 0) {
832 bt_gatt_read_req_t read_req = {0, };
833 bt_user_info_t *user_info = NULL;
834 struct gatt_req_info *req_info = NULL;
835 struct gatt_service_info *svc_info = NULL;
838 g_variant_get(parameters, "(&syq)", &addr, &req_id, &offset);
840 BT_DBG("Application path = %s", object_path);
842 BT_DBG("Remote Device address number = %s", addr);
843 BT_DBG("Request id = %d, Offset = %d", req_id, offset);
845 BT_DBG("Sender = %s", sender);
847 read_req.att_handle = g_strdup(object_path);
848 read_req.address = g_strdup(addr);
849 read_req.req_id = req_id;
850 read_req.offset = offset;
851 svc_info = __bt_gatt_find_gatt_service_from_desc(object_path);
852 if (svc_info != NULL) {
853 read_req.service_handle = g_strdup(svc_info->serv_path);
854 user_info = _bt_get_user_data(BT_COMMON);
856 /* Store requets information */
857 req_info = g_new0(struct gatt_req_info, 1);
858 req_info->attr_path = g_strdup(object_path);
859 req_info->svc_path = g_strdup(read_req.service_handle);
860 req_info->request_id = req_id;
861 req_info->offset = offset;
862 req_info->context = invocation;
863 gatt_requests = g_slist_append(gatt_requests, req_info);
865 if (user_info != NULL) {
867 BLUETOOTH_EVENT_GATT_SERVER_READ_REQUESTED,
868 BLUETOOTH_ERROR_NONE, &read_req,
869 user_info->cb, user_info->user_data);
873 if (read_req.att_handle)
874 g_free(read_req.att_handle);
875 if (read_req.address)
876 g_free(read_req.address);
877 if (read_req.service_handle)
878 g_free(read_req.service_handle);
881 } else if (g_strcmp0(method_name, "WriteValue") == 0) {
882 GVariant *var = NULL;
886 bt_gatt_value_change_t value_change = {0, };
887 bt_user_info_t *user_info = NULL;
889 struct gatt_service_info *svc_info = NULL;
890 struct gatt_req_info *req_info = NULL;
892 BT_DBG("WriteValue");
893 BT_DBG("Application path = %s", object_path);
894 BT_DBG("Sender = %s", sender);
896 g_variant_get(parameters, "(&syq@ay)", &addr, &req_id, &offset, &var);
898 value_change.att_handle = g_strdup(object_path);
899 value_change.address = g_strdup(addr);
900 svc_info = __bt_gatt_find_gatt_service_from_desc(object_path);
901 if (svc_info == NULL) {
902 g_variant_unref(var);
903 g_dbus_method_invocation_return_value(invocation, NULL);
907 value_change.service_handle = g_strdup(svc_info->serv_path);
908 value_change.offset = offset;
909 value_change.req_id = req_id;
911 len = g_variant_get_size(var);
915 value_change.att_value = (guint8 *)malloc(len);
916 if (!value_change.att_value) {
917 BT_ERR("att_value is NULL");
918 g_variant_unref(var);
919 g_dbus_method_invocation_return_value(invocation, NULL);
922 data = (char *)g_variant_get_data(var);
923 memcpy(value_change.att_value, data, len);
925 g_variant_unref(var);
927 value_change.val_len = len;
929 /* Store requets information */
930 req_info = g_new0(struct gatt_req_info, 1);
931 req_info->attr_path = g_strdup(object_path);
932 req_info->svc_path = g_strdup(value_change.service_handle);
933 req_info->request_id = req_id;
934 req_info->offset = offset;
935 req_info->context = invocation;
936 gatt_requests = g_slist_append(gatt_requests, req_info);
938 user_info = _bt_get_user_data(BT_COMMON);
939 if (user_info != NULL) {
941 BLUETOOTH_EVENT_GATT_SERVER_VALUE_CHANGED,
942 BLUETOOTH_ERROR_NONE, &value_change,
943 user_info->cb, user_info->user_data);
947 g_dbus_method_invocation_return_value(invocation, NULL);
950 gboolean __bt_gatt_emit_interface_removed(gchar *object_path, gchar *interface)
953 GError *error = NULL;
954 GVariantBuilder *array_builder;
956 array_builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
957 g_variant_builder_init(array_builder, G_VARIANT_TYPE("as"));
958 g_variant_builder_add(array_builder, "s", interface);
960 ret = g_dbus_connection_emit_signal(g_conn, NULL, "/",
961 "org.freedesktop.Dbus.Objectmanager",
963 g_variant_new("(oas)",
964 object_path, array_builder),
969 /* dbus gives error cause */
970 BT_ERR("d-bus api failure: errcode[%x], message[%s]",
971 error->code, error->message);
972 g_clear_error(&error);
975 g_variant_builder_unref(array_builder);
980 static const GDBusInterfaceVTable desc_interface_vtable = {
981 __bt_gatt_desc_method_call,
986 static const GDBusInterfaceVTable char_interface_vtable = {
987 __bt_gatt_char_method_call,
992 static const GDBusInterfaceVTable serv_interface_vtable = {
998 static const GDBusInterfaceVTable manager_interface_vtable = {
999 __bt_gatt_manager_method_call,
1004 static GDBusNodeInfo *__bt_gatt_create_method_node_info(
1005 const gchar *introspection_data)
1008 GDBusNodeInfo *node_info = NULL;
1010 if (introspection_data == NULL)
1013 node_info = g_dbus_node_info_new_for_xml(introspection_data, &err);
1016 BT_ERR("Unable to create node: %s", err->message);
1017 g_clear_error(&err);
1022 static struct gatt_service_info *__bt_gatt_find_gatt_service_info(
1023 const char *service_path)
1027 for (l = gatt_services; l != NULL; l = l->next) {
1028 struct gatt_service_info *info = l->data;
1030 if (g_strcmp0(info->serv_path, service_path) == 0)
1033 BT_ERR("Gatt service not found");
1037 static struct gatt_char_info *__bt_gatt_find_gatt_char_info(
1038 const char *service_path, const char *char_path)
1042 for (l1 = gatt_services; l1 != NULL; l1 = l1->next) {
1043 struct gatt_service_info *serv_info = l1->data;
1045 if (g_strcmp0(serv_info->serv_path, service_path) == 0) {
1047 for (l2 = serv_info->char_data; l2 != NULL; l2 = l2->next) {
1048 struct gatt_char_info *char_info = l2->data;
1050 if (g_strcmp0(char_info->char_path, char_path)
1054 BT_ERR("Gatt characteristic not found");
1058 BT_ERR("Gatt service not found");
1062 static struct gatt_desc_info *__bt_gatt_find_gatt_desc_info(
1063 const char *serv_path, const char *char_path,
1064 const char *desc_path)
1066 GSList *l1, *l2, *l3;
1068 for (l1 = gatt_services; l1 != NULL; l1 = l1->next) {
1069 struct gatt_service_info *serv_info = l1->data;
1071 if (g_strcmp0(serv_info->serv_path, serv_path) == 0) {
1072 for (l2 = serv_info->char_data; l2 != NULL; l2 = l2->next) {
1073 struct gatt_char_info *char_info = l2->data;
1075 if (g_strcmp0(char_info->char_path, char_path)
1077 for (l3 = char_info->desc_data; l3 != NULL; l3 = l3->next) {
1078 struct gatt_desc_info *desc_info = l3->data;
1079 if (g_strcmp0(desc_info->desc_path,
1088 BT_ERR("Gatt descriptor not found");
1092 static struct gatt_req_info *__bt_gatt_find_request_info(guint request_id)
1096 for (l = gatt_requests; l != NULL; l = l->next) {
1097 struct gatt_req_info *req_info = l->data;
1099 if (req_info && req_info->request_id == request_id) {
1103 BT_ERR("Gatt Request not found");
1107 static GDBusProxy *__bt_gatt_gdbus_init_manager_proxy(const gchar *service,
1108 const gchar *path, const gchar *interface)
1114 g_conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM,
1119 BT_ERR("Unable to connect to gdbus: %s", err->message);
1120 g_clear_error(&err);
1125 proxy = g_dbus_proxy_new_sync(g_conn,
1126 G_DBUS_PROXY_FLAGS_NONE, NULL,
1128 interface, NULL, &err);
1132 BT_ERR("Unable to create proxy: %s", err->message);
1133 g_clear_error(&err);
1137 manager_gproxy = proxy;
1142 static GDBusProxy *__bt_gatt_gdbus_get_manager_proxy(const gchar *service,
1143 const gchar *path, const gchar *interface)
1145 return (manager_gproxy) ? manager_gproxy :
1146 __bt_gatt_gdbus_init_manager_proxy(service,
1150 int bluetooth_gatt_convert_prop2string(
1151 bt_gatt_characteristic_property_t properties,
1152 char *char_properties[])
1156 if (properties & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_BROADCAST) {
1157 char_properties[flag_count] = g_strdup("broadcast");
1160 if (properties & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_READ) {
1161 char_properties[flag_count] = g_strdup("read");
1164 if (properties & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_WRITE_NO_RESPONSE) {
1165 char_properties[flag_count] = g_strdup("write-without-response");
1168 if (properties & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_WRITE) {
1169 char_properties[flag_count] = g_strdup("write");
1172 if (properties & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_NOTIFY) {
1173 char_properties[flag_count] = g_strdup("notify");
1176 if (properties & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_INDICATE) {
1177 char_properties[flag_count] = g_strdup("indicate");
1180 if (properties & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_SIGNED_WRITE) {
1181 char_properties[flag_count] = g_strdup("authenticated-signed-writes");
1184 if (properties & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_RELIABLE_WRITE) {
1185 char_properties[flag_count] = g_strdup("reliable-write");
1188 if (properties & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_WRITABLE_AUXILIARIES) {
1189 char_properties[flag_count] = g_strdup("writable-auxiliaries");
1192 if (properties & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_ENCRYPT_READ) {
1193 char_properties[flag_count] = g_strdup("encrypt-read");
1196 if (properties & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_ENCRYPT_WRITE) {
1197 char_properties[flag_count] = g_strdup("encrypt-write");
1200 if (properties & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_ENCRYPT_AUTHENTICATED_READ) {
1201 char_properties[flag_count] = g_strdup("encrypt-authenticated-read");
1204 if (properties & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_ENCRYPT_AUTHENTICATED_WRITE) {
1205 char_properties[flag_count] = g_strdup("encrypt-authenticated-write");
1209 if (flag_count == 0) {
1210 char_properties[flag_count] = g_strdup("read");
1217 int bluetooth_gatt_convert_perm2string(
1218 bt_gatt_permission_t properties,
1219 char *char_properties[])
1223 if (properties & BLUETOOTH_GATT_PERMISSION_READ) {
1224 char_properties[flag_count] = g_strdup("read");
1227 if (properties & BLUETOOTH_GATT_PERMISSION_WRITE) {
1228 char_properties[flag_count] = g_strdup("write");
1231 if (properties & BLUETOOTH_GATT_PERMISSION_ENCRYPT_READ) {
1232 char_properties[flag_count] = g_strdup("encrypt-read");
1235 if (properties & BLUETOOTH_GATT_PERMISSION_ENCRYPT_WRITE) {
1236 char_properties[flag_count] = g_strdup("encrypt-write");
1239 if (properties & BLUETOOTH_GATT_PERMISSION_ENCRYPT_AUTHENTICATED_READ) {
1240 char_properties[flag_count] = g_strdup("encrypt-authenticated-read");
1243 if (properties & BLUETOOTH_GATT_PERMISSION_ENCRYPT_AUTHENTICATED_WRITE) {
1244 char_properties[flag_count] = g_strdup("encrypt-authenticated-write");
1248 if (flag_count == 0) {
1249 char_properties[flag_count] = g_strdup("read");
1256 static void __bt_gatt_set_service_state(const char *service_path,
1259 struct gatt_service_info *svc_info = NULL;
1260 svc_info = __bt_gatt_find_gatt_service_info(service_path);
1262 if (svc_info != NULL) {
1263 BT_DBG("Updating the gatt service register state %d", state);
1264 svc_info->is_svc_registered = state;
1268 BT_DBG("gatt service not found");
1271 static gboolean __bt_gatt_get_service_state(const char *service_path)
1273 struct gatt_service_info *svc_info = NULL;
1275 svc_info = __bt_gatt_find_gatt_service_info(service_path);
1277 if (svc_info != NULL) {
1278 BT_DBG("Return the state of the gatt service %d",
1279 svc_info->is_svc_registered);
1280 return svc_info->is_svc_registered;
1283 BT_DBG("gatt service info is NULL");
1287 void get_service_cb(GObject *object, GAsyncResult *res, gpointer user_data)
1289 GError *error = NULL;
1291 GVariantIter *iter = NULL;
1292 const gchar *key = NULL;
1293 GVariant *value = NULL;
1294 const gchar *service = NULL;
1295 const gchar *characteristic = NULL;
1296 const gchar *descriptor = NULL;
1300 result = g_dbus_proxy_call_finish(manager_gproxy, res, &error);
1302 if (result == NULL) {
1303 /* dBUS-RPC is failed */
1304 BT_ERR("Dbus-RPC is failed\n");
1306 if (error != NULL) {
1307 /* dBUS gives error cause */
1308 BT_ERR("D-Bus API failure: errCode[%x], message[%s]\n",
1309 error->code, error->message);
1310 g_clear_error(&error);
1313 char *char_cmp = NULL;
1314 g_variant_get(result, "(a{sv})", &iter);
1315 char_cmp = g_strdup_printf("Characteristic%d", n_char);
1317 while (g_variant_iter_loop(iter, "{sv}", &key, &value)) {
1318 if (g_strcmp0(key, "Service") == 0) {
1319 service = g_variant_get_string(value, NULL);
1320 BT_DBG("Service %s", service);
1321 } else if (g_strcmp0(key, char_cmp) == 0) {
1322 characteristic = g_variant_get_string(value, NULL);
1324 char_cmp = g_strdup_printf("Characteristic%d", ++n_char);
1325 BT_DBG("%s", characteristic);
1326 } else if (g_strcmp0(key, "Descriptor") == 0) {
1327 descriptor = g_variant_get_string(value, NULL);
1328 BT_DBG("Descriptor %s", descriptor);
1331 g_variant_iter_free(iter);
1333 /* TODO: Store the service informationa and
1334 * Send respponse to CAPI layer. */
1336 g_variant_unref(result);
1341 void register_application_cb(GObject *object, GAsyncResult *res, gpointer user_data)
1343 BT_INFO("RegisterApplication is completed");
1345 GError *error = NULL;
1348 register_pending_cnt = 0;
1350 result = g_dbus_proxy_call_finish(manager_gproxy, res, &error);
1352 if (result == NULL) {
1353 /* dBUS-RPC is failed */
1354 BT_ERR("Dbus-RPC is failed\n");
1356 if (error != NULL) {
1357 /* dBUS gives error cause */
1358 BT_ERR("D-Bus API failure: errCode[%x], message[%s]\n",
1359 error->code, error->message);
1360 g_clear_error(&error);
1365 void unregister_application_cb(GObject *object, GAsyncResult *res,
1368 BT_INFO("UnregisterApplication is completed");
1370 GError *error = NULL;
1373 result = g_dbus_proxy_call_finish(manager_gproxy, res, &error);
1375 if (result == NULL) {
1376 /* dBUS-RPC is failed */
1377 BT_ERR("Dbus-RPC is failed\n");
1379 if (error != NULL) {
1380 /* dBUS gives error cause */
1381 BT_ERR("D-Bus API failure: errCode[%x], message[%s]\n",
1382 error->code, error->message);
1383 g_clear_error(&error);
1388 static int __bt_gatt_unregister_service(const char *service_path)
1390 if (!__bt_gatt_get_service_state(service_path)) {
1391 BT_DBG("service not registered \n");
1392 return BLUETOOTH_ERROR_NOT_FOUND;
1395 return BLUETOOTH_ERROR_NONE;
1398 BT_EXPORT_API int bluetooth_gatt_unregister_application(void)
1400 GDBusProxy *proxy = NULL;
1402 if (is_server_started) {
1403 proxy = __bt_gatt_gdbus_get_manager_proxy("org.bluez",
1404 "/org/bluez/hci0", GATT_MNGR_INTERFACE);
1406 if (proxy == NULL || app_path == NULL)
1407 return BLUETOOTH_ERROR_INTERNAL;
1409 BT_INFO("UnregisterApplication");
1411 /* Async Call to Unregister Service */
1412 g_dbus_proxy_call(proxy,
1413 "UnregisterApplication",
1414 g_variant_new("(o)",
1416 G_DBUS_CALL_FLAGS_NONE, -1,
1418 (GAsyncReadyCallback) unregister_application_cb,
1421 is_server_started = false;
1422 return BLUETOOTH_ERROR_NONE;
1425 BT_INFO("GATT server not started");
1426 return BLUETOOTH_ERROR_NONE;
1429 static GDBusConnection *__bt_gatt_get_gdbus_connection(void)
1431 GDBusConnection *local_system_gconn = NULL;
1434 if (g_conn == NULL) {
1435 g_conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
1438 BT_ERR("Unable to connect to dbus: %s", err->message);
1439 g_clear_error(&err);
1443 } else if (g_dbus_connection_is_closed(g_conn)) {
1444 local_system_gconn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
1446 if (!local_system_gconn) {
1447 BT_ERR("Unable to connect to dbus: %s", err->message);
1448 g_clear_error(&err);
1451 g_conn = local_system_gconn;
1457 BT_EXPORT_API int bluetooth_gatt_init(void)
1459 GDBusConnection *conn;
1460 GDBusNodeInfo *obj_info;
1461 GError *error = NULL;
1463 owner_id = g_bus_own_name(G_BUS_TYPE_SYSTEM,
1464 BT_GATT_SERVICE_NAME,
1465 G_BUS_NAME_OWNER_FLAGS_NONE,
1466 NULL, NULL, NULL, NULL, NULL);
1468 BT_DBG("owner_id is [%d]", owner_id);
1469 app_path = g_strdup_printf("/com/%d", getpid());
1473 conn = __bt_gatt_get_gdbus_connection();
1475 BT_ERR("Unable to get connection");
1476 return BLUETOOTH_ERROR_INTERNAL;
1479 /* Register ObjectManager interface */
1480 obj_info = __bt_gatt_create_method_node_info(
1481 manager_introspection_xml);
1483 if (obj_info == NULL) {
1484 BT_ERR("failed to get node info");
1485 return BLUETOOTH_ERROR_INTERNAL;
1488 manager_id = g_dbus_connection_register_object(g_conn, app_path,
1489 obj_info->interfaces[0],
1490 &manager_interface_vtable,
1491 NULL, NULL, &error);
1493 if (manager_id == 0) {
1494 BT_ERR("failed to register: %s", error->message);
1495 g_error_free(error);
1496 return BLUETOOTH_ERROR_INTERNAL;
1499 return BLUETOOTH_ERROR_NONE;
1502 BT_EXPORT_API int bluetooth_gatt_deinit()
1504 int ret = BLUETOOTH_ERROR_NONE;
1505 /* Unown gdbus bus */
1508 /* remove/unregister all services */
1509 BT_DBG("removing all registered gatt service\n");
1510 bluetooth_gatt_delete_services();
1512 g_bus_unown_name(owner_id);
1514 /* unregister the exported interface for object manager */
1515 g_dbus_connection_unregister_object(g_conn,
1518 BT_DBG("Gatt service deinitialized \n");
1520 g_slist_free(gatt_services);
1521 gatt_services = NULL;
1523 ret = bluetooth_gatt_unregister_application();
1525 if (ret == BLUETOOTH_ERROR_NONE) {
1533 return BLUETOOTH_ERROR_NOT_FOUND;
1536 BT_EXPORT_API int bluetooth_gatt_add_service(const char *svc_uuid,
1539 GError *error = NULL;
1541 GDBusNodeInfo *node_info;
1543 GVariantBuilder *builder = NULL;
1544 GVariantBuilder *builder1 = NULL;
1545 GVariantBuilder *inner_builder = NULL;
1546 gboolean svc_primary = TRUE;
1547 struct gatt_service_info *serv_info = NULL;
1549 node_info = __bt_gatt_create_method_node_info(
1550 service_introspection_xml);
1552 if (node_info == NULL)
1553 return BLUETOOTH_ERROR_INTERNAL;
1555 path = g_strdup_printf("%s"GATT_SERV_OBJECT_PATH"%d", app_path, serv_id++);
1556 BT_DBG("gatt service path is [%s]", path);
1558 object_id = g_dbus_connection_register_object(g_conn, path,
1559 node_info->interfaces[0],
1560 &serv_interface_vtable,
1561 NULL, NULL, &error);
1563 if (object_id == 0) {
1564 BT_ERR("failed to register: %s", error->message);
1565 g_error_free(error);
1568 return BLUETOOTH_ERROR_INTERNAL;
1571 /* Add object_id/gatt service information; it's required at the time of
1572 * service unregister and Getmanagedobjects
1574 serv_info = g_new0(struct gatt_service_info, 1);
1576 serv_info->serv_path = g_strdup(path);
1577 serv_info->serv_id = object_id;
1578 serv_info->service_uuid = g_strdup(svc_uuid);
1579 serv_info->is_svc_registered = FALSE;
1580 serv_info->is_svc_primary = svc_primary;
1582 gatt_services = g_slist_append(gatt_services, serv_info);
1584 /* emit interfacesadded signal here for service path */
1585 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sa{sv}}"));
1586 inner_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
1588 g_variant_builder_add(inner_builder, "{sv}",
1589 "UUID", g_variant_new_string(svc_uuid));
1591 g_variant_builder_add(inner_builder, "{sv}",
1592 "Primary", g_variant_new_boolean(svc_primary));
1594 builder1 = g_variant_builder_new(G_VARIANT_TYPE("ao"));
1596 g_variant_builder_add(inner_builder, "{sv}", "Characteristics",
1597 g_variant_new("ao", builder1));
1599 g_variant_builder_add(builder, "{sa{sv}}",
1600 GATT_SERV_INTERFACE, inner_builder);
1602 g_dbus_connection_emit_signal(g_conn, NULL, "/",
1603 "org.freedesktop.Dbus.ObjectManager",
1605 g_variant_new("(oa{sa{sv}})",
1611 *svc_path = g_strdup(path);
1614 g_variant_builder_unref(inner_builder);
1615 g_variant_builder_unref(builder);
1616 g_variant_builder_unref(builder1);
1618 return BLUETOOTH_ERROR_NONE;
1621 BT_EXPORT_API int bluetooth_gatt_add_new_characteristic(
1622 const char *svc_path, const char *char_uuid,
1623 bt_gatt_permission_t permissions,
1624 bt_gatt_characteristic_property_t properties,
1628 GError *error = NULL;
1630 GDBusNodeInfo *node_info;
1632 GVariantBuilder *builder = NULL;
1633 GVariantBuilder *inner_builder = NULL;
1634 struct gatt_service_info *serv_info = NULL;
1635 struct gatt_char_info *char_info = NULL;
1636 GVariantBuilder *builder2 = NULL;
1637 GVariantBuilder *builder3 = NULL;
1638 GVariant *flags_val = NULL;
1640 char *char_flags[NUMBER_OF_FLAGS];
1645 new_service = FALSE;
1648 BT_DBG("gatt svc_path path is [%s]", svc_path);
1649 serv_info = __bt_gatt_find_gatt_service_info(svc_path);
1650 if (serv_info == NULL)
1651 return BLUETOOTH_ERROR_INVALID_PARAM;
1653 node_info = __bt_gatt_create_method_node_info(
1654 characteristics_introspection_xml);
1656 if (node_info == NULL)
1657 return BLUETOOTH_ERROR_INTERNAL;
1659 path = g_strdup_printf("%s/characteristic%d", svc_path, char_id++);
1660 BT_DBG("gatt characteristic path is [%s]", path);
1662 object_id = g_dbus_connection_register_object(g_conn, path,
1663 node_info->interfaces[0],
1664 &char_interface_vtable,
1665 NULL, NULL, &error);
1667 if (object_id == 0) {
1668 BT_ERR("failed to register: %s", error->message);
1669 g_error_free(error);
1672 return BLUETOOTH_ERROR_INTERNAL;
1675 if (permissions & BLUETOOTH_GATT_PERMISSION_ENCRYPT_READ)
1676 properties |= BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_ENCRYPT_READ;
1677 if (permissions & BLUETOOTH_GATT_PERMISSION_ENCRYPT_AUTHENTICATED_READ)
1678 properties |= BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_ENCRYPT_AUTHENTICATED_READ;
1679 if (permissions & BLUETOOTH_GATT_PERMISSION_ENCRYPT_WRITE)
1680 properties |= BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_ENCRYPT_WRITE;
1681 if (permissions & BLUETOOTH_GATT_PERMISSION_ENCRYPT_AUTHENTICATED_WRITE)
1682 properties |= BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_ENCRYPT_AUTHENTICATED_WRITE;
1684 flag_count = bluetooth_gatt_convert_prop2string(properties, char_flags);
1686 char_info = g_new0(struct gatt_char_info, 1);
1688 char_info->char_path = g_strdup(path);
1689 char_info->char_id = object_id;
1690 char_info->char_uuid = g_strdup(char_uuid);
1692 for (i = 0; i < flag_count; i++) {
1693 char_info->char_flags[i] = char_flags[i];
1696 char_info->flags_length = flag_count;
1698 serv_info->char_data = g_slist_append(serv_info->char_data, char_info);
1700 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sa{sv}}"));
1701 inner_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
1703 g_variant_builder_add(inner_builder, "{sv}", "UUID",
1704 g_variant_new("s", char_uuid));
1705 g_variant_builder_add(inner_builder, "{sv}", "Service",
1706 g_variant_new("o", svc_path));
1708 builder2 = g_variant_builder_new(G_VARIANT_TYPE("as"));
1710 for (i = 0; i < flag_count; i++) {
1711 g_variant_builder_add(builder2, "s", char_flags[i]);
1714 flags_val = g_variant_new("as", builder2);
1715 g_variant_builder_add(inner_builder, "{sv}", "Flags",
1718 builder3 = g_variant_builder_new(G_VARIANT_TYPE("ao"));
1720 g_variant_builder_add(inner_builder, "{sv}", "Descriptors",
1721 g_variant_new("ao", builder3));
1723 g_variant_builder_add(builder, "{sa{sv}}",
1724 GATT_CHAR_INTERFACE,
1727 g_dbus_connection_emit_signal(g_conn, NULL, "/",
1728 "org.freedesktop.Dbus.ObjectManager",
1730 g_variant_new("(oa{sa{sv}})",
1734 *char_path = g_strdup(path);
1740 g_variant_builder_unref(inner_builder);
1741 g_variant_builder_unref(builder);
1742 g_variant_builder_unref(builder2);
1743 g_variant_builder_unref(builder3);
1745 return BLUETOOTH_ERROR_NONE;
1748 BT_EXPORT_API int bluetooth_gatt_set_characteristic_value(
1749 const char *characteristic, const char *char_value,
1752 gchar **line_argv = NULL;
1753 char *serv_path = NULL;
1754 struct gatt_char_info *char_info = NULL;
1755 GVariantBuilder *builder1 = NULL;
1756 GVariantBuilder *builder = NULL;
1757 GVariantBuilder *inner_builder = NULL;
1758 GVariant *char_val = NULL;
1759 GError *error = NULL;
1761 int res = BLUETOOTH_ERROR_NONE;
1763 line_argv = g_strsplit_set(characteristic, "/", 0);
1764 serv_path = g_strdup_printf("/%s/%s/%s", line_argv[1], line_argv[2], line_argv[3]);
1766 char_info = __bt_gatt_find_gatt_char_info(serv_path, characteristic);
1768 if (char_info == NULL) {
1769 /* Fix : RESOURCE_LEAK */
1770 res = BLUETOOTH_ERROR_INVALID_PARAM;
1774 char_info->value_length = value_length;
1776 char_info->char_value = (char *)malloc(value_length);
1777 /* Fix : NULL_RETURNS */
1778 if (char_info->char_value == NULL) {
1779 res = BLUETOOTH_ERROR_MEMORY_ALLOCATION;
1783 for (i = 0; i < value_length; i++)
1784 char_info->char_value[i] = char_value[i];
1786 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sa{sv}}"));
1787 inner_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
1789 builder1 = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
1791 for (i = 0; i < value_length; i++) {
1792 g_variant_builder_add(builder1, "y", char_value[i]);
1795 char_val = g_variant_new("ay", builder1);
1796 g_variant_builder_add(inner_builder, "{sv}", "Value", char_val);
1798 g_variant_builder_add(builder, "{sa{sv}}",
1799 GATT_CHAR_INTERFACE,
1802 g_dbus_connection_emit_signal(g_conn, NULL, "/",
1803 "org.freedesktop.Dbus.ObjectManager",
1805 g_variant_new("(oa{sa{sv}})",
1806 char_info->char_path, builder),
1809 g_variant_builder_unref(inner_builder);
1810 g_variant_builder_unref(builder);
1811 g_variant_builder_unref(builder1);
1813 g_strfreev(line_argv);
1819 BT_EXPORT_API int bluetooth_gatt_add_descriptor(
1820 const char *char_path, const char *desc_uuid,
1821 bt_gatt_permission_t permissions,
1824 static int desc_id = 1;
1825 GError *error = NULL;
1827 GDBusNodeInfo *node_info;
1829 GVariantBuilder *builder = NULL;
1830 GVariantBuilder *inner_builder = NULL;
1831 struct gatt_char_info *char_info = NULL;
1832 struct gatt_desc_info *desc_info = NULL;
1833 gchar **line_argv = NULL;
1835 GVariantBuilder *builder2 = NULL;
1836 GVariant *flags_val = NULL;
1838 char *desc_flags[NUMBER_OF_FLAGS];
1846 line_argv = g_strsplit_set(char_path, "/", 0);
1847 serv_path = g_strdup_printf("/%s/%s/%s", line_argv[1], line_argv[2], line_argv[3]);
1849 char_info = __bt_gatt_find_gatt_char_info(serv_path, char_path);
1850 if (char_info == NULL) {
1851 g_strfreev(line_argv);
1852 return BLUETOOTH_ERROR_INVALID_PARAM;
1855 node_info = __bt_gatt_create_method_node_info(
1856 descriptor_introspection_xml);
1858 if (node_info == NULL) {
1859 g_strfreev(line_argv);
1860 return BLUETOOTH_ERROR_INTERNAL;
1863 path = g_strdup_printf("%s/descriptor%d", char_path, desc_id++);
1864 BT_DBG("gatt descriptor path is [%s]", path);
1866 object_id = g_dbus_connection_register_object(g_conn, path,
1867 node_info->interfaces[0],
1868 &desc_interface_vtable,
1869 NULL, NULL, &error);
1871 if (object_id == 0) {
1872 BT_ERR("failed to register: %s", error->message);
1873 g_error_free(error);
1875 g_strfreev(line_argv);
1877 return BLUETOOTH_ERROR_INTERNAL;
1880 flag_count = bluetooth_gatt_convert_perm2string(permissions, desc_flags);
1882 desc_info = g_new0(struct gatt_desc_info, 1);
1884 desc_info->desc_path = g_strdup(path);
1885 desc_info->desc_id = object_id;
1886 desc_info->desc_uuid = g_strdup(desc_uuid);
1888 for (i = 0; i < flag_count; i++) {
1889 desc_info->desc_flags[i] = desc_flags[i];
1892 desc_info->flags_length = flag_count;
1894 char_info->desc_data = g_slist_append(char_info->desc_data, desc_info);
1896 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sa{sv}}"));
1897 inner_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
1899 g_variant_builder_add(inner_builder, "{sv}", "UUID",
1900 g_variant_new("s", desc_uuid));
1901 g_variant_builder_add(inner_builder, "{sv}", "Characteristic",
1902 g_variant_new("o", char_path));
1904 builder2 = g_variant_builder_new(G_VARIANT_TYPE("as"));
1906 for (i = 0; i < flag_count; i++) {
1907 g_variant_builder_add(builder2, "s", desc_flags[i]);
1910 flags_val = g_variant_new("as", builder2);
1911 g_variant_builder_add(inner_builder, "{sv}", "Flags",
1914 g_variant_builder_add(builder, "{sa{sv}}",
1915 GATT_DESC_INTERFACE,
1918 g_dbus_connection_emit_signal(g_conn, NULL, "/",
1919 "org.freedesktop.Dbus.ObjectManager",
1921 g_variant_new("(oa{sa{sv}})",
1925 *desc_path = g_strdup(path);
1928 g_strfreev(line_argv);
1929 g_variant_builder_unref(inner_builder);
1930 g_variant_builder_unref(builder);
1932 return BLUETOOTH_ERROR_NONE;
1935 BT_EXPORT_API int bluetooth_gatt_set_descriptor_value(
1936 const char *desc_path, const char *desc_value,
1939 GError *error = NULL;
1940 GVariantBuilder *builder = NULL;
1941 GVariantBuilder *inner_builder = NULL;
1942 GVariantBuilder *builder1 = NULL;
1943 struct gatt_desc_info *desc_info = NULL;
1944 gchar **line_argv = NULL;
1946 GVariant *desc_val = NULL;
1947 char *serv_path = NULL;
1950 line_argv = g_strsplit_set(desc_path, "/", 0);
1951 serv_path = g_strdup_printf("/%s/%s/%s", line_argv[1], line_argv[2], line_argv[3]);
1952 char_path = g_strdup_printf("%s/%s", serv_path, line_argv[4]);
1954 desc_info = __bt_gatt_find_gatt_desc_info(serv_path, char_path, desc_path);
1956 /* Free the allocated memory */
1957 g_strfreev(line_argv);
1961 /* Fix : NULL_RETURNS */
1962 retv_if(desc_info == NULL, BLUETOOTH_ERROR_INVALID_PARAM);
1964 desc_info->desc_value = (char *)malloc(value_length);
1966 /* Fix : NULL_RETURNS */
1967 retv_if(desc_info->desc_value == NULL, BLUETOOTH_ERROR_MEMORY_ALLOCATION);
1969 for (i = 0; i < value_length; i++)
1970 desc_info->desc_value[i] = desc_value[i];
1972 desc_info->value_length = value_length;
1974 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sa{sv}}"));
1975 inner_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
1977 builder1 = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
1979 for (i = 0; i < value_length; i++) {
1980 g_variant_builder_add(builder1, "y", desc_value[i]);
1982 desc_val = g_variant_new("ay", builder1);
1983 g_variant_builder_add(inner_builder, "{sv}", "Value", desc_val);
1985 g_variant_builder_add(builder, "{sa{sv}}",
1986 GATT_DESC_INTERFACE,
1989 g_dbus_connection_emit_signal(g_conn, NULL, "/",
1990 "org.freedesktop.Dbus.ObjectManager",
1992 g_variant_new("(oa{sa{sv}})",
1993 desc_info->desc_path, builder),
1996 g_variant_builder_unref(inner_builder);
1997 g_variant_builder_unref(builder);
1998 g_variant_builder_unref(builder1);
2000 return BLUETOOTH_ERROR_NONE;
2003 int bluetooth_gatt_get_service(const char *svc_uuid)
2005 GDBusProxy *proxy = NULL;
2008 proxy = __bt_gatt_gdbus_get_manager_proxy("org.bluez",
2009 "/org/bluez/hci0", GATT_MNGR_INTERFACE);
2011 return BLUETOOTH_ERROR_INTERNAL;
2013 uuid = g_strdup(svc_uuid);
2015 g_dbus_proxy_call(proxy,
2017 g_variant_new("(s)",
2019 G_DBUS_CALL_FLAGS_NONE, -1,
2021 (GAsyncReadyCallback) get_service_cb,
2026 return BLUETOOTH_ERROR_NONE;
2029 BT_EXPORT_API int bluetooth_gatt_register_service(
2030 const char *svc_path)
2032 if (_bt_check_privilege(BT_CHECK_PRIVILEGE, BT_GATT_REGISTER_SERVICE)
2033 == BLUETOOTH_ERROR_PERMISSION_DEINED) {
2034 BT_ERR("Don't have aprivilege to use this API");
2035 return BLUETOOTH_ERROR_PERMISSION_DEINED;
2038 register_pending_cnt++;
2040 if (__bt_gatt_get_service_state(svc_path)) {
2041 BT_DBG("service already registered \n");
2042 return BLUETOOTH_ERROR_NONE;
2045 __bt_gatt_set_service_state(svc_path, TRUE);
2047 return BLUETOOTH_ERROR_NONE;
2050 BT_EXPORT_API int bluetooth_gatt_register_application(void)
2052 GDBusProxy *proxy = NULL;
2054 if (!is_server_started) {
2056 if (_bt_check_privilege(BT_CHECK_PRIVILEGE, BT_GATT_REGISTER_APPLICATION)
2057 == BLUETOOTH_ERROR_PERMISSION_DEINED) {
2058 BT_ERR("Don't have aprivilege to use this API");
2059 return BLUETOOTH_ERROR_PERMISSION_DEINED;
2062 proxy = __bt_gatt_gdbus_get_manager_proxy("org.bluez",
2063 "/org/bluez/hci0", GATT_MNGR_INTERFACE);
2064 if (proxy == NULL || app_path == NULL)
2065 return BLUETOOTH_ERROR_INTERNAL;
2067 BT_INFO("RegisterApplication");
2069 g_dbus_proxy_call(proxy,
2070 "RegisterApplication",
2071 g_variant_new("(oa{sv})",
2073 G_DBUS_CALL_FLAGS_NONE, -1,
2075 (GAsyncReadyCallback) register_application_cb,
2078 is_server_started = true;
2080 return BLUETOOTH_ERROR_NONE;
2083 BT_INFO("Already RegisterApplication");
2085 return BLUETOOTH_ERROR_NONE;
2088 BT_EXPORT_API int bluetooth_gatt_delete_services(void)
2091 int error = BLUETOOTH_ERROR_NONE;
2095 for (l = gatt_services; l != NULL; l = l->next) {
2096 struct gatt_service_info *info = l->data;
2097 BT_DBG("svc_path is %s", info->serv_path);
2098 if (bluetooth_gatt_unregister_service(info->serv_path)
2099 != BLUETOOTH_ERROR_NONE) {
2100 error = BLUETOOTH_ERROR_INTERNAL;
2101 BT_DBG(" Error in removing service %s \n",
2105 BT_DBG(" All services removed successfully.\n ");
2107 BT_DBG(" There are no registered services.\n ");
2110 g_slist_free(gatt_services);
2111 gatt_services = NULL;
2114 if (error != BLUETOOTH_ERROR_NONE)
2117 return BLUETOOTH_ERROR_NONE;
2120 BT_EXPORT_API int bluetooth_gatt_update_characteristic(
2121 const char *char_path, const char* char_value,
2124 GVariantBuilder *outer_builder;
2125 GVariantBuilder *inner_builder;
2126 GVariantBuilder *invalidated_builder;
2127 GVariant *update_value = NULL;
2128 GError *error = NULL;
2129 gboolean ret = FALSE;
2130 int err = BLUETOOTH_ERROR_NONE;
2132 gchar **line_argv = NULL;
2133 gchar *serv_path = NULL;
2135 line_argv = g_strsplit_set(char_path, "/", 0);
2136 serv_path = g_strdup_printf("/%s/%s/%s", line_argv[1], line_argv[2], line_argv[3]);
2138 if (!__bt_gatt_get_service_state(serv_path)) {
2139 BT_DBG("service not registered for this characteristic \n");
2140 g_strfreev(line_argv);
2141 return BLUETOOTH_ERROR_INTERNAL;
2144 outer_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
2145 invalidated_builder = g_variant_builder_new(G_VARIANT_TYPE("as"));
2147 inner_builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
2148 for (i = 0; i < value_length; i++) {
2149 g_variant_builder_add(inner_builder, "y", char_value[i]);
2152 update_value = g_variant_new("ay", inner_builder);
2154 outer_builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
2155 g_variant_builder_add(outer_builder, "{sv}", "Value",
2158 BT_DBG("Updating characteristic value \n");
2159 ret = g_dbus_connection_emit_signal(g_conn, NULL,
2161 "org.freedesktop.DBus.Properties",
2162 "PropertiesChanged",
2163 g_variant_new("(sa{sv}as)",
2164 "org.bluez.GattCharacteristic1",
2165 outer_builder, invalidated_builder),
2169 if (error != NULL) {
2170 BT_ERR("D-Bus API failure: errCode[%x], \
2172 error->code, error->message);
2173 g_clear_error(&error);
2175 err = BLUETOOTH_ERROR_INTERNAL;
2177 struct gatt_char_info *char_info = NULL;
2179 char_info = __bt_gatt_find_gatt_char_info(serv_path, char_path);
2180 if (char_info == NULL) {
2181 return BLUETOOTH_ERROR_INVALID_DATA;
2184 char_info->value_length = value_length;
2186 char_info->char_value = (char *)realloc(char_info->char_value, value_length);
2187 if (char_info->char_value) {
2188 for (i = 0; i < value_length; i++) {
2189 char_info->char_value[i] = char_value[i];
2194 g_strfreev(line_argv);
2195 g_variant_builder_unref(inner_builder);
2196 g_variant_builder_unref(outer_builder);
2197 g_variant_builder_unref(invalidated_builder);
2202 BT_EXPORT_API int bluetooth_gatt_unregister_service(const char *svc_path)
2205 struct gatt_service_info *svc_info;
2207 int err = BLUETOOTH_ERROR_NONE;
2210 BT_DBG("svc_path %s", svc_path);
2211 svc_info = __bt_gatt_find_gatt_service_info(svc_path);
2214 BT_ERR("Unable to find service info");
2215 return BLUETOOTH_ERROR_NOT_FOUND;
2218 err = __bt_gatt_unregister_service(svc_path);
2219 if (err != BLUETOOTH_ERROR_NONE) {
2220 BT_DBG("Could not unregister application");
2224 for (l = svc_info->char_data; l != NULL; l = l->next) {
2225 struct gatt_char_info *char_info = l->data;
2227 for (l1 = char_info->desc_data; l1 != NULL; l1 = l1->next) {
2228 struct gatt_desc_info *desc_info = l1->data;
2230 ret = g_dbus_connection_unregister_object(g_conn,
2231 desc_info->desc_id);
2233 __bt_gatt_emit_interface_removed(
2234 desc_info->desc_path,
2235 GATT_DESC_INTERFACE);
2237 err = BLUETOOTH_ERROR_INTERNAL;
2240 ret = g_dbus_connection_unregister_object(g_conn,
2241 char_info->char_id);
2243 __bt_gatt_emit_interface_removed(char_info->char_path,
2244 GATT_CHAR_INTERFACE);
2246 err = BLUETOOTH_ERROR_INTERNAL;
2249 ret = g_dbus_connection_unregister_object(g_conn, svc_info->serv_id);
2251 __bt_gatt_emit_interface_removed(svc_info->serv_path,
2252 GATT_SERV_INTERFACE);
2254 err = BLUETOOTH_ERROR_INTERNAL;
2257 ret = g_dbus_connection_unregister_object(g_conn, svc_info->prop_id);
2259 BT_DBG("Unregistered the service on properties interface");
2262 for (tmp = gatt_services; tmp != NULL; tmp = tmp->next) {
2263 struct gatt_service_info *info = tmp->data;
2265 if (g_strcmp0(info->serv_path, svc_path) == 0) {
2266 gatt_services = g_slist_delete_link(gatt_services, tmp->data);
2270 new_service = FALSE;
2272 if (gatt_services->next == NULL)
2278 BT_EXPORT_API int bluetooth_gatt_send_response(int request_id, guint req_type,
2279 int resp_state, int offset, char *value, int value_length)
2281 struct gatt_req_info *req_info = NULL;
2283 if (_bt_check_privilege(BT_CHECK_PRIVILEGE, BT_GATT_SEND_RESPONSE)
2284 == BLUETOOTH_ERROR_PERMISSION_DEINED) {
2285 BT_ERR("Don't have aprivilege to use this API");
2286 return BLUETOOTH_ERROR_PERMISSION_DEINED;
2289 req_info = __bt_gatt_find_request_info(request_id);
2292 if (resp_state != BLUETOOTH_ERROR_NONE) {
2294 GQuark quark = g_quark_from_string("gatt-server");
2295 GError *err = g_error_new(quark, 0, "Application Error");
2296 g_dbus_method_invocation_return_gerror(req_info->context, err);
2299 gatt_requests = g_slist_remove(gatt_requests, req_info);
2301 req_info->context = NULL;
2302 if (req_info->attr_path)
2303 g_free(req_info->attr_path);
2304 if (req_info->svc_path)
2305 g_free(req_info->svc_path);
2308 return BLUETOOTH_ERROR_NONE;
2310 if (req_type == BLUETOOTH_GATT_ATT_REQUEST_TYPE_READ) {
2312 GVariantBuilder *inner_builder = NULL;
2313 inner_builder = g_variant_builder_new(G_VARIANT_TYPE("ay"));
2314 if (value_length > 0 && value != NULL) {
2315 for (i = 0; i < value_length; i++)
2316 g_variant_builder_add(inner_builder, "y", value[i]);
2318 g_dbus_method_invocation_return_value(req_info->context,
2319 g_variant_new("(ay)", inner_builder));
2320 g_variant_builder_unref(inner_builder);
2322 g_dbus_method_invocation_return_value(req_info->context, NULL);
2324 gatt_requests = g_slist_remove(gatt_requests, req_info);
2326 req_info->context = NULL;
2327 if (req_info->attr_path)
2328 g_free(req_info->attr_path);
2329 if (req_info->svc_path)
2330 g_free(req_info->svc_path);
2333 return BLUETOOTH_ERROR_INTERNAL;
2336 return BLUETOOTH_ERROR_NONE;
2339 BT_EXPORT_API int bluetooth_gatt_server_set_notification(const char *char_path,
2340 bluetooth_device_address_t *unicast_address)
2342 GVariantBuilder *outer_builder;
2343 GVariantBuilder *invalidated_builder;
2344 GError *error = NULL;
2345 gboolean notify = TRUE;
2346 gboolean ret = TRUE;
2347 int err = BLUETOOTH_ERROR_NONE;
2348 gchar **line_argv = NULL;
2349 gchar *serv_path = NULL;
2350 char addr[20] = { 0 };
2352 line_argv = g_strsplit_set(char_path, "/", 0);
2353 serv_path = g_strdup_printf("/%s/%s/%s", line_argv[1], line_argv[2], line_argv[3]);
2355 if (!__bt_gatt_get_service_state(serv_path)) {
2356 BT_DBG("service not registered for this characteristic \n");
2357 g_strfreev(line_argv);
2358 return BLUETOOTH_ERROR_INTERNAL;
2361 outer_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
2362 invalidated_builder = g_variant_builder_new(G_VARIANT_TYPE("as"));
2364 g_variant_builder_add(outer_builder, "{sv}", "Notifying",
2365 g_variant_new("b", notify));
2367 if (unicast_address) {
2368 _bt_convert_addr_type_to_string(addr,
2369 (unsigned char *)unicast_address->addr);
2371 g_variant_builder_add(outer_builder, "{sv}", "Unicast",
2372 g_variant_new("s", addr));
2374 BT_DBG("Set characteristic Notification \n");
2375 ret = g_dbus_connection_emit_signal(g_conn, NULL,
2377 "org.freedesktop.DBus.Properties",
2378 "PropertiesChanged",
2379 g_variant_new("(sa{sv}as)",
2380 "org.bluez.GattCharacteristic1",
2381 outer_builder, invalidated_builder),
2385 if (error != NULL) {
2386 BT_ERR("D-Bus API failure: errCode[%x], \
2388 error->code, error->message);
2389 g_clear_error(&error);
2391 err = BLUETOOTH_ERROR_INTERNAL;
2394 g_strfreev(line_argv);
2395 g_variant_builder_unref(outer_builder);
2396 g_variant_builder_unref(invalidated_builder);