1 /* ****************************************************************
3 * Copyright 2015 Intel Corporation All Rights Reserved.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
17 ******************************************************************/
20 #include "gatt_dbus.h"
24 #include "cagattservice.h"
26 #include "oic_malloc.h"
34 static char const TAG[] = "BLE_SERVICE";
36 static GVariant * CAGattServiceGetProperties(GattService1 * service)
39 Create a variant containing the @c GattService1 properties, of
40 the form @c a{sa{sv}}.
44 * Populate the property table, and create the variant to be
45 * embedded in the results of the
46 * @c org.freedesktop.Dbus.ObjectManager.GetManagedObjects()
49 * The @c "Device" property is only available on the client side
50 * so we don't bother returning it here.
52 * @todo Do we care about the @c "Includes" property?
53 * @c "Includes" isn't implemented by BlueZ as of version
54 * 5.30, so we can leave it out.
56 CADBusSkeletonProperty const properties[] = {
58 g_variant_new_string(gatt_service1_get_uuid(service)) },
60 g_variant_new_boolean(gatt_service1_get_primary(service)) },
63 gatt_service1_get_characteristics(service),
68 CAMakePropertyDictionary(
69 BLUEZ_GATT_SERVICE_INTERFACE,
71 sizeof(properties) / sizeof(properties[0]));
75 * Implementation of the
76 * @c org.freedesktop.DBus.ObjectManager.GetManagedObjects() method
77 * for the @c org.bluez.GattService1 interface.
79 static gboolean CAGattServiceHandleGetManagedObjects(
80 ObjectManager * object,
81 GDBusMethodInvocation * invocation,
85 * @note Ideally we shouldn't need this implementation, and should
86 * be able to simply rely GDBusObjectManagerServer instead.
87 * Unfortunately, BlueZ expects the @c
88 * org.bluez.GattService1 object to implement the @c
89 * ObjectManager interface, and both interfaces must rooted
90 * at the same object path, as well. That requirement
91 * prevents us from using @c GDBusObjectManagerServer since
92 * it won't allow us to export more than interface on a
97 Build the object array containing the IoTivity
98 org.bluez.GattService1 hierarchy.
102 CAGattService * const service = user_data;
104 GVariantBuilder builder;
105 g_variant_builder_init(&builder, G_VARIANT_TYPE("a{oa{sa{sv}}}"));
107 // Start out with the service itself.
108 g_variant_builder_add(&builder,
110 service->object_path,
111 CAGattServiceGetProperties(service->service));
114 Add the request characteristic and user description
117 CAGattCharacteristic * const request_chrc =
118 &service->request_characteristic;
120 g_variant_builder_add(&builder,
122 request_chrc->object_path,
123 CAGattCharacteristicGetProperties(
124 request_chrc->characteristic));
126 CAGattDescriptor * const request_desc = &request_chrc->descriptor;
128 g_variant_builder_add(&builder,
130 request_desc->object_path,
131 CAGattDescriptorGetProperties(
132 request_desc->descriptor));
135 Add the response characteristic and user description
138 CAGattCharacteristic * const response_chrc =
139 &service->response_characteristic;
141 g_variant_builder_add(&builder,
143 response_chrc->object_path,
144 CAGattCharacteristicGetProperties(
145 response_chrc->characteristic));
147 CAGattDescriptor * const response_desc = &response_chrc->descriptor;
149 g_variant_builder_add(&builder,
151 response_desc->object_path,
152 CAGattDescriptorGetProperties(
153 response_desc->descriptor));
155 GVariant * const objects = g_variant_builder_end(&builder);
157 object_manager_complete_get_managed_objects(object,
164 char * CAGattServiceMakePeerAddress(CAGattService * s)
169 Since there is no direct way to obtain the client address
170 associated with the GATT characterstics on the server side,
171 embed a stringified pointer to this GATT service of the form
172 "&ABCDEF01" as the address instead so that we can use it to
173 refer to the client. This works since:
174 1) only one LE central is ever connected to an LE peripheral
175 2) the CA layer doesn't directly interpret the client
180 Length of stringified pointer in hexadecimal format, plus one
181 for the leading ampersand, and one more for the null
184 static size_t const PSEUDO_ADDR_LEN = sizeof(uintptr_t) * 2 + 2;
186 assert(MAX_ADDR_STR_SIZE_CA > PSEUDO_ADDR_LEN);
188 char * const addr = OICMalloc(PSEUDO_ADDR_LEN);
195 int const count = snprintf(addr,
200 if (count < 0 || count >= (int) PSEUDO_ADDR_LEN)
204 "Error creating peer address on server side.");
214 CAGattService * CAGattServiceDecodeAddress(char const * address)
217 The peer address is actually the value of the pointer to the
218 CAGattService object containing the response characteristic.
220 uintptr_t s = (uintptr_t) NULL;
221 (void) sscanf(address, "&%" SCNxPTR, &s);
223 return (CAGattService *) s;
226 bool CAGattServiceInitialize(CAGattService * s,
227 char const * hci_name,
228 CALEContext * context)
231 assert(context != NULL);
232 assert(hci_name != NULL);
234 // Path of the form /org/iotivity/gatt/hci0/service0.
236 g_strdup_printf("%s/%s/%s",
237 CA_GATT_SERVICE_ROOT_PATH,
239 CA_GATT_SERVICE_PATH);
241 assert(g_variant_is_object_path(s->object_path));
243 s->object_manager = object_manager_skeleton_new();
244 s->service = gatt_service1_skeleton_new();
246 gatt_service1_set_uuid(s->service, CA_GATT_SERVICE_UUID);
247 gatt_service1_set_primary(s->service, TRUE);
249 if (!CAGattRequestCharacteristicInitialize(s, context)
250 || !CAGattResponseCharacteristicInitialize(s, context))
252 CAGattServiceDestroy(s);
257 The characteristic object paths are not fixed at compile-time.
258 Retrieve the object paths that were set at run-time.
260 char const * const characteristic_paths[] = {
261 s->request_characteristic.object_path,
262 s->response_characteristic.object_path,
266 gatt_service1_set_characteristics(s->service, characteristic_paths);
269 Set the org.freedesktop.DBus.ObjectManager.GetManagedObjects()
270 handler for our BlueZ GATT service.
274 "handle-get-managed-objects",
275 G_CALLBACK(CAGattServiceHandleGetManagedObjects),
279 BlueZ expects both the org.freedesktop.DBus.ObjectManager and
280 org.bluez.GattService1 interfaces to be rooted at the same
281 object path. Export the service and object manager interface
282 skeletons with the same object path.
284 GError * error = NULL;
285 if (!g_dbus_interface_skeleton_export(
286 G_DBUS_INTERFACE_SKELETON(s->object_manager),
290 || !g_dbus_interface_skeleton_export(
291 G_DBUS_INTERFACE_SKELETON(s->service),
298 "Unable to export GATT service interfaces: %s",
307 void CAGattServiceDestroy(CAGattService * s)
310 * @todo If necessary, emit the
311 * @c org.freedesktop.DBus.ObjectManager.InterfacesRemoved
312 * signal via @c object_manager_emit_interfaces_removed() if
313 * the CA GATT service objects were removed from the
317 assert(s != NULL); // As designed, s is always non-NULL.
319 g_clear_object(&s->gatt_manager);
321 CAGattCharacteristicDestroy(&s->response_characteristic);
322 CAGattCharacteristicDestroy(&s->request_characteristic);
324 g_clear_object(&s->service);
325 g_clear_object(&s->object_manager);
327 g_free(s->object_path);
328 s->object_path = NULL;