Imported Upstream version 1.0.0
[platform/upstream/iotivity.git] / resource / csdk / connectivity / src / bt_le_adapter / linux / service.c
1 /* ****************************************************************
2  *
3  * Copyright 2015 Intel Corporation All Rights Reserved.
4  *
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
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
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.
16  *
17  ******************************************************************/
18
19 #include "service.h"
20 #include "gatt_dbus.h"
21 #include "utils.h"
22 #include "bluez.h"
23
24 #include "cagattservice.h"
25 #include "logger.h"
26
27 #include <assert.h>
28
29
30 // Logging tag.
31 static char const TAG[] = "BLE_SERVICE";
32
33 static GVariant * CAGattServiceGetProperties(GattService1 * service)
34 {
35     /*
36       Create a variant containing the @c GattService1 properties, of
37       the form @c a{sa{sv}}.
38     */
39
40     /**
41      * Populate the property table, and create the variant to be
42      * embedded in the results of the
43      * @c org.freedesktop.Dbus.ObjectManager.GetManagedObjects()
44      * method call.
45      *
46      * The @c "Device" property is only available on the client side
47      * so we don't bother returning it here.
48      *
49      * @todo Do we care about the @c "Includes" property?
50      *       @c "Includes" isn't implemented by BlueZ as of version
51      *       5.30, so we can leave it out.
52     */
53     CADBusSkeletonProperty const properties[] = {
54         { "UUID",
55           g_variant_new_string(gatt_service1_get_uuid(service)) },
56         { "Primary",
57           g_variant_new_boolean(gatt_service1_get_primary(service)) },
58         { "Characteristics",
59           g_variant_new_objv(
60               gatt_service1_get_characteristics(service),
61               -1) }
62     };
63
64     return
65         CAMakePropertyDictionary(
66             BLUEZ_GATT_SERVICE_INTERFACE,
67             properties,
68             sizeof(properties) / sizeof(properties[0]));
69 }
70
71 /**
72  * Implementation of the
73  * @c org.freedesktop.DBus.ObjectManager.GetManagedObjects() method
74  * for the @c org.bluez.GattService1 interface.
75  */
76 static gboolean CAGattServiceHandleGetManagedObjects(
77     ObjectManager * object,
78     GDBusMethodInvocation * invocation,
79     gpointer user_data)
80 {
81     /**
82      * @note Ideally we shouldn't need this implementation, and should
83      *       be able to simply rely GDBusObjectManagerServer instead.
84      *       Unfortunately, BlueZ expects the @c
85      *       org.bluez.GattService1 object to implement the @c
86      *       ObjectManager interface, and both interfaces must rooted
87      *       at the same object path, as well.  That requirement
88      *       prevents us from using @c GDBusObjectManagerServer since
89      *       it won't allow us to export more than interface on a
90      *       given object path.
91      */
92
93     /*
94       Build the object array containing the IoTivity
95       org.bluez.GattService1 hierarchy.
96
97       a{oa{sa{sv}}}
98     */
99     CAGattService * const service = user_data;
100
101     GVariantBuilder builder;
102     g_variant_builder_init(&builder, G_VARIANT_TYPE("a{oa{sa{sv}}}"));
103
104     // Start out with the service itself.
105     g_variant_builder_add(&builder,
106                           "{o@a{sa{sv}}}",
107                           service->object_path,
108                           CAGattServiceGetProperties(service->service));
109
110     /*
111       Add the request characteristic and user description
112       descriptor.
113     */
114     CAGattCharacteristic * const request_chrc =
115         &service->request_characteristic;
116
117     g_variant_builder_add(&builder,
118                           "{o@a{sa{sv}}}",
119                           request_chrc->object_path,
120                           CAGattCharacteristicGetProperties(
121                               request_chrc->characteristic));
122
123     CAGattDescriptor * const request_desc = &request_chrc->descriptor;
124
125     g_variant_builder_add(&builder,
126                           "{o@a{sa{sv}}}",
127                           request_desc->object_path,
128                           CAGattDescriptorGetProperties(
129                               request_desc->descriptor));
130
131     /*
132       Add the response characteristic and user description
133       descriptor.
134     */
135     CAGattCharacteristic * const response_chrc =
136         &service->response_characteristic;
137
138     g_variant_builder_add(&builder,
139                           "{o@a{sa{sv}}}",
140                           response_chrc->object_path,
141                           CAGattCharacteristicGetProperties(
142                               response_chrc->characteristic));
143
144     CAGattDescriptor * const response_desc = &response_chrc->descriptor;
145
146     g_variant_builder_add(&builder,
147                           "{o@a{sa{sv}}}",
148                           response_desc->object_path,
149                           CAGattDescriptorGetProperties(
150                               response_desc->descriptor));
151
152     GVariant * const objects = g_variant_builder_end(&builder);
153
154     object_manager_complete_get_managed_objects(object,
155                                                 invocation,
156                                                 objects);
157
158     return TRUE;
159 }
160
161 bool CAGattServiceInitialize(CAGattService * s,
162                              CALEContext * context,
163                              char const * hci_name)
164 {
165     assert(s != NULL);
166     assert(context != NULL);
167     assert(hci_name != NULL);
168
169     // Path of the form /org/iotivity/gatt/hci0/service0.
170     s->object_path =
171         g_strdup_printf("%s/%s/%s",
172                         CA_GATT_SERVICE_ROOT_PATH,
173                         hci_name,
174                         CA_GATT_SERVICE_PATH);
175
176     assert(g_variant_is_object_path(s->object_path));
177
178     s->object_manager = object_manager_skeleton_new();
179     s->service = gatt_service1_skeleton_new();
180
181     gatt_service1_set_uuid(s->service, CA_GATT_SERVICE_UUID);
182     gatt_service1_set_primary(s->service, TRUE);
183
184     if (!CAGattRequestCharacteristicInitialize(s, context)
185         || !CAGattResponseCharacteristicInitialize(s, context))
186     {
187         CAGattServiceDestroy(s);
188         return false;
189     }
190
191     /*
192       The characteristic object paths are not fixed at compile-time.
193       Retrieve the object paths that were set at run-time.
194     */
195     char const * characteristic_paths[] = {
196         s->request_characteristic.object_path,
197         s->response_characteristic.object_path,
198         NULL
199     };
200
201     gatt_service1_set_characteristics(s->service, characteristic_paths);
202
203     /*
204       Set the org.freedesktop.DBus.ObjectManager.GetManagedObjects()
205       handler for our BlueZ GATT service.
206     */
207     g_signal_connect(
208         s->object_manager,
209         "handle-get-managed-objects",
210         G_CALLBACK(CAGattServiceHandleGetManagedObjects),
211         s);
212
213     /*
214       BlueZ expects both the org.freedesktop.DBus.ObjectManager and
215       org.bluez.GattService1 interfaces to be rooted at the same
216       object path.  Export the service and object manager interface
217       skeletons with the same object path.
218      */
219     GError * error = NULL;
220     if (!g_dbus_interface_skeleton_export(
221             G_DBUS_INTERFACE_SKELETON(s->object_manager),
222             context->connection,
223             s->object_path,
224             &error)
225         || !g_dbus_interface_skeleton_export(
226             G_DBUS_INTERFACE_SKELETON(s->service),
227             context->connection,
228             s->object_path,
229             &error))
230     {
231         OIC_LOG_V(ERROR,
232                   TAG,
233                   "Unable to export GATT service interfaces: %s",
234                   error->message);
235
236         return false;
237     }
238
239     return true;
240 }
241
242 void CAGattServiceDestroy(CAGattService * s)
243 {
244     /**
245      * @todo If necessary, emit the
246      *       @c org.freedesktop.DBus.ObjectManager.InterfacesRemoved
247      *       signal via @c object_manager_emit_interfaces_removed() if
248      *       the CA GATT service objects were removed from the
249      *       @c ObjectManager.
250      */
251
252     assert(s != NULL);  // As designed, s is always non-NULL.
253
254     g_clear_object(&s->gatt_manager);
255
256     CAGattCharacteristicDestroy(&s->response_characteristic);
257     CAGattCharacteristicDestroy(&s->request_characteristic);
258
259     g_clear_object(&s->service);
260     g_clear_object(&s->object_manager);
261
262     g_free(s->object_path);
263     s->object_path = NULL;
264 }