632240a23b2c87aeff27d16b71ad7d0c189fe515
[platform/upstream/iotivity.git] / resource / csdk / connectivity / src / bt_le_adapter / linux / caleinterface.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 "caleinterface.h"
20 #include "bluez.h"
21 #include "central.h"
22 #include "peripheral.h"
23 #include "client.h"
24 #include "server.h"
25 #include "utils.h"
26
27 #include "cagattservice.h"
28 #include "oic_malloc.h"
29 #include "oic_string.h"
30 #include "logger.h"
31
32 #include <string.h>
33 #include <strings.h>  // For strcasecmp().
34 #include <assert.h>
35
36
37 #define MICROSECS_PER_SEC 1000000
38
39 // Logging tag.
40 static char const TAG[] = "BLE_INTERFACE";
41
42 /*
43     The IoTivity adapter interface currently doesn't provide a means to
44     pass context down to the transport layer so rely on a file scope
45     context instead.
46 */
47 static CALEContext g_context = {
48     .lock = NULL
49 };
50
51 // -----------------------------------------------------------------------
52 // Functions internal to this BLE adapter implementation.
53 // -----------------------------------------------------------------------
54 static bool CALESetUpBlueZObjects(CALEContext * context);
55
56 static bool CALECheckStarted()
57 {
58     ca_mutex_lock(g_context.lock);
59
60     bool const started = (g_context.event_loop != NULL);
61
62     ca_mutex_unlock(g_context.lock);
63
64     /**
65      * @todo Fix potential TOCTOU race condition.  A LE transport
66      *       adapter could have been started or stopped between the
67      *       mutex unlock and boolean check.
68      */
69     return started;
70 }
71
72 static void CALEDumpDBusSignalParameters(char const * sender_name,
73                                          char const * object_path,
74                                          char const * interface_name,
75                                          char const * signal_name,
76                                          GVariant   * parameters)
77 {
78     (void)sender_name;
79     (void)object_path;
80     (void)interface_name;
81     (void)signal_name;
82     (void)parameters;
83 #ifdef TB_LOG
84     gchar * const param_dump =
85         g_variant_print(parameters, TRUE);
86
87     OIC_LOG_V(DEBUG,
88               TAG,
89               "%s()\n"
90               "\tsender_name: %s\n"
91               "\tobject_path: %s\n"
92               "\tinterface_name: %s\n"
93               "\tsignal_name: %s\n"
94               "\tparameters: %s\n",
95               __func__,
96               sender_name,
97               object_path,
98               interface_name,
99               signal_name,
100               param_dump);
101
102     g_free(param_dump);
103 #endif  // TB_LOG
104 }
105
106 static void CALEOnInterfaceProxyPropertiesChanged(
107     GDBusObjectManagerClient * manager,
108     GDBusObjectProxy         * object_proxy,
109     GDBusProxy               * interface_proxy,
110     GVariant                 * changed_properties,
111     gchar const * const      * invalidated_properties,
112     gpointer                   user_data)
113 {
114     (void)manager;
115     (void)object_proxy;
116     (void)invalidated_properties;
117     OIC_LOG_V(DEBUG,
118               TAG,
119               "Properties Changed on %s:\n",
120               g_dbus_object_get_object_path(
121                   G_DBUS_OBJECT(object_proxy)));
122
123     char const * const interface_name =
124         g_dbus_proxy_get_interface_name(interface_proxy);
125
126     bool const is_adapter_interface =
127         (strcmp(BLUEZ_ADAPTER_INTERFACE, interface_name) == 0);
128
129     if (!is_adapter_interface)
130     {
131         /*
132           Only specific org.bluez.Adapter1 property changes are
133           currently supported.
134         */
135         return;
136     }
137
138     CALEContext * const context = user_data;
139
140     GVariantIter iter;
141     gchar const * key   = NULL;
142     GVariant    * value = NULL;
143
144     g_variant_iter_init(&iter, changed_properties);
145     while (g_variant_iter_next(&iter, "{&sv}", &key, &value))
146     {
147         if (strcmp(key, "Powered") == 0)
148         {
149             /*
150               Report a change in the availability of the bluetooth
151               adapter.
152             */
153
154             gboolean const powered = g_variant_get_boolean(value);
155             CAAdapterState_t const status =
156                 (powered ? CA_ADAPTER_ENABLED : CA_ADAPTER_DISABLED);
157
158             CAEndpoint_t info =
159                 {
160                     .adapter = CA_ADAPTER_GATT_BTLE,
161                 };
162
163             GVariant * const prop =
164                 g_dbus_proxy_get_cached_property(interface_proxy,
165                                                  "Address");
166
167             gchar const * const address = g_variant_get_string(prop, NULL);
168
169             OICStrcpy(info.addr, sizeof(info.addr), address);
170
171             g_variant_unref(prop);
172
173             /**
174              * @todo Should we acquire the context lock here to
175              *       prevent the @c CALEDeviceStateChangedCallback
176              *       from being potentially yanked out from under us
177              *       if the CA adapters are stopped/terminated as
178              *       we're about to invoke this callback?
179              *
180              * @todo Unfortunately the CA LE interface defined in
181              *       caleinterface.h assumes that only one BLE adapter
182              *       will exist on a given host.  However, this
183              *       implementation can handle multiple BLE adapters.
184              *       The CA LE interface should be updated so that it
185              *       can handle multiple BLE adapters.
186              */
187             context->on_device_state_changed(status);
188         }
189
190 #ifdef TB_LOG
191         gchar * const s = g_variant_print(value, TRUE);
192         OIC_LOG_V(DEBUG, TAG, "  %s -> %s", key, s);
193         g_free(s);
194 #endif  // TB_LOG
195
196         g_variant_unref(value);
197     }
198 }
199
200 static void CALEHandleInterfaceAdded(GList ** proxy_list,
201                                      char const * interface,
202                                      GVariant * parameters)
203 {
204     /**
205      * @note The @a parameters are of the form "(oa{sv})".
206      */
207     GDBusProxy * const proxy =
208         CAGetBlueZInterfaceProxy(parameters,
209                                  interface,
210                                  g_context.object_manager);
211
212     if (proxy == NULL)
213     {
214         return;
215     }
216
217     ca_mutex_lock(g_context.lock);
218
219     /*
220       Add the object information to the list.
221
222       Note that we prepend instead of append in this case since it
223       is more efficient to do so for linked lists like the one used
224       here.
225     */
226     *proxy_list = g_list_prepend(*proxy_list, proxy);
227
228     ca_mutex_unlock(g_context.lock);
229
230     /**
231      * Let the thread that may be blocked waiting for Devices to be
232      * discovered know that at least one was found.
233      *
234      * @todo It doesn't feel good putting this @c org.bluez.Device1
235      *       specific code here since this function is meant to be
236      *       BlueZ interface neutral.  Look into ways of moving this
237      *       out of here.
238      */
239     if (strcmp(interface, BLUEZ_DEVICE_INTERFACE) == 0)
240     {
241         ca_cond_signal(g_context.condition);
242     }
243 }
244
245 static void CALEOnInterfacesAdded(GDBusConnection * connection,
246                                   char const * sender_name,
247                                   char const * object_path,
248                                   char const * interface_name,
249                                   char const * signal_name,
250                                   GVariant   * parameters,
251                                   gpointer     user_data)
252 {
253     (void)connection;
254     (void)user_data;
255     CALEDumpDBusSignalParameters(sender_name,
256                                  object_path,
257                                  interface_name,
258                                  signal_name,
259                                  parameters);
260
261     // The signal should always be InterfacesAdded.
262     assert(strcmp(signal_name, "InterfacesAdded") == 0);
263
264     // Handle addition of a new org.bluez.Adapter1 interface.
265     CALEHandleInterfaceAdded(&g_context.adapters,
266                              BLUEZ_ADAPTER_INTERFACE,
267                              parameters);
268
269     // Handle addition of a new org.bluez.Device1 interface.
270     CALEHandleInterfaceAdded(&g_context.devices,
271                              BLUEZ_DEVICE_INTERFACE,
272                              parameters);
273 }
274
275 static void CALEOnInterfacesRemoved(GDBusConnection * connection,
276                                     char const * sender_name,
277                                     char const * object_path,
278                                     char const * interface_name,
279                                     char const * signal_name,
280                                     GVariant   * parameters,
281                                     gpointer     user_data)
282 {
283     (void)connection;
284     (void)user_data;
285     CALEDumpDBusSignalParameters(sender_name,
286                                  object_path,
287                                  interface_name,
288                                  signal_name,
289                                  parameters);
290
291     // The signal should always be InterfacesRemoved.
292     assert(strcmp(signal_name, "InterfacesRemoved") == 0);
293
294     /*
295       The object path is first tuple element, and the interface names
296       the second.  Check if "org.bluez.Adapter1" exists in the
297       interface array.  If it does, remove the corresponding
298       information from the adapter_infos list.
299     */
300     GVariant * const interfaces =
301         g_variant_get_child_value(parameters, 1);
302
303     GVariantIter * iter = NULL;
304     g_variant_get(interfaces, "as", &iter);
305
306     /**
307      * Iterate over the array and remove all BlueZ interface proxies
308      * with a matching D-Bus object path from the corresponding list.
309      *
310      * @todo Determine whether we should optimize this nested loop.
311      *       It may not be worthwhile to do so since the lists being
312      *       iterated over should be very short.
313      */
314     for (GVariant * child = g_variant_iter_next_value(iter);
315          child != NULL;
316          child = g_variant_iter_next_value(iter))
317     {
318         char const * interface = NULL;
319         g_variant_get(child, "&s", &interface);
320
321         GList ** list = NULL;
322
323         if (strcmp(interface, BLUEZ_ADAPTER_INTERFACE) == 0)
324         {
325             list = &g_context.adapters;
326         }
327         else if (strcmp(interface, BLUEZ_DEVICE_INTERFACE) == 0)
328         {
329             list = &g_context.devices;
330         }
331         else
332         {
333             continue;
334         }
335
336         // The object path is the first tuple element.
337         gchar const * path = NULL;
338         g_variant_get_child(parameters, 0, "&o", &path);
339
340         ca_mutex_lock(g_context.lock);
341
342         for (GList * l = *list; l != NULL; l = g_list_next(l))
343         {
344             GDBusProxy * const proxy = G_DBUS_PROXY(l->data);
345
346             if (strcmp(path,
347                        g_dbus_proxy_get_object_path(proxy)) == 0)
348             {
349                 // Found a match!
350                 g_object_unref(proxy);
351
352                 *list = g_list_delete_link(*list, l);
353
354                 break;
355             }
356         }
357
358         ca_mutex_unlock(g_context.lock);
359
360         g_variant_unref(child);
361     }
362
363     if (iter != NULL)
364     {
365         g_variant_iter_free(iter);
366     }
367 }
368
369 static void CALEOnPropertiesChanged(GDBusConnection * connection,
370                                     char const * sender_name,
371                                     char const * object_path,
372                                     char const * interface_name,
373                                     char const * signal_name,
374                                     GVariant   * parameters,
375                                     gpointer     user_data)
376 {
377     (void)connection;
378     (void)user_data;
379     CALEDumpDBusSignalParameters(sender_name,
380                                  object_path,
381                                  interface_name,
382                                  signal_name,
383                                  parameters);
384 }
385
386 static void CALEOnPropertyChanged(GDBusConnection * connection,
387                                   char const * sender_name,
388                                   char const * object_path,
389                                   char const * interface_name,
390                                   char const * signal_name,
391                                   GVariant   * parameters,
392                                   gpointer     user_data)
393 {
394     (void)connection;
395     (void)user_data;
396     CALEDumpDBusSignalParameters(sender_name,
397                                  object_path,
398                                  interface_name,
399                                  signal_name,
400                                  parameters);
401 }
402
403 static void CALESubscribeToSignals(CALEContext * context,
404                                    GDBusConnection * connection,
405                                    GDBusObjectManager * object_manager)
406 {
407     static char const om_interface[] =
408         "org.freedesktop.DBus.ObjectManager";
409
410     /*
411       Subscribe to D-Bus signals that will allow us to detect changes
412       in BlueZ adapter and device properties.
413      */
414     guint const interfaces_added_sub_id =
415         g_dbus_connection_signal_subscribe(
416             connection,
417             NULL,  // sender
418             om_interface,
419             "InterfacesAdded",
420             NULL,  // object path
421             NULL,  // arg0
422             G_DBUS_SIGNAL_FLAGS_NONE,
423             CALEOnInterfacesAdded,
424             NULL,  // user_data
425             NULL);
426
427     guint const interfaces_removed_sub_id =
428         g_dbus_connection_signal_subscribe(
429             connection,
430             NULL,  // sender
431             om_interface,
432             "InterfacesRemoved",
433             NULL,  // object path
434             NULL,  // arg0
435             G_DBUS_SIGNAL_FLAGS_NONE,
436             CALEOnInterfacesRemoved,
437             NULL,  // user_data
438             NULL);
439
440 #if GLIB_CHECK_VERSION(2,38,0)
441     /*
442       The G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH flag was introduced in
443       GLib 2.38.
444     */
445     static GDBusSignalFlags const device_signal_flags =
446         G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH;
447 #else
448     static GDBusSignalFlags const device_signal_flags =
449         G_DBUS_SIGNAL_FLAGS_NONE;
450 #endif
451
452     /**
453      * @todo Verify that this signal subscription is needed.
454      *
455      * @bug The arg0 argument below should be a D-Bus object path, not
456      *      interface name.
457      */
458     guint const properties_changed_sub_id =
459         g_dbus_connection_signal_subscribe(
460             connection,
461             NULL,  // sender
462             "org.freedesktop.DBus.Properties",
463             "PropertiesChanged",
464             NULL,  // object path
465             "org.bluez.Device1",  // arg0
466             device_signal_flags,
467             CALEOnPropertiesChanged,
468             NULL,  // user_data
469             NULL);
470
471     /**
472      * @todo Verify that this signal subscription is needed.
473      */
474     guint const property_changed_sub_id =
475         g_dbus_connection_signal_subscribe(connection,
476                                            NULL,  // sender
477                                            BLUEZ_ADAPTER_INTERFACE,
478                                            "PropertyChanged",
479                                            NULL,  // object path
480                                            NULL,  // arg0
481                                            G_DBUS_SIGNAL_FLAGS_NONE,
482                                            CALEOnPropertyChanged,
483                                            NULL,  // user_data
484                                            NULL);
485
486     g_signal_connect(object_manager,
487                      "interface-proxy-properties-changed",
488                      G_CALLBACK(CALEOnInterfaceProxyPropertiesChanged),
489                      context);
490
491     ca_mutex_lock(context->lock);
492
493     context->interfaces_added_sub_id   = interfaces_added_sub_id;
494     context->interfaces_removed_sub_id = interfaces_removed_sub_id;
495     context->properties_changed_sub_id = properties_changed_sub_id;
496     context->property_changed_sub_id   = property_changed_sub_id;
497
498     ca_mutex_unlock(context->lock);
499 }
500
501 static bool CALESetUpDBus(CALEContext * context)
502 {
503     assert(context != NULL);
504
505     bool success = false;
506
507     GError * error = NULL;
508
509     /*
510       Set up connection to the D-Bus system bus, where the BlueZ
511       daemon is found.
512     */
513     GDBusConnection * const connection =
514         g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
515
516     if (connection == NULL)
517     {
518         OIC_LOG_V(ERROR,
519                   TAG,
520                   "Connection to D-Bus system bus failed: %s.",
521                   error->message);
522
523         g_error_free(error);
524
525         return success;
526     }
527
528     // Create a proxy to the BlueZ D-Bus ObjectManager.
529     static char const object_manager_path[] = "/";
530
531     GDBusObjectManager * const object_manager =
532         g_dbus_object_manager_client_new_sync(
533             connection,
534             G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
535             BLUEZ_NAME,
536             object_manager_path,
537             NULL,   // get_proxy_type_func
538             NULL,   // get_proxy_type_user_data
539             NULL,   // get_proxy_type_destroy_notify
540             NULL,   // cancellable
541             &error);
542
543     if (object_manager == NULL)
544     {
545         OIC_LOG_V(ERROR,
546                   TAG,
547                   "Unable to create D-Bus ObjectManager client: %s",
548                   error->message);
549
550         g_error_free(error);
551
552         g_object_unref(connection);
553
554         return success;
555     }
556
557     CALESubscribeToSignals(context, connection, object_manager);
558
559     ca_mutex_lock(context->lock);
560     context->connection     = connection;
561     context->object_manager = object_manager;
562     ca_mutex_unlock(context->lock);
563
564     success = CALESetUpBlueZObjects(context);
565
566     return success;
567 }
568
569 static void CALETearDownDBus(CALEContext * context)
570 {
571     assert(context != NULL);
572
573     /*
574       Minimize the time we hold the global lock by only clearing the
575       global state, and pushing resource finalization outside the global
576       lock.
577     */
578     ca_mutex_lock(context->lock);
579
580     GDBusConnection * const connection = context->connection;
581     context->connection = NULL;
582
583     GDBusObjectManager * const object_manager = context->object_manager;
584     context->object_manager = NULL;
585
586     GList * const objects = context->objects;
587     context->objects = NULL;
588
589     GList * const adapters = context->adapters;
590     context->adapters = NULL;
591
592     GList * const devices = context->devices;
593     context->devices = NULL;
594
595     guint const interfaces_added   = context->interfaces_added_sub_id;
596     guint const interfaces_removed = context->interfaces_removed_sub_id;
597     guint const properties_changed = context->properties_changed_sub_id;
598     guint const property_changed   = context->property_changed_sub_id;
599
600     context->interfaces_added_sub_id   = 0;
601     context->interfaces_removed_sub_id = 0;
602     context->properties_changed_sub_id = 0;
603     context->property_changed_sub_id   = 0;
604
605     ca_mutex_unlock(context->lock);
606
607     // Destroy the device proxies list.
608     g_list_free_full(devices, g_object_unref);
609
610     // Destroy the adapter proxies list.
611     g_list_free_full(adapters, g_object_unref);
612
613     // Destroy the list of objects obtained from the ObjectManager.
614     g_list_free_full(objects, g_object_unref);
615
616     // Destroy the ObjectManager proxy.
617     if (object_manager != NULL)
618     {
619         g_object_unref(object_manager);
620     }
621
622     // Tear down the D-Bus connection to the system bus.
623     if (connection != NULL)
624     {
625         g_dbus_connection_signal_unsubscribe(connection,
626                                              interfaces_added);
627         g_dbus_connection_signal_unsubscribe(connection,
628                                              interfaces_removed);
629         g_dbus_connection_signal_unsubscribe(connection,
630                                              properties_changed);
631         g_dbus_connection_signal_unsubscribe(connection,
632                                              property_changed);
633         g_object_unref(connection);
634     }
635 }
636
637 static bool CALEDeviceFilter(GDBusProxy * device)
638 {
639     bool accepted = false;
640
641     /*
642       Filter out any devices that don't support the OIC Transport
643       Profile service.
644     */
645     GVariant * const prop =
646         g_dbus_proxy_get_cached_property(device, "UUIDs");
647
648     if (prop == NULL)
649     {
650         // No remote services available on the device.
651         return accepted;
652     }
653
654     gsize length = 0;
655     char const ** const UUIDs = g_variant_get_strv(prop, &length);
656
657     /*
658       It would have been nice to use g_strv_contains() here, but we
659       would need to run it twice: once for the uppercase form of the
660       UUID and once for for the lowercase form.  Just run the loop
661       manually, and use strcasecmp() instead.
662     */
663     char const * const * const end = UUIDs + length;
664     for (char const * const * u = UUIDs; u != end; ++u)
665     {
666         if (strcasecmp(*u, CA_GATT_SERVICE_UUID) == 0)
667         {
668             accepted = true;
669             break;
670         }
671     }
672
673     g_free(UUIDs);
674     g_variant_unref(prop);
675
676     return accepted;
677 }
678
679
680 static bool CALESetUpBlueZObjects(CALEContext * context)
681 {
682     bool success = false;
683
684     // Get the list of BlueZ D-Bus objects.
685     GList * const objects =
686         g_dbus_object_manager_get_objects(context->object_manager);
687
688     if (objects == NULL) {
689         OIC_LOG(ERROR,
690                 TAG,
691                 "Unable to get objects from ObjectManager.");
692
693         return success;
694     }
695
696     ca_mutex_lock(context->lock);
697     context->objects = objects;
698     ca_mutex_unlock(context->lock);
699
700     /*
701       Create a proxies to the org.bluez.Adapter1 D-Bus objects that
702       will later be used to obtain local bluetooth adapter properties,
703       as well as by the BLE central code to discover peripherals.
704     */
705     GList * adapters = NULL;
706     success = CAGetBlueZManagedObjectProxies(&adapters,
707                                              BLUEZ_ADAPTER_INTERFACE,
708                                              context,
709                                              NULL);
710
711     // An empty adapters list is NULL.
712     if (success && adapters != NULL)
713     {
714         ca_mutex_lock(context->lock);
715         context->adapters = adapters;
716         ca_mutex_unlock(context->lock);
717     }
718
719     /*
720       Create a proxies to the org.bluez.Device1 D-Bus objects that
721       will later be used to establish connections.
722     */
723     GList * devices = NULL;
724     success = CAGetBlueZManagedObjectProxies(&devices,
725                                              BLUEZ_DEVICE_INTERFACE,
726                                              context,
727                                              CALEDeviceFilter);
728
729     // An empty device list is NULL.
730     if (success && devices != NULL)
731     {
732         ca_mutex_lock(context->lock);
733         context->devices = devices;
734         ca_mutex_unlock(context->lock);
735     }
736
737     /* success = CAGattClientInitialize(context); */
738
739     return success;
740 }
741
742 static void CALEStartEventLoop(void * data)
743 {
744     CALEContext * const context = data;
745
746     assert(context != NULL);
747
748     // Create the event loop.
749     GMainContext * const loop_context = g_main_context_new();
750     GMainLoop * const event_loop = g_main_loop_new(loop_context, FALSE);
751
752     ca_mutex_lock(context->lock);
753
754     assert(context->event_loop == NULL);
755     context->event_loop = event_loop;
756
757     ca_mutex_unlock(context->lock);
758
759     g_main_context_push_thread_default(loop_context);
760
761     /*
762       We have to do the BlueZ object manager client initialization and
763       signal subscription here so that the corresponding asynchronous
764       signal handling occurs in the same thread as the one running the
765       GLib event loop.
766     */
767     if (!CALESetUpDBus(&g_context))
768         return;
769
770     ca_cond_signal(g_context.condition);
771
772     g_main_loop_run(event_loop);
773 }
774
775 static void CALEStopEventLoop(CALEContext * context)
776 {
777     ca_mutex_lock(context->lock);
778
779     GMainLoop * const event_loop = context->event_loop;
780     context->event_loop = NULL;
781
782     ca_mutex_unlock(context->lock);
783
784     if (event_loop != NULL)
785     {
786         g_main_loop_quit(event_loop);
787
788         GMainContext * const loop_context =
789             g_main_loop_get_context(event_loop);
790
791         if (loop_context != NULL)
792         {
793             g_main_context_wakeup(loop_context);
794             g_main_context_unref(loop_context);
795         }
796
797         g_main_loop_unref(event_loop);
798     }
799 }
800
801 /**
802  * Wait for @a list to be non-empty.
803  *
804  * @param[in] list    List that should not be empty.
805  * @param[in] retries Number of times to retry if the @a timeout is
806  *                    reached.
807  * @param[in] timeout Timeout in microseconds to wait between retries.
808  */
809 static bool CALEWaitForNonEmptyList(GList * const * list,
810                                     int retries,
811                                     uint64_t timeout)
812 {
813     bool success = false;
814
815     ca_mutex_lock(g_context.lock);
816
817     for (int i = 0; *list == NULL && i < retries; ++i)
818     {
819         if (ca_cond_wait_for(g_context.condition,
820                              g_context.lock,
821                              timeout) == 0)
822         {
823             /*
824               Condition variable was signaled before the timeout was
825               reached.
826             */
827             success = true;
828         }
829     }
830
831     ca_mutex_unlock(g_context.lock);
832
833     return success;
834 }
835
836 static CAResult_t CALEStop()
837 {
838     CAResult_t result = CA_STATUS_FAILED;
839
840     OIC_LOG(DEBUG, TAG, "Stop Linux BLE adapter.");
841
842     // Only stop if we were previously started.
843     if (!CALECheckStarted())
844     {
845         return result;
846     }
847
848     // Stop the event loop thread regardless of previous errors.
849     CALEStopEventLoop(&g_context);
850
851     CALETearDownDBus(&g_context);
852
853     return result;
854 }
855
856 static void CALETerminate()
857 {
858     OIC_LOG(DEBUG, TAG, "Terminate BLE adapter.");
859
860     CAPeripheralFinalize();
861
862     ca_mutex_lock(g_context.lock);
863
864     g_context.on_device_state_changed = NULL;
865     g_context.on_server_received_data = NULL;
866     g_context.on_client_received_data = NULL;
867     g_context.client_thread_pool      = NULL;
868     g_context.server_thread_pool      = NULL;
869     g_context.on_client_error         = NULL;
870     g_context.on_server_error         = NULL;
871
872     ca_mutex_unlock(g_context.lock);
873
874     ca_cond_free(g_context.condition);
875     ca_mutex_free(g_context.lock);
876 }
877
878 // -----------------------------------------------------------------------
879
880 CAResult_t CAInitializeLEAdapter()
881 {
882 #if !GLIB_CHECK_VERSION(2,36,0)
883     /*
884       Initialize the GLib type system.
885
886       As of GLib 2.36, it is no longer necessary to explicitly call
887       g_type_init().
888     */
889     g_type_init();
890 #endif
891
892     g_context.lock      = ca_mutex_new();
893     g_context.condition = ca_cond_new();
894
895     CAPeripheralInitialize();
896
897     return CA_STATUS_OK;
898 }
899
900 CAResult_t CAStartLEAdapter()
901 {
902     /*
903       This function is called by the connectivity abstraction when
904       CASelectNetwork(CA_ADAPTER_GATT_BTLE) is called by the user.
905     */
906
907     OIC_LOG(DEBUG, TAG, __func__);
908
909     CAResult_t result = CA_STATUS_FAILED;
910
911     // Only start if we were previously stopped.
912     if (CALECheckStarted())
913     {
914       return result;
915     }
916
917     /**
918      * Spawn a thread to run the GLib event loop that will drive D-Bus
919      * signal handling.
920      *
921      * @note Ideally this should be done in the @c CAInitializeLE()
922      *       function so that we can detect local bluetooth adapter
923      *       changes right away, without having to first start this LE
924      *       adapter/transport via @cCASelectNetwork().  However, a
925      *       limitation in the CA termination code that destroys the
926      *       thread pool before the transport adapters prevents us
927      *       from doing that without potentially triggering a
928      *       @c pthread_join() call that blocks indefinitely due to
929      *       this event loop not be stopped.  See the comments in the
930      *       @c CAGetLEInterfaceInformation() function below for
931      *       further details.
932      */
933     result = ca_thread_pool_add_task(g_context.client_thread_pool,
934                                      CALEStartEventLoop,
935                                      &g_context);
936
937     if (result != CA_STATUS_OK)
938     {
939         return result;
940     }
941
942     /*
943       Wait until initialization completes before continuing, basically
944       until some Bluetooth adapters were found.
945     */
946
947     // Number of times to wait for initialization to complete.
948     static int const retries = 2;
949
950     static uint64_t const timeout =
951         2 * MICROSECS_PER_SEC;  // Microseconds
952
953     if (CALEWaitForNonEmptyList(&g_context.adapters, retries, timeout))
954     {
955         result = CA_STATUS_OK;
956     }
957
958     return result;
959 }
960
961 CAResult_t CAGetLEAdapterState()
962 {
963     /**
964      * @todo To be implemented shortly as part of the effort to
965      *       address a critical code review that stated this BLE
966      *       transport should implement the interface defined in
967      *       caleinterface.h.
968      */
969     return CA_NOT_SUPPORTED;
970 }
971
972 CAResult_t CAInitializeLENetworkMonitor()
973 {
974     /**
975      * @todo To be implemented shortly as part of the effort to
976      *       address a critical code review that stated this BLE
977      *       transport should implement the interface defined in
978      *       caleinterface.h.
979      */
980     return CA_STATUS_OK;
981 }
982
983 void CATerminateLENetworkMonitor()
984 {
985     /**
986      * @todo To be implemented shortly as part of the effort to
987      *       address a critical code review that stated this BLE
988      *       transport should implement the interface defined in
989      *       caleinterface.h.
990      */
991 }
992
993 CAResult_t CASetLEAdapterStateChangedCb(CALEDeviceStateChangedCallback callback)
994 {
995     ca_mutex_lock(g_context.lock);
996     g_context.on_device_state_changed = callback;
997     ca_mutex_unlock(g_context.lock);
998
999     return CA_STATUS_OK;
1000 }
1001
1002 CAResult_t CAInitLENetworkMonitorMutexVariables()
1003 {
1004     /*
1005       This CA LE interface implementation doesn't use a network
1006       monitor as the other platform implementationd do.
1007     */
1008     return CA_STATUS_OK;
1009 }
1010
1011 void CATerminateLENetworkMonitorMutexVariables()
1012 {
1013     /*
1014       This CA LE interface implementation doesn't use a network
1015       monitor as the other platform implementationd do.
1016     */
1017 }
1018
1019 CAResult_t CAGetLEAddress(char **local_address)
1020 {
1021     OIC_LOG(DEBUG, TAG, "Get Linux BLE local device information.");
1022
1023     if (local_address == NULL)
1024     {
1025         return CA_STATUS_INVALID_PARAM;
1026     }
1027
1028     /**
1029      * @bug Attempting to get LE interface information before this
1030      *      connectivity abstraction adapter has started (e.g. via
1031      *      @c CASelectNetwork()) could result in an inaccurate list
1032      *      of LE interfaces.  For example, detection of hot-plugged
1033      *      bluetooth adapters will only work after the LE IoTivity
1034      *      network has been selected.  If the LE IoTivity network
1035      *      hasn't been selected, the hot-plugged bluetooth adapter
1036      *      will not be reflected in the @c CALocalConnectivity_t list
1037      *      returned by this function.
1038      *      @par
1039      *      This issue caused by the fact that the event loop that
1040      *      handles such events can only be run after this LE
1041      *      adapter/transport is started.  The event loop cannot be
1042      *      started earlier, e.g. during @c CAInitialize(), due to a
1043      *      limitation in the CA transport termination code that
1044      *      requires thread pools to be destroyed before transport
1045      *      termination.  If the event loop was added as a task to the
1046      *      thread pool during @c CAInitialize(), it's possible that
1047      *      the thread running that event loop could be blocked
1048      *      waiting for events during a later call to
1049      *      @c CATerminate() if @c CASelectNetwork() was not called
1050      *      beforehand.  The thread pool destruction that occurs
1051      *      during @c CATerminate() waits for threads in the pool to
1052      *      exit.  However, in this case the event loop thread is
1053      *      still blocked waiting for events since it may not have
1054      *      been stopped since the transport itself was not stopped,
1055      *      meaning termination will also be blocked.
1056      *      @par
1057      *      Other than refactoring to the termination code to allow
1058      *      thread pools to be started during @c CAInitialize(), the
1059      *      only other choice we have to prevent the hang at
1060      *      termination is to move the event loop creation and
1061      *      termination to the @c CAAdapterStart() and
1062      *      @c CAAdapterStop() implementations, respectively, which is
1063      *      why we have this bug.
1064      */
1065     if (!CALECheckStarted())
1066       return CA_ADAPTER_NOT_ENABLED;
1067
1068     *local_address = NULL;
1069
1070     ca_mutex_lock(g_context.lock);
1071
1072     for (GList * l = g_context.adapters; l != NULL; l = l->next)
1073     {
1074         GDBusProxy * const adapter = G_DBUS_PROXY(l->data);
1075
1076         /*
1077           The local bluetooth adapter MAC address is stored in the
1078           org.bluez.Adapter1.Address property.
1079         */
1080         GVariant * const prop =
1081             g_dbus_proxy_get_cached_property(adapter, "Address");
1082
1083         /*
1084           Unless the org.bluez.Adapter1.Address property no longer
1085           exists, prop should not be NULL!  We have bigger problems if
1086           this assert() is ever tripped since that would mean the
1087           org.bluez.Adapter1 D-Bus interface changed.
1088         */
1089         assert(prop != NULL);
1090
1091         gchar const * const address = g_variant_get_string(prop, NULL);
1092
1093         *local_address = OICStrdup(address);
1094
1095         /*
1096           No longer need the property variant.  The address has been
1097           copied.
1098         */
1099         g_variant_unref(prop);
1100
1101         /**
1102          * @todo Unfortunately the CA LE interface defined in
1103          *       caleinterface.h assumes that only one BLE adapter
1104          *       will exist on a given host.  However, this
1105          *       implementation can handle multiple BLE adapters.  The
1106          *       CA LE interface should be updated so that it can
1107          *       handle multiple BLE adapters.  For now we'll just
1108          *       return the address for the first BLE adapter in the
1109          *       list.
1110          */
1111         break;
1112     }
1113
1114     ca_mutex_unlock(g_context.lock);
1115
1116     return *local_address != NULL ? CA_STATUS_OK : CA_STATUS_FAILED;
1117 }
1118
1119 CAResult_t CAStartLEGattServer()
1120 {
1121     return CAPeripheralStart(&g_context);
1122 }
1123
1124 CAResult_t CAStopLEGattServer()
1125 {
1126     CAResult_t result    = CAPeripheralStop();
1127     CAResult_t const tmp = CALEStop();
1128
1129     if (result == CA_STATUS_OK && tmp != CA_STATUS_OK)
1130     {
1131         result = tmp;
1132     }
1133
1134     return result;
1135 }
1136
1137 void CATerminateLEGattServer()
1138 {
1139     CALETerminate();
1140 }
1141
1142 void CASetLEReqRespServerCallback(CABLEDataReceivedCallback callback)
1143 {
1144     ca_mutex_lock(g_context.lock);
1145     g_context.on_server_received_data = callback;
1146     ca_mutex_unlock(g_context.lock);
1147 }
1148
1149 CAResult_t CAUpdateCharacteristicsToGattClient(char const * address,
1150                                                uint8_t const * value,
1151                                                uint32_t valueLen)
1152 {
1153     (void)address;
1154     (void)value;
1155     (void)valueLen;
1156     /**
1157      * @todo To be implemented shortly as part of the effort to
1158      *       address a critical code review that stated this BLE
1159      *       transport should implement the interface defined in
1160      *       caleinterface.h.
1161      */
1162     return CA_NOT_SUPPORTED;
1163 }
1164
1165 CAResult_t CAUpdateCharacteristicsToAllGattClients(uint8_t const * value,
1166                                                    uint32_t valueLen)
1167 {
1168     (void)value;
1169     (void)valueLen;
1170     /**
1171      * @todo To be implemented shortly as part of the effort to
1172      *       address a critical code review that stated this BLE
1173      *       transport should implement the interface defined in
1174      *       caleinterface.h.
1175      */
1176     return CA_NOT_SUPPORTED;
1177 }
1178
1179 CAResult_t CAStartLEGattClient()
1180 {
1181     return CACentralStart(&g_context);
1182 }
1183
1184 void CAStopLEGattClient()
1185 {
1186     (void) CACentralStop(&g_context);
1187     (void) CALEStop();
1188 }
1189
1190 void CATerminateLEGattClient()
1191 {
1192     CALETerminate();
1193 }
1194
1195 void CACheckLEData()
1196 {
1197     /*
1198       This function is only used in single-threaded builds, but this
1199       CA LE adapter implementation is multi-threaded.  Consequently,
1200       this function is a no-op.
1201      */
1202 }
1203
1204 CAResult_t CAUpdateCharacteristicsToGattServer(
1205     char const * remoteAddress,
1206     uint8_t const * data,
1207     uint32_t dataLen,
1208     CALETransferType_t type,
1209     int32_t position)
1210 {
1211     (void)remoteAddress;
1212     (void)data;
1213     (void)dataLen;
1214     (void)type;
1215     (void)position;
1216     /**
1217      * @todo To be implemented shortly as part of the effort to
1218      *       address a critical code review that stated this BLE
1219      *       transport should implement the interface defined in
1220      *       caleinterface.h.
1221      */
1222     return CA_NOT_SUPPORTED;
1223 }
1224
1225 CAResult_t CAUpdateCharacteristicsToAllGattServers(uint8_t const * data,
1226                                                    uint32_t length)
1227 {
1228     OIC_LOG(DEBUG, TAG, "Send data to all");
1229
1230     /*
1231       Multicast data is only sent when a request is sent from a client
1232       across all endpoints.  We need not worry about sending a
1233       response from a server here.
1234     */
1235
1236     CAResult_t result = CA_STATUS_FAILED;
1237
1238     ca_mutex_lock(g_context.lock);
1239     bool found_peripherals = (g_context.devices != NULL);
1240     ca_mutex_unlock(g_context.lock);
1241
1242     if (!found_peripherals)
1243     {
1244         /*
1245           Start discovery of LE peripherals that advertise the OIC
1246           Transport Profile.
1247         */
1248         result = CACentralStartDiscovery(&g_context);
1249
1250         if (result != CA_STATUS_OK)
1251         {
1252             return -1;
1253         }
1254
1255         // Wait for LE peripherals to be discovered.
1256
1257         // Number of times to wait for discovery to complete.
1258         static int const retries = 5;
1259
1260         static uint64_t const timeout =
1261             2 * MICROSECS_PER_SEC;  // Microseconds
1262
1263         if (!CALEWaitForNonEmptyList(&g_context.devices,
1264                                      retries,
1265                                      timeout))
1266         {
1267             return -1;
1268         }
1269
1270         ca_mutex_lock(g_context.lock);
1271         found_peripherals = (g_context.devices == NULL);
1272         ca_mutex_unlock(g_context.lock);
1273
1274         if (!found_peripherals)
1275         {
1276             // No peripherals discovered!
1277             return -1;
1278         }
1279     }
1280
1281     /*
1282       Stop discovery so that we can connect to LE peripherals.
1283       Otherwise, the bluetooth subsystem will claim the adapter is
1284       busy.
1285     */
1286
1287     result = CACentralStopDiscovery(&g_context);
1288
1289     if (result != CA_STATUS_OK)
1290     {
1291         return -1;
1292     }
1293
1294     bool const connected = CACentralConnectToAll(&g_context);
1295
1296     if (!connected)
1297     {
1298         return -1;
1299     }
1300
1301     /**
1302      * @todo Start notifications on all response characteristics.
1303      */
1304
1305     /*
1306       Now send the request through all BLE connections through the
1307       corresponding OIC GATT request characterstics.
1308     */
1309
1310     CAGattRequestInfo const info =
1311         {
1312             .characteristic_info = NULL,  // g_context.characteristics
1313             .context = &g_context
1314         };
1315
1316     return CAGattClientSendDataToAll(&info, data, length);
1317
1318     /**
1319      * @todo Should we restart discovery after the send?
1320      */
1321 }
1322
1323 void CASetLEReqRespClientCallback(CABLEDataReceivedCallback callback)
1324 {
1325     ca_mutex_lock(g_context.lock);
1326     g_context.on_client_received_data = callback;
1327     ca_mutex_unlock(g_context.lock);
1328 }
1329
1330 void CASetLEServerThreadPoolHandle(ca_thread_pool_t handle)
1331 {
1332     ca_mutex_lock(g_context.lock);
1333     g_context.server_thread_pool = handle;
1334     ca_mutex_unlock(g_context.lock);
1335 }
1336
1337 void CASetLEClientThreadPoolHandle(ca_thread_pool_t handle)
1338 {
1339     ca_mutex_lock(g_context.lock);
1340     g_context.client_thread_pool = handle;
1341     ca_mutex_unlock(g_context.lock);
1342 }
1343
1344 CAResult_t CAUnSetLEAdapterStateChangedCb()
1345 {
1346     ca_mutex_lock(g_context.lock);
1347     g_context.on_device_state_changed = NULL;
1348     ca_mutex_unlock(g_context.lock);
1349
1350     return CA_STATUS_OK;
1351 }
1352
1353 void CASetBLEClientErrorHandleCallback(CABLEErrorHandleCallback callback)
1354 {
1355     ca_mutex_lock(g_context.lock);
1356     g_context.on_client_error = callback;
1357     ca_mutex_unlock(g_context.lock);
1358 }
1359
1360 void CASetBLEServerErrorHandleCallback(CABLEErrorHandleCallback callback)
1361 {
1362     ca_mutex_lock(g_context.lock);
1363     g_context.on_server_error = callback;
1364     ca_mutex_unlock(g_context.lock);
1365 }