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