Update RD with latest master
[platform/upstream/iotivity.git] / resource / csdk / connectivity / src / bt_le_adapter / linux / client.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 "client.h"
20 #include "recv.h"
21 #include "context.h"
22 #include "bluez.h"
23 #include "utils.h"
24
25 #include "cafragmentation.h"
26 #include "logger.h"
27 #include "oic_malloc.h"
28 #include "oic_string.h"
29
30 #include <gio/gio.h>
31
32 #include <string.h>
33 #include <assert.h>
34
35
36 // Logging tag.
37 static char const TAG[] = "BLE_CLIENT";
38
39 // ---------------------------------------------------------------------
40 //                        GATT Client Set-up
41 // ---------------------------------------------------------------------
42 static bool CAGattClientServiceFilter(GDBusProxy * service)
43 {
44     /*
45       On the client side, we only care about the GATT services on
46       remote devices.  Ignore the locally created ones by checking for
47       the existence of the org.bluez.GattService1.Device property in
48       the service proxy.  GATT services on remote devices will have
49       that property.
50     */
51     GVariant * const remote_device =
52         g_dbus_proxy_get_cached_property(service, "Device");
53
54     if (remote_device == NULL)
55     {
56         return false;
57     }
58
59     /*
60       org.bluez.GattService1.Device property exists, meaning the
61       GATT service was advertised from a remote object.
62     */
63     g_object_unref(remote_device);
64     return true;
65 }
66
67 bool CAGattClientsInitialize(CALEContext * context)
68 {
69     /*
70       Create a proxies to the org.bluez.GattService1 D-Bus objects that
71       will later be used to send requests and receive responses on the
72       client side.
73     */
74     GList * services = NULL;
75     bool success =
76         CAGetBlueZManagedObjectProxies(&services,
77                                        BLUEZ_GATT_SERVICE_INTERFACE,
78                                        context,
79                                        CAGattClientServiceFilter);
80
81     /**
82      * @todo Is this really an error?
83      */
84     if (!success)
85     {
86         return success;
87     }
88
89     /*
90       Map Bluetooth MAC address to OIC Transport Profile
91       characteristics.
92     */
93     GHashTable * const characteristic_map =
94         g_hash_table_new_full(g_str_hash,
95                               g_str_equal,
96                               OICFree,
97                               g_object_unref);
98
99     char const * const address = NULL;  // OICMalloc(...);
100     GDBusProxy * const client = NULL;
101
102 #if GLIB_CHECK_VERSION(2,40,0)
103     /*
104       GLib hash table functions started returning a boolean result in
105        version 2.40.x.
106     */
107     success =
108 #endif
109         g_hash_table_insert(characteristic_map,
110                             OICStrdup(address),
111                             client);
112
113     // An empty services list is NULL.
114     if (success && services != NULL)
115     {
116         ca_mutex_lock(context->lock);
117         context->characteristic_map = characteristic_map;
118         ca_mutex_unlock(context->lock);
119     }
120
121     return success;
122 }
123
124 bool CAGattClientsDestroy(CALEContext * context)
125 {
126     (void)context;
127     /* g_hash_table_destroy(...); */   // FIXME
128     return false;
129 }
130
131 // ---------------------------------------------------------------------
132 //                        GATT Request Send
133 // ---------------------------------------------------------------------
134 /**
135  * Send data to the GATT server through the given request
136  * @a characteristic proxy.
137  *
138  * @param[in] characteristic The D-Bus proxy of the request
139  *                           characteristic through which the
140  *                           @c WriteValue() method will be invoked.
141  * @param[in] data           The byte array to be sent.
142  * @param[in] length         The number of elements in the byte
143  *                           array.
144  */
145 static bool CAGattClientSendRequestData(GDBusProxy * characteristic,
146                                         CALEContext * context,
147                                         uint8_t const * data,
148                                         size_t length)
149 {
150     assert(context != NULL);
151
152     GVariant * const value =
153         g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE,
154                                   data,
155                                   length,
156                                   1);  // sizeof(data[0]) == 1
157
158     GError * error = NULL;
159
160     GVariant * const ret =
161         g_dbus_proxy_call_sync(characteristic,
162                                "WriteValue",
163                                value,  // parameters
164                                G_DBUS_CALL_FLAGS_NONE,
165                                -1,    // timeout (default == -1),
166                                NULL,  // cancellable
167                                &error);
168
169     if (ret == NULL)
170     {
171         OIC_LOG_V(ERROR,
172                   TAG,
173                   "[%p] WriteValue() call failed: %s",
174                   characteristic,
175                   error->message);
176
177         g_error_free(error);
178
179         ca_mutex_lock(context->lock);
180
181         if (context->on_client_error != NULL)
182         {
183             /*
184               At this point endpoint and send data information is
185               available.
186             */
187             context->on_client_error(NULL,   // endpoint
188                                      data,
189                                      length,
190                                      CA_STATUS_FAILED);
191         }
192
193         ca_mutex_unlock(context->lock);
194
195         return false;
196     }
197
198     g_variant_unref(ret);
199
200     return true;
201 }
202
203 CAResult_t CAGattClientSendData(void const * method_info,
204                                 uint8_t const * data,
205                                 size_t length)
206 {
207     assert(method_info != NULL);
208
209     CAGattRequestInfo const * const info = method_info;
210
211     GDBusProxy * const characteristic =
212         G_DBUS_PROXY(info->characteristic_info);
213
214     return CAGattClientSendRequestData(characteristic,
215                                        info->context,
216                                        data,
217                                        length);
218 }
219
220 CAResult_t CAGattClientSendDataToAll(void const * method_info,
221                                      uint8_t const * data,
222                                      size_t length)
223 {
224     assert(method_info != NULL);
225
226     CAResult_t result = CA_STATUS_OK;
227
228     CAGattRequestInfo const * const info = method_info;
229
230     for (GList const * l = info->characteristic_info;
231          l != NULL && result == CA_STATUS_OK;
232          l = l->next)
233     {
234         GDBusProxy * const characteristic = G_DBUS_PROXY(l->data);
235
236         result = CAGattClientSendRequestData(characteristic,
237                                              info->context,
238                                              data,
239                                              length);
240     }
241
242     return result;
243 }
244
245 // ---------------------------------------------------------------------
246 //                      GATT Response Receive
247 // ---------------------------------------------------------------------
248 void CAGattReceiveResponse(GDBusConnection * connection,
249                            char const * sender_name,
250                            char const * object_path,
251                            char const * interface_name,
252                            char const * signal_name,
253                            GVariant   * parameters,
254                            gpointer     user_data)
255 {
256     (void)connection;
257     (void)sender_name;
258     (void)object_path;
259     (void)interface_name;
260     (void)signal_name;
261     /*
262       This handler is only trigged in a GATT client when receiving
263       data sent by a GATT server through a notification, e.g. such as
264       when a GATT server sent a response.
265     */
266     gsize fragment_len = 0;
267     gconstpointer const fragment =
268         g_variant_get_fixed_array(parameters,
269                                   &fragment_len,
270                                   1);  // sizeof(guchar) == 1
271
272     CAGattRecvInfo * const info = user_data;
273
274     if (CAGattRecv(info, fragment, fragment_len))
275     {
276     }
277     else
278     {
279     }
280 }