Implemented Linux BLE transport.
authorOssama Othman <ossama.othman@intel.com>
Mon, 27 Apr 2015 21:36:19 +0000 (14:36 -0700)
committerErich Keane <erich.keane@intel.com>
Fri, 31 Jul 2015 07:05:45 +0000 (07:05 +0000)
This is an implementation of the proposed OIC Bluetooth Low Energy
transport for Linux.

Change-Id: Id105a1d7a86c59d41900c6e4b0fc1b0a60b97c75
Signed-off-by: Ossama Othman <ossama.othman@intel.com>
Reviewed-on: https://gerrit.iotivity.org/gerrit/1125
Tested-by: jenkins-iotivity <jenkins-iotivity@opendaylight.org>
Reviewed-by: Jon A. Cruz <jonc@osg.samsung.com>
Reviewed-by: Erich Keane <erich.keane@intel.com>
55 files changed:
.gitignore
extlibs/bluez/0001-core-advertising-Fix-using-wrong-instance-id.patch [new file with mode: 0644]
extlibs/bluez/SConscript [new file with mode: 0644]
extlibs/bluez/bluetooth.service.in.patch [new file with mode: 0644]
resource/csdk/SConscript
resource/csdk/connectivity/SConscript
resource/csdk/connectivity/inc/cagattservice.h [new file with mode: 0644]
resource/csdk/connectivity/inc/caleadapter.h
resource/csdk/connectivity/inc/caleinterface.h
resource/csdk/connectivity/src/bt_le_adapter/SConscript
resource/csdk/connectivity/src/bt_le_adapter/android/caleclient.c
resource/csdk/connectivity/src/bt_le_adapter/android/calenwmonitor.c
resource/csdk/connectivity/src/bt_le_adapter/android/caleserver.c
resource/csdk/connectivity/src/bt_le_adapter/android/caleutils.h
resource/csdk/connectivity/src/bt_le_adapter/arduino/cableclient.cpp
resource/csdk/connectivity/src/bt_le_adapter/arduino/cablenwmonitor.cpp
resource/csdk/connectivity/src/bt_le_adapter/arduino/cableserver.cpp
resource/csdk/connectivity/src/bt_le_adapter/caleadapter.c
resource/csdk/connectivity/src/bt_le_adapter/linux/README [new file with mode: 0644]
resource/csdk/connectivity/src/bt_le_adapter/linux/SConscript
resource/csdk/connectivity/src/bt_le_adapter/linux/advertisement.c [new file with mode: 0644]
resource/csdk/connectivity/src/bt_le_adapter/linux/advertisement.h [new file with mode: 0644]
resource/csdk/connectivity/src/bt_le_adapter/linux/bluez.h [new file with mode: 0644]
resource/csdk/connectivity/src/bt_le_adapter/linux/bluez.xml [new file with mode: 0644]
resource/csdk/connectivity/src/bt_le_adapter/linux/caleadapter.c [deleted file]
resource/csdk/connectivity/src/bt_le_adapter/linux/caleinterface.c [new file with mode: 0644]
resource/csdk/connectivity/src/bt_le_adapter/linux/central.c [new file with mode: 0644]
resource/csdk/connectivity/src/bt_le_adapter/linux/central.h [new file with mode: 0644]
resource/csdk/connectivity/src/bt_le_adapter/linux/characteristic.c [new file with mode: 0644]
resource/csdk/connectivity/src/bt_le_adapter/linux/characteristic.h [new file with mode: 0644]
resource/csdk/connectivity/src/bt_le_adapter/linux/client.c [new file with mode: 0644]
resource/csdk/connectivity/src/bt_le_adapter/linux/client.h [new file with mode: 0644]
resource/csdk/connectivity/src/bt_le_adapter/linux/context.h [new file with mode: 0644]
resource/csdk/connectivity/src/bt_le_adapter/linux/descriptor.c [new file with mode: 0644]
resource/csdk/connectivity/src/bt_le_adapter/linux/descriptor.h [new file with mode: 0644]
resource/csdk/connectivity/src/bt_le_adapter/linux/gatt_dbus.h [new file with mode: 0644]
resource/csdk/connectivity/src/bt_le_adapter/linux/object_manager.xml [new file with mode: 0644]
resource/csdk/connectivity/src/bt_le_adapter/linux/org.iotivity.gatt.service.conf.in [new file with mode: 0644]
resource/csdk/connectivity/src/bt_le_adapter/linux/peripheral.c [new file with mode: 0644]
resource/csdk/connectivity/src/bt_le_adapter/linux/peripheral.h [new file with mode: 0644]
resource/csdk/connectivity/src/bt_le_adapter/linux/recv.c [new file with mode: 0644]
resource/csdk/connectivity/src/bt_le_adapter/linux/recv.h [new file with mode: 0644]
resource/csdk/connectivity/src/bt_le_adapter/linux/server.c [new file with mode: 0644]
resource/csdk/connectivity/src/bt_le_adapter/linux/server.h [new file with mode: 0644]
resource/csdk/connectivity/src/bt_le_adapter/linux/service.c [new file with mode: 0644]
resource/csdk/connectivity/src/bt_le_adapter/linux/service.h [new file with mode: 0644]
resource/csdk/connectivity/src/bt_le_adapter/linux/utils.c [new file with mode: 0644]
resource/csdk/connectivity/src/bt_le_adapter/linux/utils.h [new file with mode: 0644]
resource/csdk/connectivity/src/bt_le_adapter/tizen/cableclient.c
resource/csdk/connectivity/src/bt_le_adapter/tizen/cablenwmonitor.c
resource/csdk/connectivity/src/bt_le_adapter/tizen/cableserver.c
resource/csdk/connectivity/src/bt_le_adapter/tizen/cableutil.c
resource/csdk/connectivity/src/bt_le_adapter/tizen/cableutil.h
tools/scons/RunTest.py
tools/valgrind/iotivity.supp

index c891e5c..3cb9926 100644 (file)
@@ -103,6 +103,7 @@ extlibs/arduino/arduino-1.5.8
 build_common/arduino/extlibs/arduino/arduino-1.5.8
 extlibs/tinydtls/dtls-client
 extlibs/tinydtls/dtls-server
+extlibs/bluez/bluez
 
 # Ignore editor (e.g. Emacs) backup and autosave files
 *~
diff --git a/extlibs/bluez/0001-core-advertising-Fix-using-wrong-instance-id.patch b/extlibs/bluez/0001-core-advertising-Fix-using-wrong-instance-id.patch
new file mode 100644 (file)
index 0000000..dc290b3
--- /dev/null
@@ -0,0 +1,73 @@
+From 31fafe0dd2265cd181734ee909554f24fd3c3c20 Mon Sep 17 00:00:00 2001
+From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Date: Fri, 26 Jun 2015 14:52:22 +0300
+Subject: [PATCH] core/advertising: Fix using wrong instance id
+
+The instance id shall be limited to the number of instance the kernel
+support, and since this will probably be quite small the ids should be
+reused once the client unregistered.
+---
+ src/advertising.c | 12 +++++++-----
+ 1 file changed, 7 insertions(+), 5 deletions(-)
+
+diff --git a/src/advertising.c b/src/advertising.c
+index d6ab084..3763d85 100644
+--- a/src/advertising.c
++++ b/src/advertising.c
+@@ -48,7 +48,7 @@ struct btd_advertising {
+       uint16_t mgmt_index;
+       uint8_t max_adv_len;
+       uint8_t max_ads;
+-      unsigned int next_instance_id;
++      unsigned int instance_bitmap;
+ };
+ #define AD_TYPE_BROADCAST 0
+@@ -155,6 +155,8 @@ static void advertisement_remove(void *data)
+       queue_remove(ad->manager->ads, ad);
++      util_clear_uid(&ad->manager->instance_bitmap, ad->instance);
++
+       g_idle_add(advertisement_free_idle_cb, ad);
+ }
+@@ -633,6 +635,7 @@ static DBusMessage *register_advertisement(DBusConnection *conn,
+       DBusMessageIter args;
+       struct advertisement *ad;
+       struct dbus_obj_match match;
++      uint8_t instance;
+       DBG("RegisterAdvertisement");
+@@ -649,7 +652,8 @@ static DBusMessage *register_advertisement(DBusConnection *conn,
+       if (queue_find(manager->ads, match_advertisement, &match))
+               return btd_error_already_exists(msg);
+-      if (queue_length(manager->ads) >= manager->max_ads)
++      instance = util_get_uid(&manager->instance_bitmap, manager->max_ads);
++      if (!instance)
+               return btd_error_failed(msg, "Maximum advertisements reached");
+       dbus_message_iter_next(&args);
+@@ -664,7 +668,7 @@ static DBusMessage *register_advertisement(DBusConnection *conn,
+       DBG("Registered advertisement at path %s", match.path);
+-      ad->instance = manager->next_instance_id++;
++      ad->instance = instance;
+       ad->manager = manager;
+       queue_push_tail(manager->ads, ad);
+@@ -787,8 +791,6 @@ advertising_manager_create(struct btd_adapter *adapter)
+       manager->ads = queue_new();
+-      manager->next_instance_id = 1;
+-
+       return manager;
+ }
+-- 
+2.1.4
+
diff --git a/extlibs/bluez/SConscript b/extlibs/bluez/SConscript
new file mode 100644 (file)
index 0000000..05b2b1b
--- /dev/null
@@ -0,0 +1,77 @@
+# ------------------------------------------------------------------------
+# Copyright 2015 Intel Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ------------------------------------------------------------------------
+
+######################################################################
+# BlueZ download script
+#
+# BlueZ is currently only used by the IoTivity Linux BLE transport.
+# The IoTivity Linux BLE transport depends on two headers found in the
+# BlueZ bluetooth library: <bluetooth/bluetooth.h> and
+# <bluetooth/hci.h>.  Those headers are used solely when pulling in
+# the types and constants necessary to a create kernel Bluetooth
+# management socket.  There is no need to link BlueZ's libbluetooth
+# library.
+######################################################################
+import os
+import subprocess
+
+Import('env')
+
+# First check if the BlueZ bluetooth library development files are
+# installed.  Add the location of the bluetooth library headers to the
+# include path if they are installed.  Otherwise, download the BlueZ
+# source code and adjust the include path, accordingly.
+
+# The subprocess.run() function became available in Python 3.5.  Use
+# the older high-level API instead, since some installations may still
+# be using older versions of Python.
+bluez_installed = (subprocess.call([ 'pkg-config',
+                                     'bluez',
+                                     '--exists' ]) == 0)
+
+if bluez_installed:
+        env.ParseConfig("pkg-config bluez --cflags-only-I")
+        Return()
+
+if not os.path.exists('bluez'):
+        bluez = env.Action([
+                'git clone git://git.kernel.org/pub/scm/bluetooth/bluez.git',
+                'cd bluez && ln -s lib bluetooth && cd -'])
+
+        print 'Downloading BlueZ ...'
+        if env.Execute(bluez):
+                print '''
+*********************************** Error *********************************
+* Please download Bluez 5.32 or better, build it and install it.          *
+* Alternatively, but less preferrably, create a symbolic as follows       *
+*     $ cd  extlibs/bluez                                                 *
+*     $ git clone git://git.kernel.org/pub/scm/bluetooth/bluez.git        *
+*     $ cd bluez                                                          *
+*     $ ln -s lib bluetooth                                               *
+*     $ cd ../../..                                                       *
+***************************************************************************
+'''
+                Exit(1)
+        else:
+                print 'BlueZ download complete.'
+
+env.AppendUnique(CPPPATH = ['#extlibs/bluez/bluez'])
+
+
+# Local Variables:
+# mode:python
+# indent-tabs-mode: nil
+# End:
diff --git a/extlibs/bluez/bluetooth.service.in.patch b/extlibs/bluez/bluetooth.service.in.patch
new file mode 100644 (file)
index 0000000..40bb01d
--- /dev/null
@@ -0,0 +1,13 @@
+diff --git a/src/bluetooth.service.in b/src/bluetooth.service.in
+index 35e9457..8204a79 100644
+--- a/src/bluetooth.service.in
++++ b/src/bluetooth.service.in
+@@ -5,7 +5,7 @@ Documentation=man:bluetoothd(8)
+ [Service]
+ Type=dbus
+ BusName=org.bluez
+-ExecStart=@libexecdir@/bluetoothd
++ExecStart=@libexecdir@/bluetoothd --experimental
+ NotifyAccess=main
+ #WatchdogSec=10
+ #Restart=on-failure
index cee8dc9..a9e30c8 100644 (file)
@@ -66,10 +66,11 @@ if target_os not in ['windows', 'winrt']:
 
 liboctbstack_env.AppendUnique(LIBPATH = [env.get('BUILD_DIR')])
 
-if target_os in ['android', 'linux','tizen']:
-       liboctbstack_env.AppendUnique(LIBS = ['connectivity_abstraction'])
+if target_os in ['android', 'linux', 'tizen']:
+       liboctbstack_env.PrependUnique(LIBS = ['connectivity_abstraction'])
        if with_ra:
                liboctbstack_env.AppendUnique(LIBS = ['ra_xmpp'])
+
 liboctbstack_env.AppendUnique(LIBS = ['coap', 'm'])
 
 if target_os == 'tizen':
index f7560e6..e68924f 100644 (file)
@@ -25,7 +25,7 @@ if 'ALL' in transport:
        if with_ra == True:
                        env.AppendUnique(CPPDEFINES = ['RA_ADAPTER'])
        if target_os == 'linux':
-               env.AppendUnique(CPPDEFINES = ['IP_ADAPTER','NO_EDR_ADAPTER','NO_LE_ADAPTER'])
+               env.AppendUnique(CPPDEFINES = ['IP_ADAPTER','NO_EDR_ADAPTER','LE_ADAPTER'])
        elif target_os == 'tizen':
                env.AppendUnique(CPPDEFINES = ['IP_ADAPTER','EDR_ADAPTER','LE_ADAPTER'])
        elif target_os in['darwin','ios']:
@@ -45,12 +45,8 @@ else:
                env.AppendUnique(CPPDEFINES = ['NO_EDR_ADAPTER'])
 
        if 'BLE' in transport:
-               if target_os == 'linux':
-                       print "CA Transport BLE is not supported in Linux"
-                       Exit(1)
-               else:
-                       env.AppendUnique(CPPDEFINES = ['LE_ADAPTER'])
-                       print "CA Transport is BLE"
+               env.AppendUnique(CPPDEFINES = ['LE_ADAPTER'])
+               print "CA Transport is BLE"
        else:
                env.AppendUnique(CPPDEFINES = ['NO_LE_ADAPTER'])
 
diff --git a/resource/csdk/connectivity/inc/cagattservice.h b/resource/csdk/connectivity/inc/cagattservice.h
new file mode 100644 (file)
index 0000000..a6ad4d5
--- /dev/null
@@ -0,0 +1,76 @@
+/* ****************************************************************
+ *
+ * Copyright 2015 Intel Corporation All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+#ifndef CA_GATT_SERVICE_H
+#define CA_GATT_SERVICE_H
+
+
+/**
+ * @name OIC GATT Transport Constants
+ *
+ * Group of constants, such as UUIDs, specific to the OIC GATT
+ * Transport Profile.
+ */
+//@{
+/// OIC Transport Profile GATT service UUID.
+#define CA_GATT_SERVICE_UUID "ADE3D529-C784-4F63-A987-EB69F70EE816"
+
+/// OIC Transport Profile GATT request characteristic UUID.
+#define CA_GATT_REQUEST_CHRC_UUID "AD7B334F-4637-4B86-90B6-9D787F03D218"
+
+/**
+ * Standard Bluetooth GATT characteristic user description descriptor
+ * UUID.
+ *
+ * @note Used by both the OIC GATT request and response
+ *       characteristics.
+ */
+#define CA_GATT_CHRC_USER_DESCRIPTION_DESC_UUID "2901"
+
+/**
+ * OIC Transport Profile GATT request characteristic user description
+ * descriptor value.
+ */
+#define CA_GATT_REQUEST_USER_DESCRIPTION "OIC Node Request"
+
+/// OIC Transport Profile GATT response characteristic UUID.
+#define CA_GATT_RESPONSE_CHRC_UUID "E9241982-4580-42C4-8831-95048216B256"
+
+/**
+ * OIC Transport Profile GATT response characteristic user description
+ * descriptor value.
+ */
+#define CA_GATT_RESPONSE_USER_DESCRIPTION "OIC Node Response"
+
+/**
+ * Standard Bluetooth GATT client characteristic configuration
+ * descriptor UUID.
+ *
+ * @note Only used by the OIC GATT response characteristic.
+ */
+#define CA_GATT_CONFIGURATION_DESC_UUID "2902"
+
+/**
+ * OIC Transport Profile GATT response client characteristic
+ * configuration descriptor value.
+ */
+#define CA_GATT_RESPONSE_CONFIG_DESC "0001"
+//@}
+
+
+#endif  // CA_GATT_SERVICE_H
index 88b94af..bf85d27 100644 (file)
  *
  ******************************************************************/
 
-/**
- * @file
- *
- * This file contains the APIs for LE adapters to be implemented.
- */
 
 #ifndef CA_LEADAPTER_H_
 #define CA_LEADAPTER_H_
 
 #include "cacommon.h"
 #include "caadapterinterface.h"
-#include "cathreadpool.h" /* for thread pool */
+#include "cathreadpool.h"
 
-// BLE Interface APIs.
 #ifdef __cplusplus
 extern "C"
 {
 #endif
 
-/**
- * Stores the information of the Data to be sent from the queues.
- * This structure will be pushed to the sender/receiver queue for processing.
- */
-typedef struct
-{
-    CAEndpoint_t *remoteEndpoint;   /**< Remote endpoint contains the
-                                       information of remote device. */
-    void *data;        /**< Data to be transmitted over LE transport. */
-    uint32_t dataLen;  /**< Length of the data being transmitted. */
-} CALEData_t;
-
-/**
- * Stores information of all the senders.
- * This structure will be used to track and de-fragmentation all incoming data packets.
- */
-typedef struct
-{
-    uint32_t recvDataLen;
-    uint32_t totalDataLen;
-    char *defragData;
-    CAEndpoint_t *remoteEndpoint;
-}CABLESenderInfo_t;
 
 /**
  * Initialize LE connectivity interface.
+ *
  * @param[in]  registerCallback Callback to register LE interfaces to
- *                               Connectivity Abstraction Layer.
+ *                              Connectivity Abstraction Layer.
  * @param[in]  reqRespCallback  Callback to notify request and response
- *                               messages from server(s) started at
- *                               Connectivity Abstraction Layer.
+ *                              messages from server(s) started at
+ *                              Connectivity Abstraction Layer.
  * @param[in]  netCallback      Callback to notify the network additions
- *                               to Connectivity Abstraction Layer.
+ *                              to Connectivity Abstraction Layer.
  * @param[in]  errorCallback    errorCallback to notify error to
- *                               connectivity common logic layer from adapter.
+ *                              connectivity common logic layer from adapter.
  * @param[in]  handle           Threadpool Handle.
+ *
  * @return ::CA_STATUS_OK or Appropriate error code.
  */
 CAResult_t CAInitializeLE(CARegisterConnectivityCallback registerCallback,
                           CANetworkPacketReceivedCallback reqRespCallback,
                           CANetworkChangeCallback netCallback,
-                          CAErrorHandleCallback errorCallback, ca_thread_pool_t handle);
-
-/**
- * Starting LE connectivity adapters.
- * As its peer to peer it doesnot require to start any servers.
- * @return  ::CA_STATUS_OK or Appropriate error code.
- */
-CAResult_t CAStartLE();
-
-/**
- * Starting listening server for receiving multicast search requests.
- * Transport Specific Behavior:
- *   LE  Starts GATT Server with prefixed UUID and Characteristics as per
- *   OIC Specification.
- * @return  ::CA_STATUS_OK or Appropriate error code.
- */
-CAResult_t CAStartLEListeningServer();
-
-/**
- * for starting discovery servers for receiving multicast advertisements.
- * Transport Specific Behavior:
- *   LE  Starts GATT Server with prefixed UUID and Characteristics as per
- *   OIC Specification.
- * @return  ::CA_STATUS_OK or Appropriate error code
- */
-CAResult_t CAStartLEDiscoveryServer();
-
-/**
- * Sends data to the endpoint using the adapter connectivity.
- * @param[in]   endpoint   Remote Endpoint information (like ipaddress ,
- *                          port, reference uri and connectivity type) to
- *                          which the unicast data has to be sent.
- * @param[in]   data       Data which required to be sent.
- * @param[in]   dataLen    Size of data to be sent.
- * @note  dataLen must be > 0.
- * @return  The number of bytes sent on the network, or -1 on error.
- */
-int32_t CASendLEUnicastData(const CAEndpoint_t *endpoint, const void *data,
-                             uint32_t dataLen);
-
-/**
- * Sends Multicast data to the endpoint using the LE connectivity.
- * @param[in]   endpoint     Remote Endpoint information to which the
- *                            unicast data has to be sent.
- * @param[in]   data         Data which required to be sent.
- * @param[in]   dataLen      Size of data to be sent.
- * @note  dataLen must be > 0.
- * @return  The number of bytes sent on the network, or -1 on error.
- */
-int32_t CASendLEMulticastData(const CAEndpoint_t *endpoint, const void *data, uint32_t dataLen);
-
-/**
- * Starts notification server on EDR adapters.
- * @return  ::CA_STATUS_OK or Appropriate error code.
- */
-CAResult_t CAStartLENotifyServer();
-
-/**
- * Send notification information.
- * @param[in]   endpoint     Remote Endpoint information (like ipaddress ,
- *                            port, reference uri and connectivity type)
- *                            to which the unicast data has to be sent.
- * @param[in]   data         Data which required to be sent.
- * @param[in]   dataLen      Size of data to be sent.
- * @note dataLen must be > 0.
- * @return  The number of bytes sent on the network, or 0 on error.
- */
-uint32_t CASendLENotification(const CAEndpoint_t *endpoint, const void *data,
-                              uint32_t dataLen);
-
-/**
- * Get LE Connectivity network information.
- * @param[out]  info          Local connectivity information structures.
- * @param[out]  size          Number of local connectivity structures.
- * @return ::CA_STATUS_OK or Appropriate error code.
- */
-CAResult_t CAGetLEInterfaceInformation(CAEndpoint_t **info, uint32_t *size);
-
-/**
- * Read Synchronous API callback.
- * @return  ::CA_STATUS_OK or Appropriate error code.
- */
-CAResult_t CAReadLEData();
-
-/**
- * Stopping the adapters and close socket connections.
- *   LE Stops all GATT servers and GATT Clients.
- * @return  ::CA_STATUS_OK or Appropriate error code.
- */
-CAResult_t CAStopLE();
-
-/**
- * Terminate the LE connectivity adapter.
- * Configuration information will be deleted from further use.
- */
-void CATerminateLE();
-
-/**
- * This function will receive the data from the GattServer and add the data to
- *         the Server receiver queue.
- * @param[in]  remoteAddress Remote address of the device from where data
- *                            is received.
- * @param[in]  serviceUUID   Uuid of the OIC service running on the remote
- *                            device.
- * @param[in]  data          Actual data Received from the remote device.
- * @param[in]  dataLength    Length of the data received from the remote device.
- * @param[in]  sentLength    Length of the data sent from the remote device.
- * @return ::CA_STATUS_OK or Appropriate error code.
- * @retval ::CA_STATUS_OK  Successful.
- * @retval ::CA_STATUS_INVALID_PARAM  Invalid input arguments.
- * @retval ::CA_STATUS_FAILED Operation failed.
- *
- */
-CAResult_t CALEAdapterServerReceivedData(const char *remoteAddress, const char *serviceUUID,
-                                         const void *data, uint32_t dataLength,
-                                         uint32_t *sentLength);
+                          CAErrorHandleCallback errorCallback,
+                          ca_thread_pool_t handle);
 
-/**
- * This function will receive the data from the GattClient and add the
- * data into the Client receiver queue.
- * @param[in]  remoteAddress Remote address of the device from where data
- *                            is received.
- * @param[in]  serviceUUID   Uuid of the OIC service running on the remote
- *                            device.
- * @param[in]  data          Actual data received from the remote device.
- * @param[in]  dataLength    Length of the data received from the remote device.
- * @param[in]  sentLength    Length of the data sent from the remote device.
- * @return ::CA_STATUS_OK or Appropriate error code.
- * @retval ::CA_STATUS_OK  Successful.
- * @retval ::CA_STATUS_INVALID_PARAM  Invalid input  arguments.
- * @retval ::CA_STATUS_FAILED Operation failed.
- */
-CAResult_t CALEAdapterClientReceivedData(const char *remoteAddress, const char *serviceUUID,
-                                         const void *data, uint32_t dataLength,
-                                         uint32_t *sentLength);
-
-/**
- * This function is used to set the NetworkPacket received callback to CA
- * layer from adapter layer.
- * @param[in]  callback callback handle sent from the upper layer.
- */
-void CASetLEReqRespAdapterCallback(CANetworkPacketReceivedCallback callback);
-
-/**
- * This function will push the data from CA layer to the Sender processor queue.
- *
- * @param[in]  remoteEndpoint Remote endpoint information of the server.
- * @param[in]  data           Data to be transmitted from LE.
- * @param[in]  dataLen        length of the Data being transmitted.
- *
- * @return ::CA_STATUS_OK or Appropriate error code.
- * @retval ::CA_STATUS_OK  Successful.
- * @retval ::CA_STATUS_INVALID_PARAM  Invalid input  arguments.
- * @retval ::CA_STATUS_FAILED Operation failed.
- */
-CAResult_t CALEAdapterServerSendData(const CAEndpoint_t *remoteEndpoint,
-                                     const void *data, uint32_t dataLen);
-
-/**
- * This function will push the data from CA layer to the Sender processor queue.
- *
- * @param[in]  remoteEndpoint Remote endpoint information of the server.
- * @param[in]  data           Data to be transmitted from LE.
- * @param[in]  dataLen        length of the Data being transmitted.
- *
- * @return ::CA_STATUS_OK or Appropriate error code.
- * @retval ::CA_STATUS_OK  Successful.
- * @retval ::CA_STATUS_INVALID_PARAM  Invalid input  arguments.
- * @retval ::CA_STATUS_FAILED Operation failed.
- */
-CAResult_t CALEAdapterClientSendData(const CAEndpoint_t *remoteEndpoint,
-                                     const void *data,  uint32_t dataLen);
-
-/**
- * This function will be associated with the sender queue for GattServer.
- * This function will fragment the data to the MTU of the transport and
- * send the data in fragments to the adapters. The function will be
- * blocked untill all data is sent out from the adapter.
- *
- * @param[in] threadData Data pushed to the queue which contains the info
- * about RemoteEndpoint and Data.
- */
-void CALEServerSendDataThread(void *threadData);
-
-/**
- * This function will be associated with the sender queue for GattClient.
- * This function will fragment the data to the MTU of the transport and
- * send the data in fragments to the adapters. The function will be
- * blocked until all data is sent out from the adapter.
- *
- * @param[in]  threadData Data pushed to the queue which contains the info
- * about RemoteEndpoint and Data.
- */
-void CALEClientSendDataThread(void *threadData);
-
-/**
- * This function will be associated with the receiver queue. This function will reassemble
- * the received data from each sender respectively and will send it up to CA layer.
- * Respective sender's header will provide the length of the data sent.
- *
- * @param [IN]  threadData Data pushed to the queue which contains the info about RemoteEndpoint
- * and Data.
- */
-void CALEDataReceiverHandler(void *threadData);
-
-/**
- * This function is used to initialize both GattServer and GattClient
- * queues. All four queues will be initialized with this function invocations.
- */
-void CAInitLEQueues();
-
-/**
- * This function will stop all queues created for GattServer and GattClient. All
- * four queues will be be stopped with this function invocations.
- */
-void CAStopLEQueues();
-
-/**
- * This function will terminate all queues created for GattServer and
- * GattClient. All four queues will be be terminated with this function
- * invocations.
- */
-void CATerminateLEQueues();
-
-/**
- * This function will initialize the Receiver and Sender queues for
- * GattServer. This function will inturn call the functions
- * CAInitBleServerReceiverQueue() and  CAInitBleServerSenderQueue() to
- * initialize the queues.
- * @return ::CA_STATUS_OK or Appropriate error code.
- * @retval ::CA_STATUS_OK  Successful.
- * @retval ::CA_STATUS_INVALID_PARAM  Invalid input arguments.
- * @retval ::CA_STATUS_FAILED Operation failed.
- */
-CAResult_t CAInitLEServerQueues();
-
-/**
- * This function will initialize the Receiver and Sender queues for
- * GattClient. This function will inturn call the functions
- * CAInitBleClientReceiverQueue() and CAInitBleClientSenderQueue() to
- * initialize the queues.
- *
- * @return ::CA_STATUS_OK or Appropriate error code.
- * @retval ::CA_STATUS_OK  Successful.
- * @retval ::CA_STATUS_INVALID_PARAM  Invalid input arguments.
- * @retval ::CA_STATUS_FAILED Operation failed.
- *
- */
-CAResult_t CAInitLEClientQueues();
-
-/**
- * This function will initialize the Receiver queue for GattServer. This
- * will initialize the queue to process the function
- * CABLEServerSendDataThread() when ever the task is added to this queue.
- *
- * @return ::CA_STATUS_OK or Appropriate error code.
- * @retval ::CA_STATUS_OK  Successful.
- * @retval ::CA_STATUS_INVALID_PARAM  Invalid input arguments.
- * @retval ::CA_STATUS_FAILED Operation failed.
- */
-CAResult_t CAInitLEServerSenderQueue();
-
-/**
- * This function will initialize the Receiver queue for GattClient. This
- * will initialize the queue to process the function
- * CABLEClientSendDataThread() when ever the task is added to this queue.
- *
- * @return ::CA_STATUS_OK or Appropriate error code.
- * @retval ::CA_STATUS_OK  Successful.
- * @retval ::CA_STATUS_INVALID_PARAM  Invalid input arguments.
- * @retval ::CA_STATUS_FAILED Operation failed.
- */
-CAResult_t CAInitLEClientSenderQueue();
-
-/**
- * This function will initialize the Receiver queue for LEAdapter. This will initialize
- * the queue to process the function CABLEDataReceiverHandler() when ever the task
- * is added to this queue.
- *
- * @return ::CA_STATUS_OK or Appropriate error code
- * @retval ::CA_STATUS_OK  Successful
- * @retval ::CA_STATUS_INVALID_PARAM  Invalid input arguments
- * @retval ::CA_STATUS_FAILED Operation failed
- *
- */
-CAResult_t CAInitLEReceiverQueue();
-
-/**
- * This function will create the Data required to send it in the queue.
- *
- * @param[in]  remoteEndpoint Remote endpoint information of the server.
- * @param[in]  data           Data to be transmitted from LE.
- * @param[in]  dataLength     length of the Data being transmitted.
- *
- * @return ::CA_STATUS_OK or Appropriate error code.
- * @retval ::CA_STATUS_OK  Successful.
- * @retval ::CA_STATUS_INVALID_PARAM  Invalid input arguments.
- * @retval ::CA_STATUS_FAILED Operation failed.
- */
-CALEData_t *CACreateLEData(const CAEndpoint_t *remoteEndpoint, const void *data,
-                           uint32_t dataLength);
-
-/**
- * Used to free the BLE information stored in the sender/receiver queues.
- * @param[in] bleData Structure contains the information of a particular
- * data segment.
- */
-void CAFreeLEData(CALEData_t *bleData);
-
-/**
- * This will be used to notify device status changes to the LE adapter layer.
- * @param[in]  adapter_state State of the adapter.
- */
-typedef void (*CALEDeviceStateChangedCallback)(CAAdapterState_t adapter_state);
-
-/**
- * This will be used to notify that network packet received from
- * GATTClient to adapter layer.
- * @param[in]  remoteAddress  Remote endpoint Address.
- * @param[in]  serviceUUID    Service UUID.
- * @param[in]  data           Data received.
- * @param[in]  dataLength     Length of the data received.
- * @param[in]  sentLength     Length of the data sent.
- * @return ::CA_STATUS_OK or Appropriate error code.
- * @retval ::CA_STATUS_OK  Successful.
- * @retval ::CA_STATUS_INVALID_PARAM  Invalid input arguments.
- * @retval ::CA_STATUS_FAILED Operation failed.
- */
-typedef CAResult_t (*CABLEClientDataReceivedCallback)(const char *remoteAddress,
-                                                      const char *serviceUUID, const void *data,
-                                                      uint32_t dataLength, uint32_t *sentLength);
-
-/**
- * This will be used to notify that network packet received from
- * GATTServer to adapter layer.
- * @param[in]  remoteAddress  Remote endpoint Address.
- * @param[in]  serviceUUID    Service UUID.
- * @param[in]  data           Data received.
- * @param[in]  dataLength     Length of the data received.
- * @param[in]  sentLength     Length of the data sent.
- * @return ::CA_STATUS_OK or Appropriate error code.
- * @retval ::CA_STATUS_OK  Successful.
- * @retval ::CA_STATUS_INVALID_PARAM  Invalid input arguments.
- * @retval ::CA_STATUS_FAILED Operation failed.
- */
-typedef CAResult_t (*CABLEServerDataReceivedCallback)(const char *remoteAddress,
-                                                      const char *serviceUUID, const void *data,
-                                                      uint32_t dataLength, uint32_t *sentLength);
 
 #ifdef __cplusplus
 } /* extern "C" */
index b5fd208..589d146 100644 (file)
@@ -19,8 +19,6 @@
 ******************************************************************/
 
 /**
- * @file
- *
  * This file provides APIs for BLE modules.
  */
 
@@ -30,7 +28,7 @@
 #include <stdbool.h>
 
 #include "cacommon.h"
-#include "caleadapter.h"
+#include "cathreadpool.h"
 
 #ifdef __cplusplus
 extern "C"
@@ -39,7 +37,9 @@ extern "C"
 
 /**
  * Provide info about different mode of data transfer.
- * This enum is used to differentiate between unicast and multicast data transfer.
+ *
+ * This enum is used to differentiate between unicast and multicast
+ * data transfer.
  */
 typedef enum
 {
@@ -47,234 +47,295 @@ typedef enum
     LE_UNICAST       /**< When this enum is selected, data will be updated to desired OIC Server. */
 } CALETransferType_t;
 
+/**
+ * This will be used to notify device status changes to the LE adapter layer.
+ * @param[in]  adapter_state State of the adapter.
+ */
+typedef void (*CALEDeviceStateChangedCallback)(CAAdapterState_t adapter_state);
 
 /**
- * Initialize the LE adapter layer. This will be invoked from the CA layer.
+ * Notify the adapter layer that a packet was received from the GATT
+ * peer.
+ *
+ * @param[in]  remoteAddress  Remote endpoint Address.
+ * @param[in]  data           Data received.
+ * @param[in]  dataLength     Length of the data received.
+ * @param[in]  sentLength     Length of the data sent.
  *
  * @return ::CA_STATUS_OK or Appropriate error code.
  * @retval ::CA_STATUS_OK  Successful.
  * @retval ::CA_STATUS_INVALID_PARAM  Invalid input arguments.
  * @retval ::CA_STATUS_FAILED Operation failed.
  */
+typedef CAResult_t (*CABLEDataReceivedCallback)(const char *remoteAddress,
+                                                const void *data,
+                                                uint32_t dataLength,
+                                                uint32_t *sentLength);
+
+/**
+ * Initialize the LE adapter layer. This will be invoked from the CA
+ * layer.
+ *
+ * @return ::CA_STATUS_OK or Appropriate error code
+ * @retval ::CA_STATUS_OK  Successful
+ * @retval ::CA_STATUS_INVALID_PARAM  Invalid input arguments
+ * @retval ::CA_STATUS_FAILED Operation failed
+ */
 CAResult_t CAInitializeLEAdapter();
 
 /**
+ * Start the LE adapter layer.
+ *
+ * This function will be invoked from the CA layer when the LE
+ * "network" is selected via @c CASelectNetwork().  It gives an
+ * opportunity for LE adapter implementations to perform operations
+ * before starting a GATT client or server.  Most LE adapter
+ * implementations will simply implement this function as no-op.
+ *
+ * @return ::CA_STATUS_OK or Appropriate error code
+ */
+CAResult_t CAStartLEAdapter();
+
+/**
  * Used to get the current state of the LE adapter.
  *
- * @return ::CA_STATUS_OK or Appropriate error code.
- * @retval ::CA_STATUS_OK  Successful.
- * @retval ::CA_ADAPTER_NOT_ENABLED  adapter not enabled.
- * @retval ::CA_STATUS_FAILED Operation failed.
+ * @return ::CA_STATUS_OK or Appropriate error code
+ * @retval ::CA_STATUS_OK  Successful
+ * @retval ::CA_ADAPTER_NOT_ENABLED  adapter not enabled
+ * @retval ::CA_STATUS_FAILED Operation failed
  */
 CAResult_t CAGetLEAdapterState();
 
 /**
- * Used to initialize the network monitor layer of the LE adapter. Mutex variables required
- * to operate in this layer and other paramters can be initialized in this function.
+ * Initialize the network monitor layer of the LE adapter.  Mutex
+ * variables required to operate in this layer and other parameters
+ * can be initialized in this function.
  *
- * @return ::CA_STATUS_OK or Appropriate error code.
- * @retval ::CA_STATUS_OK  Successful.
- * @retval ::CA_STATUS_INVALID_PARAM  Invalid input arguments.
- * @retval ::CA_STATUS_FAILED Operation failed.
+ * @return ::CA_STATUS_OK or Appropriate error code
+ * @retval ::CA_STATUS_OK  Successful
+ * @retval ::CA_STATUS_INVALID_PARAM  Invalid input arguments
+ * @retval ::CA_STATUS_FAILED Operation failed
  */
 CAResult_t CAInitializeLENetworkMonitor();
 
 /**
- * Used to terminate the network monitor layer of the LE adapter. The variables intialized
- * in CAInitializeLEAdapterController() must be cleared in this function.
+ * Terminate the network monitor layer of the LE adapter. The
+ * variables initialized in @c CAInitializeLENetworkMonitor() must be
+ * cleared in this function.
  */
 void CATerminateLENetworkMonitor();
 
 /**
- * This function is used to set the callback for the Device state changes in the adapter.
+ * Set the callback for the device state changes in the adapter.
  *
- * @param[in]  callback  Callback to notify the Device state change to the CA Layer.
+ * @param[in] callback Callback to notify the Device state change to
+ *            the CA Layer
  *
- * @return ::CA_STATUS_OK or Appropriate error code.
- * @retval ::CA_STATUS_OK  Successful.
- * @retval ::CA_STATUS_INVALID_PARAM  Invalid input arguments.
- * @retval ::CA_STATUS_FAILED Operation failed.
+ * @return ::CA_STATUS_OK or Appropriate error code
+ * @retval ::CA_STATUS_OK  Successful
+ * @retval ::CA_STATUS_INVALID_PARAM  Invalid input arguments
+ * @retval ::CA_STATUS_FAILED Operation failed
  */
 CAResult_t CASetLEAdapterStateChangedCb(CALEDeviceStateChangedCallback callback);
 
 /**
- * Used to initilaze all the mutex variables required.
- * to operate the LE network monitor layer.
- * @return ::CA_STATUS_OK or Appropriate error code.
- * @retval ::CA_STATUS_OK  Successful.
- * @retval ::CA_STATUS_INVALID_PARAM  Invalid input arguments.
- * @retval ::CA_STATUS_FAILED Operation failed.
+ * Initialize all the mutex variables required to operate the LE
+ * network monitor layer.
+ *
+ * @return ::CA_STATUS_OK or Appropriate error code
+ * @retval ::CA_STATUS_OK  Successful
+ * @retval ::CA_STATUS_INVALID_PARAM  Invalid input arguments
+ * @retval ::CA_STATUS_FAILED Operation failed
  */
 CAResult_t CAInitLENetworkMonitorMutexVariables();
 
 /**
- * Used to terminate all the mutex variables required
- * to operate the LE network monitor layer.
+ * Used to terminate all the mutex variables required to operate the LE
+ * network monitor layer.
  */
 void CATerminateLENetworkMonitorMutexVariables();
 
 /**
- * Provides the BD address of the local adapter.
- * @param[out]  local_address    pointer to the location where bd address needs to be stored.
+ * Provides the MAC address of the local Bluetooth adapter.
  *
- * @return ::CA_STATUS_OK or Appropriate error code.
- * @retval ::CA_STATUS_OK  Successful.
- * @retval ::CA_STATUS_INVALID_PARAM  Invalid input arguments.
- * @retval ::CA_STATUS_FAILED Operation failed.
+ * @param[out] local_address Pointer to the location where bd address
+ *                           needs to be stored.
+ *
+ * @return ::CA_STATUS_OK or Appropriate error code
+ * @retval ::CA_STATUS_OK  Successful
+ * @retval ::CA_STATUS_INVALID_PARAM  Invalid input arguments
+ * @retval ::CA_STATUS_FAILED Operation failed
  */
 CAResult_t CAGetLEAddress(char **local_address);
 
 /**
- * Used to start Gatt Server thread for service creation and advertise ble service.
+ * Start Gatt Server thread for service creation and advertise BLE
+ * service.
  *
- * @return ::CA_STATUS_OK or Appropriate error code.
- * @retval ::CA_STATUS_OK  Successful.
- * @retval ::CA_STATUS_INVALID_PARAM  Invalid input arguments.
- * @retval ::CA_STATUS_FAILED Operation failed.
+ * @return ::CA_STATUS_OK or Appropriate error code
+ * @retval ::CA_STATUS_OK  Successful
+ * @retval ::CA_STATUS_INVALID_PARAM  Invalid input arguments
+ * @retval ::CA_STATUS_FAILED Operation failed
  */
 CAResult_t CAStartLEGattServer();
 
 /**
- * Used to stop BLE Gatt Service.
+ * Stop BLE Gatt Service.
  *
- * @return ::CA_STATUS_OK or Appropriate error code.
- * @retval ::CA_STATUS_OK  Successful.
- * @retval ::CA_STATUS_INVALID_PARAM  Invalid input arguments.
- * @retval ::CA_STATUS_FAILED Operation failed.
+ * @return ::CA_STATUS_OK or Appropriate error code
+ * @retval ::CA_STATUS_OK  Successful
+ * @retval ::CA_STATUS_INVALID_PARAM  Invalid input arguments
+ * @retval ::CA_STATUS_FAILED Operation failed
  */
 CAResult_t CAStopLEGattServer();
 
 /**
- * Used to stop Gatt Server thread and remove service registration, stop advertising.
+ * Stop Gatt Server thread and remove service registration, stop
+ * advertising.
  */
 void CATerminateLEGattServer();
 
 /**
- * Used to store upper layer callback locally
- * which will be used to send the data to application.
- * @param[in]  callback Callback function to pass the data to CA layer.
+ * Used to store upper layer callback locally which will be used to
+ * send the data to application.
+ *
+ * @param[in] callback Callback function to pass the data to CA layer.
  */
-void CASetLEReqRespServerCallback(CABLEServerDataReceivedCallback callback);
+void CASetLEReqRespServerCallback(CABLEDataReceivedCallback callback);
 
 /**
- * Used to update characteristics(Read/Write) value
- * that we want to send to particular client.
+ * Update characteristics(Read/Write) value that we want to send to
+ * particular client.
  *
- * @param[in]  address       BD address of Gatt client.
- * @param[in]  charValue     Data that we want to send to client(unicast).
- * @param[in]  charValueLen  Length of the data.
+ * @param[in] address      BD address of Gatt client
+ * @param[in] charValue    Data that we want to send to client(unicast)
+ * @param[in] charValueLen Length of the data.
  *
- * @return ::CA_STATUS_OK or Appropriate error code.
- * @retval ::CA_STATUS_OK  Successful.
- * @retval ::CA_STATUS_INVALID_PARAM  Invalid input arguments.
- * @retval ::CA_STATUS_FAILED Operation failed.
+ * @return ::CA_STATUS_OK or Appropriate error code
+ * @retval ::CA_STATUS_OK  Successful
+ * @retval ::CA_STATUS_INVALID_PARAM  Invalid input arguments
+ * @retval ::CA_STATUS_FAILED Operation failed
  */
-CAResult_t CAUpdateCharacteristicsToGattClient(const char* address, const char *charValue,
-                                               const uint32_t charValueLen);
+CAResult_t CAUpdateCharacteristicsToGattClient(const char *address,
+                                               const char *charValue,
+                                               uint32_t charValueLen);
 
 /**
- * Used to update characteristics(Read/Write) value that we want to multicast to all clients.
+ * Update characteristics(Read/Write) value that we want to multicast
+ * to all clients.
  *
- * @param[in]  charValue     Data that we want to send to clients(multicast).
- * @param[in]  charValueLen  Length of the data.
+ * @param[in] charValue    Data that we want to send to clients(multicast)
+ * @param[in] charValueLen Length of the data.
  *
- * @return ::CA_STATUS_OK or Appropriate error code.
- * @retval ::CA_STATUS_OK  Successful.
- * @retval ::CA_STATUS_INVALID_PARAM  Invalid input arguments.
- * @retval ::CA_STATUS_FAILED Operation failed.
+ * @return ::CA_STATUS_OK or Appropriate error code
+ * @retval ::CA_STATUS_OK  Successful
+ * @retval ::CA_STATUS_INVALID_PARAM  Invalid input arguments
+ * @retval ::CA_STATUS_FAILED Operation failed
  */
 CAResult_t CAUpdateCharacteristicsToAllGattClients(const char *charValue,
                                                    uint32_t charValueLen);
 
 /**
- * Used to start CAStartBleGattClientThread for initializing Gatt Client.
+ * Start @c CAStartBleGattClientThread for initializing Gatt Client.
  *
- * @return ::CA_STATUS_OK or Appropriate error code.
- * @retval ::CA_STATUS_OK  Successful.
- * @retval ::CA_STATUS_INVALID_PARAM  Invalid input arguments.
- * @retval ::CA_STATUS_FAILED Operation failed.
+ * @return ::CA_STATUS_OK or Appropriate error code
+ * @retval ::CA_STATUS_OK  Successful
+ * @retval ::CA_STATUS_INVALID_PARAM  Invalid input arguments
+ * @retval ::CA_STATUS_FAILED Operation failed
  */
 CAResult_t CAStartLEGattClient();
 
 /**
- * Used to stop Gatt Client gracefully in turn it will
- * call CATerminateBLEGattClient function.
- * @return ::CA_STATUS_OK or Appropriate error code.
- * @retval ::CA_STATUS_OK  Successful.
- * @retval ::CA_STATUS_INVALID_PARAM  Invalid input arguments.
- * @retval ::CA_STATUS_FAILED Operation failed.
+ * Stop Gatt client gracefully.  In turn it will call the
+ * @c CATerminateBLEGattClient function.
+ *
+ * @return ::CA_STATUS_OK or Appropriate error code
+ * @retval ::CA_STATUS_OK  Successful
+ * @retval ::CA_STATUS_INVALID_PARAM  Invalid input arguments
+ * @retval ::CA_STATUS_FAILED Operation failed
  */
 void CAStopLEGattClient();
 
 /**
- * Used to unset all the callbacks and stop service discovery.
+ * Unset all the callbacks and stop service discovery
  */
 void CATerminateLEGattClient();
 
 /**
- * API to read the data from characteristics and invoke notifyCallback.
+ * Read the data from characteristics and invoke notify callback.
  */
 void CACheckLEData();
 
 /**
- * Sets the value of characteristic and update the value to GATTServer(unicast).
+ * Set the value of characteristic and update the value to
+ * GATTServer (unicast).
  *
- * @param[in]  remoteAddress   The address of the remote device.
- * @param[in]  data            The value of characteristic (byte array).
- * @param[in]  dataLen         The length of value.
- * @param[in]  type            Type of the transfer(::CALETransferType_t).
- * @param[in]  position        The unique index of each ble server. Used for multicast feature.
+ * @param[in] remoteAddress The address of the remote device
+ * @param[in] data          The value of characteristic (byte array)
+ * @param[in] dataLen       The length of value
+ * @param[in] type          Type of the transfer(::CALETransferType_t)
+ * @param[in] position      The unique index of each ble server. Used
+ *                          for multicast feature.
  *
- * @return ::CA_STATUS_OK or Appropriate error code.
- * @retval ::CA_STATUS_OK  Successful.
- * @retval ::CA_STATUS_INVALID_PARAM  Invalid input arguments.
- * @retval ::CA_STATUS_FAILED Operation failed.
+ * @return ::CA_STATUS_OK or Appropriate error code
+ * @retval ::CA_STATUS_OK  Successful
+ * @retval ::CA_STATUS_INVALID_PARAM  Invalid input arguments
+ * @retval ::CA_STATUS_FAILED Operation failed
  */
-CAResult_t  CAUpdateCharacteristicsToGattServer(const char *remoteAddress, const char  *data,
-                                                const uint32_t dataLen, CALETransferType_t type,
-                                                const int32_t position);
+CAResult_t  CAUpdateCharacteristicsToGattServer(const char *remoteAddress,
+                                                const char  *data,
+                                                uint32_t dataLen,
+                                                CALETransferType_t type,
+                                                int32_t position);
 
 /**
- * Sets the value of characteristic and update the value to all registered.
- * GATTServer -> Multicast.
- * @param[in]  data          The value of characteristic (byte array).
- * @param[in]  dataLen       The length of value.
+ * Set the value of characteristic and update the value to all
+ * registered GATTServer (multicast).
  *
- * @return ::CA_STATUS_OK or Appropriate error code.
- * @retval ::CA_STATUS_OK  Successful.
- * @retval ::CA_STATUS_INVALID_PARAM  Invalid input arguments.
- * @retval ::CA_STATUS_FAILED Operation failed.
+ * @param[in]  data    The value of characteristic (byte array)
+ * @param[in]  dataLen The length of value
+ *
+ * @return ::CA_STATUS_OK or Appropriate error code
+ * @retval ::CA_STATUS_OK  Successful
+ * @retval ::CA_STATUS_INVALID_PARAM  Invalid input arguments
+ * @retval ::CA_STATUS_FAILED Operation failed
  */
-CAResult_t  CAUpdateCharacteristicsToAllGattServers(const char  *data, uint32_t dataLen);
+CAResult_t CAUpdateCharacteristicsToAllGattServers(const char *data,
+                                                   uint32_t dataLen);
 
 /**
- * Used to store upper layer callback locally which will be used
- * to send the data to application.
- * @param[in]  callback  Callback function to pass the data to CA layer.
+ * Store upper layer callback locally which will be used to send the
+ * data to application.
+ *
+ * @param[in] callback Callback function to pass the data to CA layer.
  */
-void CASetLEReqRespClientCallback(CABLEClientDataReceivedCallback callback);
+void CASetLEReqRespClientCallback(CABLEDataReceivedCallback callback);
 
 /**
- * Used to Set the gThreadPool handle which is required for spawning new thread.
+ * Set the server thread pool handle which is required for spawning
+ * new thread.
  *
- * @param[in] handle     Thread pool handle which is given by above layer
- *                       for using thread creation task.
- * @return ::CA_STATUS_OK or Appropriate error code.
- * @retval ::CA_STATUS_OK  Successful.
- * @retval ::CA_STATUS_INVALID_PARAM  Invalid input arguments.
- * @retval ::CA_STATUS_FAILED Operation failed.
+ * @param[in] handle Thread pool handle which is given by above layer
+ *                   for using thread creation task.
+ *
+ * @return ::CA_STATUS_OK or Appropriate error code
+ * @retval ::CA_STATUS_OK  Successful
+ * @retval ::CA_STATUS_INVALID_PARAM  Invalid input arguments
+ * @retval ::CA_STATUS_FAILED Operation failed
  */
 void CASetLEServerThreadPoolHandle(ca_thread_pool_t handle);
 
 /**
-* Used to Set the gThreadPool handle which is required for spawning new thread.
-* @param[in] handle      Thread pool handle which is given by above layer
-*                        for using thread creation task.
+* Set the client thread pool handle which is required for spawning new
+* thread.
+*
+* @param[in] handle Thread pool handle which is given by above layer
+*                   for using thread creation task.
 */
 void CASetLEClientThreadPoolHandle(ca_thread_pool_t handle);
 
 /**
- * Used to unset the callback of adapter connection state change.
+ * Unset the callback of adapter connection state change.
  *
  * @return ::CA_STATUS_OK or Appropriate error code.
  * @retval ::CA_STATUS_OK  Successful.
@@ -284,25 +345,31 @@ void CASetLEClientThreadPoolHandle(ca_thread_pool_t handle);
 CAResult_t CAUnSetLEAdapterStateChangedCb();
 
 /**
- * This will be used to notify errors in BLE adapter
- * @param[in]  remoteAddress    Remote endpoint Address.
- * @param[in]  serviceUUID      Service UUID.
- * @param[in]  data             Data received.
- * @param[in]  dataLength       Length of the data received.
- * @param[in]  result           error code as per CAResult_t.
+ * This will be used to notify errors in BLE adapter.
+ *
+ * @param[in] remoteAddress Remote endpoint Address
+ * @param[in] data          Data received
+ * @param[in] dataLength    Length of the data received
+ * @param[in] result        error code as per CAResult_t
  */
-typedef void (*CABLEErrorHandleCallback)(const char *remoteAddress, const void *data,
-                                         uint32_t dataLength, CAResult_t result);
+typedef void (*CABLEErrorHandleCallback)(const char *remoteAddress,
+                                         const void *data,
+                                         uint32_t dataLength,
+                                         CAResult_t result);
 /**
- * sets the error handle callback.
- * @param[in]  callback     Callback function to update error to the adapter.
+ * Set the client error handler callback.
+ *
+ * @param[in] callback Callback function to update error to the
+ *                     adapter.
  */
 void CASetBLEClientErrorHandleCallback(CABLEErrorHandleCallback callback);
 
 
 /**
- * sets the error handle callback.
- * @param[in]  callback     Callback function to update error to the adapter.
+ * Set the server error handler callback.
+ *
+ * @param[in] callback Callback function to update error to the
+ *                     adapter.
  */
 void CASetBLEServerErrorHandleCallback(CABLEErrorHandleCallback callback);
 
@@ -311,4 +378,3 @@ void CASetBLEServerErrorHandleCallback(CABLEErrorHandleCallback callback);
 #endif
 
 #endif /* CA_LE_INTERFACE_H_ */
-
index c5468a1..ddbfa21 100644 (file)
@@ -11,11 +11,8 @@ print "Reading BLE adapter script for", target_os
 
 src_dir = os.path.join(os.curdir, 'bt_le_adapter')
 
-# Source files to build common for all platforms.
-common_files = None
-common_files = [ os.path.join(src_dir,
-                                      'caleadapter.c') ]
-
+# Source files common to all platforms.
+common_files = [ os.path.join(src_dir, 'caleadapter.c') ]
 
 # Get list of target-specific source file base names, i.e. no parent
 # directories prepended to the path.
@@ -40,4 +37,3 @@ target_files = [ os.path.join(src_dir, target_os, f) for f in target_files ]
 # The list of BLE adapter source files is a combination of both the
 # common and target-specific source file lists.
 env.AppendUnique(CA_SRC = common_files + target_files)
-
index adaf0d5..f97d59b 100644 (file)
@@ -78,7 +78,7 @@ static ca_mutex g_deviceListMutex = NULL;
 static ca_mutex g_gattObjectMutex = NULL;
 static ca_mutex g_deviceStateListMutex = NULL;
 
-static CABLEClientDataReceivedCallback g_CABLEClientDataReceivedCallback = NULL;
+static CABLEDataReceivedCallback g_CABLEClientDataReceivedCallback = NULL;
 
 //getting jvm
 void CALEClientJniInit()
@@ -3127,8 +3127,8 @@ void CATerminateLEGattClient()
 }
 
 CAResult_t  CAUpdateCharacteristicsToGattServer(const char *remoteAddress, const char  *data,
-                                                const uint32_t dataLen, CALETransferType_t type,
-                                                const int32_t position)
+                                                uint32_t dataLen, CALETransferType_t type,
+                                                int32_t position)
 {
     OIC_LOG(DEBUG, TAG, "call CALEClientSendUnicastMessage");
     VERIFY_NON_NULL(data, TAG, "data is null");
@@ -3145,7 +3145,7 @@ CAResult_t CAUpdateCharacteristicsToAllGattServers(const char *data, uint32_t da
     return CALEClientSendMulticastMessage(data, dataLen);
 }
 
-void CASetLEReqRespClientCallback(CABLEClientDataReceivedCallback callback)
+void CASetLEReqRespClientCallback(CABLEDataReceivedCallback callback)
 {
     OIC_LOG(DEBUG, TAG, "IN");
 
@@ -3574,7 +3574,7 @@ Java_org_iotivity_ca_CaLeClientInterface_caLeGattCharacteristicChangedCallback(
 
     ca_mutex_lock(g_bleServerBDAddressMutex);
     uint32_t sentLength = 0;
-    g_CABLEClientDataReceivedCallback(address, OIC_GATT_SERVICE_UUID, receivedData, length,
+    g_CABLEClientDataReceivedCallback(address, receivedData, length,
                                       &sentLength);
     ca_mutex_unlock(g_bleServerBDAddressMutex);
 
index 28da4db..328cd3e 100644 (file)
@@ -83,6 +83,13 @@ CAResult_t CAInitializeLEAdapter()
     return CA_STATUS_OK;
 }
 
+CAResult_t CAStartLEAdapter()
+{
+    // Nothing to do.
+
+    return CA_STATUS_OK;
+}
+
 CAResult_t CAInitLENwkMonitorMutexVaraibles()
 {
     OIC_LOG(DEBUG, TAG, "IN");
index e9680c5..994f9b4 100644 (file)
@@ -52,7 +52,7 @@ static ca_thread_pool_t g_threadPoolHandle = NULL;
 static bool g_isStartServer = false;
 static bool g_isInitializedServer = false;
 
-static CABLEServerDataReceivedCallback g_CABLEServerDataReceivedCallback = NULL;
+static CABLEDataReceivedCallback g_CABLEServerDataReceivedCallback = NULL;
 static ca_mutex g_bleReqRespCbMutex = NULL;
 static ca_mutex g_bleClientBDAddressMutex = NULL;
 static ca_mutex g_connectedDeviceListMutex = NULL;
@@ -2264,7 +2264,7 @@ Java_org_iotivity_ca_CaLeServerInterface_caLeGattServerCharacteristicWriteReques
 
     ca_mutex_lock(g_bleClientBDAddressMutex);
     uint32_t sentLength = 0;
-    g_CABLEServerDataReceivedCallback(address, OIC_GATT_SERVICE_UUID, requestData, length,
+    g_CABLEServerDataReceivedCallback(address, requestData, length,
                                       &sentLength);
     ca_mutex_unlock(g_bleClientBDAddressMutex);
 
@@ -2374,7 +2374,7 @@ void CATerminateLEGattServer()
     OIC_LOG(DEBUG, TAG, "OUT");
 }
 
-void CASetLEReqRespServerCallback(CABLEServerDataReceivedCallback callback)
+void CASetLEReqRespServerCallback(CABLEDataReceivedCallback callback)
 {
     OIC_LOG(DEBUG, TAG, "IN");
 
@@ -2390,8 +2390,9 @@ void CASetBLEServerErrorHandleCallback(CABLEErrorHandleCallback callback)
     g_serverErrorCallback = callback;
 }
 
-CAResult_t CAUpdateCharacteristicsToGattClient(const char* address, const char *charValue,
-                                               const uint32_t charValueLen)
+CAResult_t CAUpdateCharacteristicsToGattClient(const char *address,
+                                               const char *charValue,
+                                               uint32_t charValueLen)
 {
     CAResult_t result = CA_SEND_FAILED;
     OIC_LOG(DEBUG, TAG, "IN");
index b56bcd7..8969b3e 100644 (file)
@@ -27,6 +27,7 @@
 
 #include "cacommon.h"
 #include "cathreadpool.h"
+#include "cagattservice.h"
 #include "uarraylist.h"
 #include "jni.h"
 
@@ -36,9 +37,9 @@ extern "C"
 #endif
 
 /* Service UUID */
-static const char OIC_GATT_SERVICE_UUID[] = "ADE3D529-C784-4F63-A987-EB69F70EE816";
-static const char OIC_GATT_CHARACTERISTIC_REQUEST_UUID[] = "AD7B334F-4637-4B86-90B6-9D787F03D218";
-static const char OIC_GATT_CHARACTERISTIC_RESPONSE_UUID[] = "E9241982-4580-42C4-8831-95048216B256";
+static const char OIC_GATT_SERVICE_UUID[] = CA_GATT_SERVICE_UUID;
+static const char OIC_GATT_CHARACTERISTIC_REQUEST_UUID[] = CA_GATT_REQUEST_CHRC_UUID;
+static const char OIC_GATT_CHARACTERISTIC_RESPONSE_UUID[] = CA_GATT_RESPONSE_CHRC_UUID;
 static const char OIC_GATT_CHARACTERISTIC_CONFIG_UUID[] = "00002902-0000-1000-8000-00805f9b34fb";
 
 static const uint32_t GATT_SUCCESS = 0;
index 6ea6967..ad99a59 100644 (file)
@@ -30,7 +30,7 @@ void CASetLEClientThreadPoolHandle(ca_thread_pool_t handle)
     OIC_LOG(DEBUG, TAG, "IN");
     OIC_LOG(DEBUG, TAG, "OUT");
 }
-void CASetLEReqRespClientCallback(CABLEClientDataReceivedCallback callback)
+void CASetLEReqRespClientCallback(CABLEDataReceivedCallback callback)
 {
     OIC_LOG(DEBUG, TAG, "IN");
     OIC_LOG(DEBUG, TAG, "OUT");
index 2740a70..0466261 100644 (file)
@@ -70,6 +70,13 @@ CAResult_t CAInitializeLEAdapter()
     return CA_STATUS_OK;
 }
 
+CAResult_t CAStartLEAdapter()
+{
+    // Nothing to do.
+
+    return CA_STATUS_OK;
+}
+
 CAResult_t CAGetLEAdapterState()
 {
     OIC_LOG(DEBUG, TAG, "IN");
index 74f9b14..09b4e20 100644 (file)
@@ -41,7 +41,7 @@
  * @brief  Maintains the callback to be notified on receival of network packets from other
  *           BLE devices
  */
-static CABLEServerDataReceivedCallback g_bleServerDataReceivedCallback = NULL;
+static CABLEDataReceivedCallback g_bleServerDataReceivedCallback = NULL;
 
 /**
  * @def MAX_EVENT_COUNT
@@ -113,7 +113,7 @@ void CACheckLEDataInternal()
                     OIC_LOG_V(DEBUG, TAG, "recv dataLen=%d", g_receivedDataLen);
                     uint32_t sentLength = 0;
                     // g_coapBuffer getting freed by CAMesssageHandler
-                    g_bleServerDataReceivedCallback("", "", g_coapBuffer,
+                    g_bleServerDataReceivedCallback("", g_coapBuffer,
                                                     g_receivedDataLen, &sentLength);
                 }
 
@@ -188,7 +188,7 @@ CAResult_t CAUpdateCharacteristicsToAllGattClients(const char *char_value,
     return CA_STATUS_OK;
 }
 
-void CASetLEReqRespServerCallback(CABLEServerDataReceivedCallback callback)
+void CASetLEReqRespServerCallback(CABLEDataReceivedCallback callback)
 {
     OIC_LOG(DEBUG, TAG, "IN");
     g_bleServerDataReceivedCallback = callback;
index 20cd845..6586b92 100644 (file)
  */
 #define CALEADAPTER_TAG "LAD"
 
+
+/**
+ * Stores the information of the Data to be sent from the queues.
+ *
+ * This structure will be pushed to the sender/receiver queue for
+ * processing.
+ */
+typedef struct
+{
+    CAEndpoint_t *remoteEndpoint;   /**< Remote endpoint contains the
+                                       information of remote device. */
+    void *data;        /**< Data to be transmitted over LE transport. */
+    uint32_t dataLen;  /**< Length of the data being transmitted. */
+} CALEData_t;
+
+/**
+ * Stores information of all the senders.
+ *
+ * This structure will be used to track and defragment all incoming
+ * data packet.
+ */
+typedef struct
+{
+    uint32_t recvDataLen;
+    uint32_t totalDataLen;
+    char *defragData;
+    CAEndpoint_t *remoteEndpoint;
+ } CABLESenderInfo_t;
+
 /**
  * Callback to provide the status of the network change to CA layer.
  */
 static CANetworkChangeCallback g_networkCallback = NULL;
 
 /**
- * bleAddress of the local adapter. Value will be initialized to zero, and will
- *        be updated later.
+ * bleAddress of the local adapter. Value will be initialized to zero,
+ * and will be updated later.
  */
-static char g_localBLEAddress[18] = {0};
+static char g_localBLEAddress[18] = { 0 };
 
 /**
  * Variable to differentiate btw GattServer and GattClient.
@@ -56,23 +85,25 @@ static char g_localBLEAddress[18] = {0};
 static bool g_isServer = false;
 
 /**
- * Mutex to synchronize the task to be executed on the GattServer function
- * calls.
+ * Mutex to synchronize the task to be executed on the GattServer
+ * function calls.
  */
 static ca_mutex g_bleIsServerMutex = NULL;
 
 /**
- * Mutex to synchronize the callback to be called for the network changes.
+ * Mutex to synchronize the callback to be called for the network
+ * changes.
  */
 static ca_mutex g_bleNetworkCbMutex = NULL;
 
 /**
- * Mutex to synchronize the updation of the local LE address of the adapter.
+ * Mutex to synchronize the updates of the local LE address of the
+ * adapter.
  */
 static ca_mutex g_bleLocalAddressMutex = NULL;
 
 /**
- * reference to threadpool.
+ * Reference to thread pool.
  */
 static ca_thread_pool_t g_bleAdapterThreadPool = NULL;
 
@@ -98,12 +129,13 @@ static ca_mutex g_bleReceiveDataMutex = NULL;
 static ca_mutex g_bleServerSendDataMutex = NULL;
 
 /**
- * Mutex to synchronize the callback to be called for the adapterReqResponse.
+ * Mutex to synchronize the callback to be called for the
+ * adapterReqResponse.
  */
 static ca_mutex g_bleAdapterReqRespCbMutex = NULL;
 
 /**
- * Callback to be called when network packet recieved from either
+ * Callback to be called when network packet received from either
  * GattServer or GattClient.
  */
 static CANetworkPacketReceivedCallback g_networkPacketReceivedCallback = NULL;
@@ -119,8 +151,9 @@ static CAErrorHandleCallback g_errorHandler = NULL;
 static CAAdapterState_t g_bleAdapterState = CA_ADAPTER_DISABLED;
 
 /**
- * status of BLE Server Status.
- * This ENUM provides information of LE Adapter Server status.
+ * BLE Server Status.
+ *
+ * This enumeration provides information of LE Adapter Server status.
  */
 typedef enum
 {
@@ -130,65 +163,68 @@ typedef enum
 } CALeServerStatus;
 
 /**
- * structure to maintain the status of the server.
+ * Structure to maintain the status of the server.
  */
 static CALeServerStatus gLeServerStatus = CA_SERVER_NOTSTARTED;
 
 /**
-* This function is used to register network change notification callback.
-*
-* @param[in]  netCallback CANetworkChangeCallback callback which will be
-* set for the change in nwk.
-*
-* @return  0 on success otherwise a positive error value.
-* @retval  CA_STATUS_OK  Successful.
-* @retval  CA_STATUS_INVALID_PARAM  Invalid input argumets.
-* @retval  CA_STATUS_FAILED Operation failed.
-*
-*/
-CAResult_t CALERegisterNetworkNotifications(CANetworkChangeCallback netCallback);
+ * Register network change notification callback.
+ *
+ * @param[in]  netCallback CANetworkChangeCallback callback which will
+ *                         be set for the change in network.
+ *
+ * @return  0 on success otherwise a positive error value.
+ * @retval  ::CA_STATUS_OK  Successful.
+ * @retval  ::CA_STATUS_INVALID_PARAM  Invalid input arguments.
+ * @retval  ::CA_STATUS_FAILED Operation failed.
+ *
+ */
+static CAResult_t CALERegisterNetworkNotifications(CANetworkChangeCallback netCallback);
 
 /**
-* Used to Set the gThreadPool handle which is required for spawning new thread.
-*
-* @param[in] handle - Thread pool handle which is given by above layer for
-* using thread creation task.
-*
-*/
-void CASetLEAdapterThreadPoolHandle(ca_thread_pool_t handle);
+ * Set the thread pool handle which is required for spawning new
+ * thread.
+ *
+ * @param[in] handle Thread pool handle which is given by above layer
+ *                   for using thread creation task.
+ *
+ */
+static void CASetLEAdapterThreadPoolHandle(ca_thread_pool_t handle);
 
 /**
-* This function is used to call the callback to the upper layer when the
-* device state gets changed.
-*
-* @param[in]  adapter_state New state of the adapter to be notified to the
-* upper layer.
-*
-*/
-void CALEDeviceStateChangedCb( CAAdapterState_t adapter_state);
+ * Call the callback to the upper layer when the device state gets
+ * changed.
+ *
+ * @param[in] adapter_state New state of the adapter to be notified to
+ *                          the upper layer.
+ */
+static void CALEDeviceStateChangedCb( CAAdapterState_t adapter_state);
 
 /**
-* Used to initialize all required mutex variable for LE Adapter implementation.
-*
-* @return  0 on success otherwise a positive error value.
-* @retval  CA_STATUS_OK  Successful.
-* @retval  CA_STATUS_INVALID_PARAM  Invalid input argumets.
-* @retval  CA_STATUS_FAILED Operation failed.
-*
-*/
-CAResult_t CAInitLEAdapterMutex();
+ * Used to initialize all required mutex variable for LE Adapter
+ * implementation.
+ *
+ * @return  0 on success otherwise a positive error value.
+ * @retval  ::CA_STATUS_OK  Successful.
+ * @retval  ::CA_STATUS_INVALID_PARAM  Invalid input arguments.
+ * @retval  ::CA_STATUS_FAILED Operation failed.
+ *
+ */
+static CAResult_t CAInitLEAdapterMutex();
 
 /**
-* Used to terminate all required mutex variable for LE adapter implementation.
-*
-*/
-void CATerminateLEAdapterMutex();
+ * Terminate all required mutex variables for LE adapter
+ * implementation.
+ */
+static void CATerminateLEAdapterMutex();
 
 /**
-* prepares and notify error through error callback.
-*
-*/
-static void CALEErrorHandler(const char *remoteAddress, const void *data, uint32_t dataLen,
+ * Prepares and notify error through error callback.
+ *
+ */
+static void CALEErrorHandler(const char *remoteAddress,
+                             const void *data,
+                             uint32_t dataLen,
                              CAResult_t result);
 
 #ifndef SINGLE_THREAD
@@ -198,7 +234,7 @@ static void CALEErrorHandler(const char *remoteAddress, const void *data, uint32
 static bool g_dataReceiverHandlerState = false;
 
 /**
- * Sender informations to be stored here
+ * Sender information.
  */
 static u_arraylist_t *g_senderInfo = NULL;
 
@@ -218,33 +254,343 @@ static CAQueueingThread_t *g_bleReceiverQueue = NULL;
 static CAQueueingThread_t *g_bleServerSendQueueHandle = NULL;
 
 /**
-* Used to free data.
-*
-*/
-static void CALEDataDestroyer(void *data, uint32_t size);
+ * Starting LE connectivity adapters.
+ *
+ * As its peer to peer it does not require to start any servers.
+ *
+ * @return ::CA_STATUS_OK or Appropriate error code.
+ */
+static CAResult_t CAStartLE();
 
-void CAInitLEQueues()
-{
-    OIC_LOG(DEBUG, CALEADAPTER_TAG, "IN");
+/**
+ * Start listening server for receiving multicast search requests.
+ *
+ * Transport Specific Behavior:
+ *   LE  Starts GATT Server with prefixed UUID and Characteristics
+ *   per OIC Specification.
+ * @return  ::CA_STATUS_OK or Appropriate error code.
+ */
+static CAResult_t CAStartLEListeningServer();
 
-    CAResult_t result = CAInitLEServerQueues();
-    if (CA_STATUS_OK != result)
-    {
-        OIC_LOG(ERROR, CALEADAPTER_TAG, "CAInitBleServerQueues failed");
-        return;
-    }
+/**
+ * Sarting discovery of servers for receiving multicast
+ * advertisements.
+ *
+ * Transport Specific Behavior:
+ *   LE  Starts GATT Server with prefixed UUID and Characteristics
+ *   per OIC Specification.
+ *
+ * @return ::CA_STATUS_OK or Appropriate error code
+ */
+static CAResult_t CAStartLEDiscoveryServer();
 
-    result = CAInitLEClientQueues();
-    if (CA_STATUS_OK != result)
-    {
-        OIC_LOG(ERROR, CALEADAPTER_TAG, "CAInitBleClientQueues failed");
-        return;
-    }
+/**
+ * Send data to the endpoint using the adapter connectivity.
+ *
+ * @param[in] endpoint Remote Endpoint information (like MAC address,
+ *                     reference URI and connectivity type) to which
+ *                     the unicast data has to be sent.
+ * @param[in] data     Data which required to be sent.
+ * @param[in] dataLen  Size of data to be sent.
+ *
+ * @note  dataLen must be > 0.
+ *
+ * @return The number of bytes sent on the network, or -1 on error.
+ */
+static int32_t CASendLEUnicastData(const CAEndpoint_t *endpoint,
+                                   const void *data,
+                                   uint32_t dataLen);
 
-    OIC_LOG(DEBUG, CALEADAPTER_TAG, "OUT");
-}
+/**
+ * Send multicast data to the endpoint using the LE connectivity.
+ *
+ * @param[in] endpoint Remote Endpoint information to which the
+ *                     multicast data has to be sent.
+ * @param[in] data     Data which required to be sent.
+ * @param[in] dataLen  Size of data to be sent.
+ *
+ * @note  dataLen must be > 0.
+ *
+ * @return The number of bytes sent on the network, or -1 on error.
+ */
+static int32_t CASendLEMulticastData(const CAEndpoint_t *endpoint,
+                                     const void *data,
+                                     uint32_t dataLen);
+
+/**
+ * Get LE Connectivity network information.
+ *
+ * @param[out] info Local connectivity information structures.
+ * @param[out] size Number of local connectivity structures.
+ *
+ * @return ::CA_STATUS_OK or Appropriate error code.
+ */
+static CAResult_t CAGetLEInterfaceInformation(CAEndpoint_t **info,
+                                              uint32_t *size);
+
+/**
+ * Read Synchronous API callback.
+ *
+ * @return  ::CA_STATUS_OK or Appropriate error code.
+ */
+static CAResult_t CAReadLEData();
+
+/**
+ * Stopping the adapters and close socket connections.
+ *
+ * LE Stops all GATT servers and GATT Clients.
+ *
+ * @return ::CA_STATUS_OK or Appropriate error code.
+ */
+static CAResult_t CAStopLE();
+
+/**
+ * Terminate the LE connectivity adapter.
+ *
+ * Configuration information will be deleted from further use.
+ */
+static void CATerminateLE();
+
+/**
+ * This function will receive the data from the GattServer and add the
+ * data to the Server receiver queue.
+ *
+ * @param[in] remoteAddress Remote address of the device from where
+ *                          data is received.
+ * @param[in] data          Actual data recevied from the remote
+ *                          device.
+ * @param[in] dataLength    Length of the data received from the
+ *                          remote device.
+ * @param[in] sentLength    Length of the data sent from the remote
+ *                          device.
+ *
+ * @return ::CA_STATUS_OK or Appropriate error code.
+ * @retval ::CA_STATUS_OK  Successful.
+ * @retval ::CA_STATUS_INVALID_PARAM  Invalid input arguments.
+ * @retval ::CA_STATUS_FAILED Operation failed.
+ *
+ */
+static CAResult_t CALEAdapterServerReceivedData(const char *remoteAddress,
+                                                const void *data,
+                                                uint32_t dataLength,
+                                                uint32_t *sentLength);
+
+/**
+ * This function will receive the data from the GattClient and add the
+ * data into the Client receiver queue.
+ *
+ * @param[in] remoteAddress Remote address of the device from where
+ *                          data is received.
+ * @param[in] data          Actual data recevied from the remote
+ *                          device.
+ * @param[in] dataLength    Length of the data received from the
+ *                          remote device.
+ * @param[in] sentLength    Length of the data sent from the remote
+ *                          device.
+ *
+ * @return ::CA_STATUS_OK or Appropriate error code.
+ * @retval ::CA_STATUS_OK  Successful.
+ * @retval ::CA_STATUS_INVALID_PARAM  Invalid input arguments.
+ * @retval ::CA_STATUS_FAILED Operation failed.
+ */
+static CAResult_t CALEAdapterClientReceivedData(const char *remoteAddress,
+                                                const void *data,
+                                                uint32_t dataLength,
+                                                uint32_t *sentLength);
+
+/**
+ * Set the NetworkPacket received callback to CA layer from adapter
+ * layer.
+ *
+ * @param[in] callback Callback handle sent from the upper layer.
+ */
+static void CASetLEReqRespAdapterCallback(CANetworkPacketReceivedCallback callback);
 
-CAResult_t CAInitLEServerQueues()
+/**
+ * Push the data from CA layer to the Sender processor queue.
+ *
+ * @param[in] remoteEndpoint Remote endpoint information of the
+ *                           server.
+ * @param[in] data           Data to be transmitted from LE.
+ * @param[in] dataLen        Length of the Data being transmitted.
+ *
+ * @return ::CA_STATUS_OK or Appropriate error code.
+ * @retval ::CA_STATUS_OK  Successful.
+ * @retval ::CA_STATUS_INVALID_PARAM  Invalid input arguments.
+ * @retval ::CA_STATUS_FAILED Operation failed.
+ */
+static CAResult_t CALEAdapterServerSendData(const CAEndpoint_t *remoteEndpoint,
+                                            const void *data,
+                                            uint32_t dataLen);
+
+/**
+ * Push the data from CA layer to the Sender processor queue.
+ *
+ * @param[in] remoteEndpoint Remote endpoint information of the
+ *                           server.
+ * @param[in] data           Data to be transmitted from LE.
+ * @param[in] dataLen        Length of the Data being transmitted.
+ *
+ * @return ::CA_STATUS_OK or Appropriate error code.
+ * @retval ::CA_STATUS_OK  Successful.
+ * @retval ::CA_STATUS_INVALID_PARAM  Invalid input arguments.
+ * @retval ::CA_STATUS_FAILED Operation failed.
+ */
+static CAResult_t CALEAdapterClientSendData(const CAEndpoint_t *remoteEndpoint,
+                                            const void *data,
+                                            uint32_t dataLen);
+
+/**
+ * This function will be associated with the sender queue for
+ * GattServer.
+ *
+ * This function will fragment the data to the MTU of the transport
+ * and send the data in fragments to the adapters. The function will
+ * be blocked until all data is sent out from the adapter.
+ *
+ * @param[in] threadData Data pushed to the queue which contains the
+ *                       info about RemoteEndpoint and Data.
+ */
+static void CALEServerSendDataThread(void *threadData);
+
+/**
+ * This function will be associated with the sender queue for
+ * GattClient.
+ *
+ * This function will fragment the data to the MTU of the transport
+ * and send the data in fragments to the adapters. The function will
+ * be blocked until all data is sent out from the adapter.
+ *
+ * @param[in] threadData Data pushed to the queue which contains the
+ *                       info about RemoteEndpoint and Data.
+ */
+static void CALEClientSendDataThread(void *threadData);
+
+/**
+ * This function will be associated with the receiver queue.
+ *
+ * This function will defragment the received data from each sender
+ * respectively and will send it up to CA layer.  Respective sender's
+ * header will provide the length of the data sent.
+ *
+ * @param[in] threadData Data pushed to the queue which contains the
+ *                       info about RemoteEndpoint and Data.
+ */
+static void CALEDataReceiverHandler(void *threadData);
+
+/**
+ * This function will stop all queues created for GattServer and
+ * GattClient. All four queues will be be stopped with this function
+ * invocations.
+ */
+static void CAStopLEQueues();
+
+/**
+ * This function will terminate all queues created for GattServer and
+ * GattClient. All four queues will be be terminated with this
+ * function invocations.
+ */
+static void CATerminateLEQueues();
+
+/**
+ * This function will initalize the Receiver and Sender queues for
+ * GattServer. This function will in turn call the functions
+ * CAInitBleServerReceiverQueue() and CAInitBleServerSenderQueue() to
+ * initialize the queues.
+ *
+ * @return ::CA_STATUS_OK or Appropriate error code.
+ * @retval ::CA_STATUS_OK  Successful.
+ * @retval ::CA_STATUS_INVALID_PARAM  Invalid input arguments.
+ * @retval ::CA_STATUS_FAILED Operation failed.
+ */
+static CAResult_t CAInitLEServerQueues();
+
+/**
+ * This function will initalize the Receiver and Sender queues for
+ * GattClient. This function will inturn call the functions
+ * CAInitBleClientReceiverQueue() and CAInitBleClientSenderQueue() to
+ * initialize the queues.
+ *
+ * @return ::CA_STATUS_OK or Appropriate error code.
+ * @retval ::CA_STATUS_OK  Successful.
+ * @retval ::CA_STATUS_INVALID_PARAM  Invalid input arguments.
+ * @retval ::CA_STATUS_FAILED Operation failed.
+ *
+ */
+static CAResult_t CAInitLEClientQueues();
+
+/**
+ * This function will initalize the Receiver queue for
+ * GattServer. This will initialize the queue to process the function
+ * CABLEServerSendDataThread() when ever the task is added to this
+ * queue.
+ *
+ * @return ::CA_STATUS_OK or Appropriate error code.
+ * @retval ::CA_STATUS_OK  Successful.
+ * @retval ::CA_STATUS_INVALID_PARAM  Invalid input arguments.
+ * @retval ::CA_STATUS_FAILED Operation failed.
+ */
+static CAResult_t CAInitLEServerSenderQueue();
+
+/**
+ * This function will initalize the Receiver queue for
+ * GattClient. This will initialize the queue to process the function
+ * CABLEClientSendDataThread() when ever the task is added to this
+ * queue.
+ *
+ * @return ::CA_STATUS_OK or Appropriate error code.
+ * @retval ::CA_STATUS_OK  Successful.
+ * @retval ::CA_STATUS_INVALID_PARAM  Invalid input arguments.
+ * @retval ::CA_STATUS_FAILED Operation failed.
+ */
+static CAResult_t CAInitLEClientSenderQueue();
+
+/**
+ * This function will initialize the Receiver queue for
+ * LEAdapter. This will initialize the queue to process the function
+ * CABLEDataReceiverHandler() when ever the task is added to this
+ * queue.
+ *
+ * @return ::CA_STATUS_OK or Appropriate error code
+ * @retval ::CA_STATUS_OK  Successful
+ * @retval ::CA_STATUS_INVALID_PARAM  Invalid input arguments
+ * @retval ::CA_STATUS_FAILED Operation failed
+ *
+ */
+static CAResult_t CAInitLEReceiverQueue();
+
+/**
+ * This function will create the Data required to send it in the
+ * queue.
+ *
+ * @param[in] remoteEndpoint Remote endpoint information of the
+ *                           server.
+ * @param[in] data           Data to be transmitted from LE.
+ * @param[in] dataLength     Length of the Data being transmitted.
+ *
+ * @return ::CA_STATUS_OK or Appropriate error code.
+ * @retval ::CA_STATUS_OK  Successful.
+ * @retval ::CA_STATUS_INVALID_PARAM  Invalid input arguments.
+ * @retval ::CA_STATUS_FAILED Operation failed.
+ */
+static CALEData_t *CACreateLEData(const CAEndpoint_t *remoteEndpoint,
+                                  const void *data,
+                                  uint32_t dataLength);
+
+/**
+ * Used to free the BLE information stored in the sender/receiver
+ * queues.
+ *
+ * @param[in] bleData Information for a particular data segment.
+ */
+static void CAFreeLEData(CALEData_t *bleData);
+
+/**
+ * Free data.
+ */
+static void CALEDataDestroyer(void *data, uint32_t size);
+
+static CAResult_t CAInitLEServerQueues()
 {
     OIC_LOG(DEBUG, CALEADAPTER_TAG, "IN");
 
@@ -274,7 +620,7 @@ CAResult_t CAInitLEServerQueues()
     return CA_STATUS_OK;
 }
 
-CAResult_t CAInitLEClientQueues()
+static CAResult_t CAInitLEClientQueues()
 {
     OIC_LOG(DEBUG, CALEADAPTER_TAG, "IN");
 
@@ -304,7 +650,7 @@ CAResult_t CAInitLEClientQueues()
     return CA_STATUS_OK;
 }
 
-CAResult_t CAInitLEReceiverQueue()
+static CAResult_t CAInitLEReceiverQueue()
 {
     OIC_LOG(DEBUG, CALEADAPTER_TAG, "IN");
     // Check if the message queue is already initialized
@@ -354,7 +700,7 @@ CAResult_t CAInitLEReceiverQueue()
     return CA_STATUS_OK;
 }
 
-CAResult_t CAInitLEServerSenderQueue()
+static CAResult_t CAInitLEServerSenderQueue()
 {
     OIC_LOG(DEBUG, CALEADAPTER_TAG, "IN");
     // Check if the message queue is already initialized
@@ -394,7 +740,7 @@ CAResult_t CAInitLEServerSenderQueue()
     return CA_STATUS_OK;
 }
 
-void CALEClearSenderInfo()
+static void CALEClearSenderInfo()
 {
     OIC_LOG(DEBUG, CALEADAPTER_TAG, "IN");
 
@@ -416,7 +762,7 @@ void CALEClearSenderInfo()
     OIC_LOG(DEBUG, CALEADAPTER_TAG, "OUT");
 }
 
-CAResult_t CAInitLEClientSenderQueue()
+static CAResult_t CAInitLEClientSenderQueue()
 {
     OIC_LOG(DEBUG, CALEADAPTER_TAG, "IN");
 
@@ -456,7 +802,7 @@ CAResult_t CAInitLEClientSenderQueue()
     return CA_STATUS_OK;
 }
 
-void CAStopLEQueues()
+static void CAStopLEQueues()
 {
     OIC_LOG(DEBUG, CALEADAPTER_TAG, "IN");
 
@@ -484,7 +830,7 @@ void CAStopLEQueues()
     OIC_LOG(DEBUG, CALEADAPTER_TAG, "OUT");
 }
 
-void CATerminateLEQueues()
+static void CATerminateLEQueues()
 {
     OIC_LOG(DEBUG, CALEADAPTER_TAG, "IN");
 
@@ -505,8 +851,9 @@ void CATerminateLEQueues()
     OIC_LOG(DEBUG, CALEADAPTER_TAG, "OUT");
 }
 
-CAResult_t CALEGetSenderInfo(char *leAddress, CABLESenderInfo_t **senderInfo,
-                                        uint32_t *senderIndex)
+static CAResult_t CALEGetSenderInfo(char *leAddress,
+                                    CABLESenderInfo_t **senderInfo,
+                                    uint32_t *senderIndex)
 {
     VERIFY_NON_NULL_RET(leAddress, CALEADAPTER_TAG, "Ble-Address in-param NULL", CA_STATUS_FAILED);
     VERIFY_NON_NULL_RET(senderIndex, CALEADAPTER_TAG, "Index in-param NULL", CA_STATUS_FAILED);
@@ -535,7 +882,7 @@ CAResult_t CALEGetSenderInfo(char *leAddress, CABLESenderInfo_t **senderInfo,
     return CA_STATUS_FAILED;
 }
 
-void CALEDataReceiverHandler(void *threadData)
+static void CALEDataReceiverHandler(void *threadData)
 {
     OIC_LOG(DEBUG, CALEADAPTER_TAG, "IN");
 
@@ -686,7 +1033,7 @@ void CALEDataReceiverHandler(void *threadData)
     OIC_LOG(DEBUG, CALEADAPTER_TAG, "OUT");
 }
 
-void CALEServerSendDataThread(void *threadData)
+static void CALEServerSendDataThread(void *threadData)
 {
     OIC_LOG(DEBUG, CALEADAPTER_TAG, "IN");
 
@@ -848,7 +1195,7 @@ void CALEServerSendDataThread(void *threadData)
     OIC_LOG(DEBUG, CALEADAPTER_TAG, "OUT");
 }
 
-void CALEClientSendDataThread(void *threadData)
+static void CALEClientSendDataThread(void *threadData)
 {
     OIC_LOG(DEBUG, CALEADAPTER_TAG, "IN");
 
@@ -1018,8 +1365,9 @@ void CALEClientSendDataThread(void *threadData)
     OIC_LOG(DEBUG, CALEADAPTER_TAG, "OUT - CABLEClientSendDataThread");
 }
 
-CALEData_t *CACreateLEData(const CAEndpoint_t *remoteEndpoint, const void *data,
-                           uint32_t dataLength)
+static CALEData_t *CACreateLEData(const CAEndpoint_t *remoteEndpoint,
+                                  const void *data,
+                                  uint32_t dataLength)
 {
     CALEData_t *bleData = (CALEData_t *) OICMalloc(sizeof(CALEData_t));
     if (!bleData)
@@ -1042,7 +1390,7 @@ CALEData_t *CACreateLEData(const CAEndpoint_t *remoteEndpoint, const void *data,
     return bleData;
 }
 
-void CAFreeLEData(CALEData_t *bleData)
+static void CAFreeLEData(CALEData_t *bleData)
 {
     VERIFY_NON_NULL_VOID(bleData, CALEADAPTER_TAG, "Param bleData is NULL");
 
@@ -1051,7 +1399,7 @@ void CAFreeLEData(CALEData_t *bleData)
     OICFree(bleData);
 }
 
-void CALEDataDestroyer(void *data, uint32_t size)
+static void CALEDataDestroyer(void *data, uint32_t size)
 {
     CALEData_t *ledata = (CALEData_t *) data;
 
@@ -1059,7 +1407,7 @@ void CALEDataDestroyer(void *data, uint32_t size)
 }
 #endif
 
-CAResult_t CAInitLEAdapterMutex()
+static CAResult_t CAInitLEAdapterMutex()
 {
     OIC_LOG(DEBUG, CALEADAPTER_TAG, "IN");
 
@@ -1153,7 +1501,7 @@ CAResult_t CAInitLEAdapterMutex()
     return CA_STATUS_OK;
 }
 
-void CATerminateLEAdapterMutex()
+static void CATerminateLEAdapterMutex()
 {
     OIC_LOG(DEBUG, CALEADAPTER_TAG, "IN");
 
@@ -1187,7 +1535,8 @@ void CATerminateLEAdapterMutex()
 CAResult_t CAInitializeLE(CARegisterConnectivityCallback registerCallback,
                           CANetworkPacketReceivedCallback reqRespCallback,
                           CANetworkChangeCallback netCallback,
-                          CAErrorHandleCallback errorCallback, ca_thread_pool_t handle)
+                          CAErrorHandleCallback errorCallback,
+                          ca_thread_pool_t handle)
 {
     OIC_LOG(DEBUG, CALEADAPTER_TAG, "IN");
 
@@ -1225,16 +1574,19 @@ CAResult_t CAInitializeLE(CARegisterConnectivityCallback registerCallback,
 
     g_errorHandler = errorCallback;
 
-    CAConnectivityHandler_t connHandler;
-    connHandler.startAdapter = CAStartLE;
-    connHandler.stopAdapter = CAStopLE;
-    connHandler.startListenServer = CAStartLEListeningServer;
-    connHandler.startDiscoveryServer = CAStartLEDiscoveryServer;
-    connHandler.sendData = CASendLEUnicastData;
-    connHandler.sendDataToAll = CASendLEMulticastData;
-    connHandler.GetnetInfo = CAGetLEInterfaceInformation;
-    connHandler.readData = CAReadLEData;
-    connHandler.terminate = CATerminateLE;
+    static const CAConnectivityHandler_t connHandler =
+        {
+            .startAdapter = CAStartLE,
+            .stopAdapter = CAStopLE,
+            .startListenServer = CAStartLEListeningServer,
+            .startDiscoveryServer = CAStartLEDiscoveryServer,
+            .sendData = CASendLEUnicastData,
+            .sendDataToAll = CASendLEMulticastData,
+            .GetnetInfo = CAGetLEInterfaceInformation,
+            .readData = CAReadLEData,
+            .terminate = CATerminateLE
+        };
+
     registerCallback(connHandler, CA_ADAPTER_GATT_BTLE);
 
     OIC_LOG(DEBUG, CALEADAPTER_TAG, "OUT");
@@ -1242,15 +1594,14 @@ CAResult_t CAInitializeLE(CARegisterConnectivityCallback registerCallback,
     return CA_STATUS_OK;
 }
 
-CAResult_t CAStartLE()
+static CAResult_t CAStartLE()
 {
-    OIC_LOG(DEBUG, CALEADAPTER_TAG, "IN");
-    OIC_LOG(DEBUG, CALEADAPTER_TAG, "CAStartLE, not implemented");
-    OIC_LOG(DEBUG, CALEADAPTER_TAG, "OUT");
-    return CA_STATUS_OK;
+    OIC_LOG(DEBUG, CALEADAPTER_TAG, __func__);
+
+    return CAStartLEAdapter();
 }
 
-CAResult_t CAStopLE()
+static CAResult_t CAStopLE()
 {
     OIC_LOG(DEBUG, CALEADAPTER_TAG, "IN");
 #ifndef SINGLE_THREAD
@@ -1273,7 +1624,7 @@ CAResult_t CAStopLE()
     return CA_STATUS_OK;
 }
 
-void CATerminateLE()
+static void CATerminateLE()
 {
     OIC_LOG(DEBUG, CALEADAPTER_TAG, "IN");
 
@@ -1302,7 +1653,7 @@ void CATerminateLE()
     OIC_LOG(DEBUG, CALEADAPTER_TAG, "OUT");
 }
 
-CAResult_t CAStartLEListeningServer()
+static CAResult_t CAStartLEListeningServer()
 {
     OIC_LOG(DEBUG, CALEADAPTER_TAG, "IN");
     CAResult_t result = CA_STATUS_OK;
@@ -1339,7 +1690,7 @@ CAResult_t CAStartLEListeningServer()
     return CA_STATUS_OK;
 }
 
-CAResult_t CAStartLEDiscoveryServer()
+static CAResult_t CAStartLEDiscoveryServer()
 {
     OIC_LOG(DEBUG, CALEADAPTER_TAG, "IN");
     CAResult_t result = CA_STATUS_OK;
@@ -1375,24 +1726,7 @@ CAResult_t CAStartLEDiscoveryServer()
     return CA_STATUS_OK;
 }
 
-CAResult_t CAStartLENotifyServer()
-{
-    OIC_LOG(DEBUG, CALEADAPTER_TAG, "IN");
-
-    OIC_LOG(DEBUG, CALEADAPTER_TAG, "OUT");
-    return CA_STATUS_OK;
-}
-
-uint32_t CASendLENotification(const CAEndpoint_t *endpoint, const void *data,
-                              uint32_t dataLen)
-{
-    OIC_LOG(DEBUG, CALEADAPTER_TAG, "IN");
-
-    OIC_LOG(DEBUG, CALEADAPTER_TAG, "OUT");
-    return 0;
-}
-
-CAResult_t CAReadLEData()
+static CAResult_t CAReadLEData()
 {
     OIC_LOG(DEBUG, CALEADAPTER_TAG, "IN");
 #ifdef SINGLE_THREAD
@@ -1402,7 +1736,9 @@ CAResult_t CAReadLEData()
     return CA_STATUS_OK;
 }
 
-int32_t CASendLEUnicastData(const CAEndpoint_t *endpoint, const void *data, uint32_t dataLen)
+static int32_t CASendLEUnicastData(const CAEndpoint_t *endpoint,
+                                   const void *data,
+                                   uint32_t dataLen)
 {
     OIC_LOG(DEBUG, CALEADAPTER_TAG, "IN");
 
@@ -1447,7 +1783,9 @@ int32_t CASendLEUnicastData(const CAEndpoint_t *endpoint, const void *data, uint
     return dataLen;
 }
 
-int32_t CASendLEMulticastData(const CAEndpoint_t *endpoint, const void *data, uint32_t dataLen)
+static int32_t CASendLEMulticastData(const CAEndpoint_t *endpoint,
+                                     const void *data,
+                                     uint32_t dataLen)
 {
     OIC_LOG(DEBUG, CALEADAPTER_TAG, "IN");
 
@@ -1498,7 +1836,7 @@ int32_t CASendLEMulticastData(const CAEndpoint_t *endpoint, const void *data, ui
     return dataLen;
 }
 
-CAResult_t CAGetLEInterfaceInformation(CAEndpoint_t **info, uint32_t *size)
+static CAResult_t CAGetLEInterfaceInformation(CAEndpoint_t **info, uint32_t *size)
 {
     OIC_LOG(DEBUG, CALEADAPTER_TAG, "IN");
 
@@ -1552,7 +1890,7 @@ CAResult_t CAGetLEInterfaceInformation(CAEndpoint_t **info, uint32_t *size)
     return CA_STATUS_OK;
 }
 
-CAResult_t CALERegisterNetworkNotifications(CANetworkChangeCallback netCallback)
+static CAResult_t CALERegisterNetworkNotifications(CANetworkChangeCallback netCallback)
 {
     OIC_LOG(DEBUG, CALEADAPTER_TAG, "IN");
 
@@ -1581,7 +1919,7 @@ CAResult_t CALERegisterNetworkNotifications(CANetworkChangeCallback netCallback)
     return res;
 }
 
-void CALEDeviceStateChangedCb( CAAdapterState_t adapter_state)
+static void CALEDeviceStateChangedCb( CAAdapterState_t adapter_state)
 {
     OIC_LOG(DEBUG, CALEADAPTER_TAG, "IN");
 
@@ -1620,9 +1958,9 @@ void CALEDeviceStateChangedCb( CAAdapterState_t adapter_state)
     OIC_LOG(DEBUG, CALEADAPTER_TAG, "OUT");
 }
 
-CAResult_t CALEAdapterClientSendData(const CAEndpoint_t *remoteEndpoint,
-                                     const void *data,
-                                     uint32_t dataLen)
+static CAResult_t CALEAdapterClientSendData(const CAEndpoint_t *remoteEndpoint,
+                                            const void *data,
+                                            uint32_t dataLen)
 {
     OIC_LOG(DEBUG, CALEADAPTER_TAG, "IN");
 
@@ -1655,10 +1993,9 @@ CAResult_t CALEAdapterClientSendData(const CAEndpoint_t *remoteEndpoint,
     return CA_STATUS_OK;
 }
 
-
-CAResult_t CALEAdapterServerSendData(const CAEndpoint_t *remoteEndpoint,
-                                     const void *data,
-                                     uint32_t dataLen)
+static CAResult_t CALEAdapterServerSendData(const CAEndpoint_t *remoteEndpoint,
+                                            const void *data,
+                                            uint32_t dataLen)
 {
     OIC_LOG(DEBUG, CALEADAPTER_TAG, "IN");
 
@@ -1743,14 +2080,14 @@ CAResult_t CALEAdapterServerSendData(const CAEndpoint_t *remoteEndpoint,
     return CA_STATUS_OK;
 }
 
-CAResult_t CALEAdapterServerReceivedData(const char *remoteAddress, const char *serviceUUID,
-                                         const void *data, uint32_t dataLength,
-                                         uint32_t *sentLength)
+static CAResult_t CALEAdapterServerReceivedData(const char *remoteAddress,
+                                                const void *data,
+                                                uint32_t dataLength,
+                                                uint32_t *sentLength)
 {
     OIC_LOG(DEBUG, CALEADAPTER_TAG, "IN");
 
     //Input validation
-    VERIFY_NON_NULL(serviceUUID, CALEADAPTER_TAG, "service UUID is null");
     VERIFY_NON_NULL(data, CALEADAPTER_TAG, "Data is null");
     VERIFY_NON_NULL(sentLength, CALEADAPTER_TAG, "Sent data length holder is null");
 
@@ -1787,7 +2124,7 @@ CAResult_t CALEAdapterServerReceivedData(const char *remoteAddress, const char *
     }
 
     CAFreeEndpoint(remoteEndpoint);
-    // Add message to send queue
+    // Add message to receiver queue
     CAQueueingThreadAddData(g_bleReceiverQueue, bleData, sizeof(CALEData_t));
 
     *sentLength = dataLength;
@@ -1796,14 +2133,14 @@ CAResult_t CALEAdapterServerReceivedData(const char *remoteAddress, const char *
     return CA_STATUS_OK;
 }
 
-CAResult_t CALEAdapterClientReceivedData(const char *remoteAddress, const char *serviceUUID,
-                                         const void *data, uint32_t dataLength,
-                                         uint32_t *sentLength)
+static CAResult_t CALEAdapterClientReceivedData(const char *remoteAddress,
+                                                const void *data,
+                                                uint32_t dataLength,
+                                                uint32_t *sentLength)
 {
     OIC_LOG(DEBUG, CALEADAPTER_TAG, "IN");
 
     //Input validation
-    VERIFY_NON_NULL(serviceUUID, CALEADAPTER_TAG, "service UUID is null");
     VERIFY_NON_NULL(data, CALEADAPTER_TAG, "Data is null");
     VERIFY_NON_NULL(sentLength, CALEADAPTER_TAG, "Sent data length holder is null");
 #ifndef SINGLE_THREAD
@@ -1832,7 +2169,7 @@ CAResult_t CALEAdapterClientReceivedData(const char *remoteAddress, const char *
     }
 
     CAFreeEndpoint(remoteEndpoint);
-    // Add message to send queue
+    // Add message to receiver queue
     CAQueueingThreadAddData(g_bleReceiverQueue, bleData, sizeof(CALEData_t));
 
     *sentLength = dataLength;
@@ -1841,18 +2178,18 @@ CAResult_t CALEAdapterClientReceivedData(const char *remoteAddress, const char *
     return CA_STATUS_OK;
 }
 
-void CASetLEAdapterThreadPoolHandle(ca_thread_pool_t handle)
+static void CASetLEAdapterThreadPoolHandle(ca_thread_pool_t handle)
 {
     OIC_LOG(DEBUG, CALEADAPTER_TAG, "IN");
 
-    ca_mutex_unlock(g_bleAdapterThreadPoolMutex);
+    ca_mutex_lock(g_bleAdapterThreadPoolMutex);
     g_bleAdapterThreadPool = handle;
     ca_mutex_unlock(g_bleAdapterThreadPoolMutex);
 
     OIC_LOG(DEBUG, CALEADAPTER_TAG, "OUT");
 }
 
-void CASetLEReqRespAdapterCallback(CANetworkPacketReceivedCallback callback)
+static void CASetLEReqRespAdapterCallback(CANetworkPacketReceivedCallback callback)
 {
     OIC_LOG(DEBUG, CALEADAPTER_TAG, "IN");
 
@@ -1865,14 +2202,18 @@ void CASetLEReqRespAdapterCallback(CANetworkPacketReceivedCallback callback)
     OIC_LOG(DEBUG, CALEADAPTER_TAG, "OUT");
 }
 
-void CALEErrorHandler(const char *remoteAddress, const void *data, uint32_t dataLen,
-                      CAResult_t result)
+static void CALEErrorHandler(const char *remoteAddress,
+                             const void *data,
+                             uint32_t dataLen,
+                             CAResult_t result)
 {
     OIC_LOG(DEBUG, CALEADAPTER_TAG, "CALEErrorHandler IN");
 
     VERIFY_NON_NULL_VOID(data, CALEADAPTER_TAG, "Data is null");
-    CAEndpoint_t *rep = CACreateEndpointObject(CA_DEFAULT_FLAGS, CA_ADAPTER_GATT_BTLE,
-                                               remoteAddress, 0);
+    CAEndpoint_t *rep = CACreateEndpointObject(CA_DEFAULT_FLAGS,
+                                               CA_ADAPTER_GATT_BTLE,
+                                               remoteAddress,
+                                               0);
     //if required, will be used to build remote end point
     g_errorHandler(rep, data, dataLen, result);
 
diff --git a/resource/csdk/connectivity/src/bt_le_adapter/linux/README b/resource/csdk/connectivity/src/bt_le_adapter/linux/README
new file mode 100644 (file)
index 0000000..0678fa2
--- /dev/null
@@ -0,0 +1,57 @@
+                 OIC GATT Transport Service for Linux
+                 ====================================
+
+This is an IoTivity BLE adapter implementation of the OIC GATT
+Transport specification for Linux.  It relies on the GATT and LE
+advertisement functionality found in BlueZ 5.31 or better.  As of
+BlueZ 5.31, the LE advertisement APIs are still considered
+experimental, meaning specific steps must be taken to enable them for
+that version of BlueZ, as described below.
+
+LE advertisement support requires Linux kernel 4.1 better.  If a LE
+peripheral won't be started, Linux kernel 3.19 is sufficient for LE
+central-only use cases.
+
+Enable LE Advertisement Support in BlueZ 5.31
+---------------------------------------------
+1. Backport the advertising patch that was created after BlueZ 5.31
+was released.  If you've cloned the BlueZ git repository this can be
+achieved by cherry picking the patch as follows:
+
+        git clone git://git.kernel.org/pub/scm/bluetooth/bluez.git
+        cd bluez
+        git checkout 5.31
+        git cherry-pick c73c1002331b2c0de0eaf555b5f1d05149f9a3b0
+
+Otherwise apply to BlueZ 5.31 the patch file found in the IoTivity
+`extlibs/bluez' directory:
+
+        0001-core-advertising-Fix-using-wrong-instance-id.patch
+
+2. Enable experimental APIs when building BlueZ 5.31, e.g.:
+
+        ./configure --enable-experimental ...
+
+3. Enable experimental APIs at run-time by starting bluetoothd with
+   the "--experimental" command line flag.  If you've installed BlueZ
+   on a platform with Systemd support, this can be done by appending
+   "--experimental" to the [Service] ExecStart option in the
+   bluetooth.service unit file (e.g.
+   /lib/systemd/system/bluetooth.service).  If you're going to build
+   and install BlueZ from source often, you may want to patch the
+   `bluetooth.service.in' in your bluez source directory instead so
+   that you won't have to modify the unit file after installation:
+
+diff --git a/src/bluetooth.service.in b/src/bluetooth.service.in
+index 35e9457..368df4c 100644
+--- a/src/bluetooth.service.in
++++ b/src/bluetooth.service.in
+@@ -5,7 +5,7 @@ Documentation=man:bluetoothd(8)
+ [Service]
+ Type=dbus
+ BusName=org.bluez
+-ExecStart=@libexecdir@/bluetoothd
++ExecStart=@libexecdir@/bluetoothd --experimental
+ NotifyAccess=main
+ #WatchdogSec=10
+ #Restart=on-failure
index 825d145..64f3a16 100644 (file)
@@ -1,9 +1,148 @@
+# ------------------------------------------------------------------------
+# Copyright 2015 Intel Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ------------------------------------------------------------------------
+
 ##########################################
 #       Build BLE adapter for Linux
 ##########################################
 
 Import('env')
 
-src_files = [ 'caleadapter.c']
+import os.path
+
+# Make sure the <bluetooth/bluetooth.h> and <bluetooth/hci.h> headers
+# necessary for use of the kernel Bluetooth management API are
+# available.  Only those headers are required.  There is no need to
+# build BlueZ in order to build IoTivity's BLE transport for Linux.
+env.SConscript('#extlibs/bluez/SConscript')
+
+# Top-level build (variant) directory.
+root_build_dir = env['BUILD_DIR']
+
+# Build (variant) directory corresponding to this source directory.
+this_build_dir = os.path.join(root_build_dir,
+                              os.path.dirname(File(SConscript).srcnode().path))
+
+# The Linux BLE adapter implementation uses GDBus to make D-Bus based
+# method calls to BlueZ.  Pull in the necessary dependencies.
+env.ParseConfig("pkg-config gio-unix-2.0 --cflags --libs")
+
+# Set up commands to generate GDBus code from the D-Bus introspection
+# XML.
+freedesktop_prefix = 'org.freedesktop.DBus.'
+bluez_prefix = 'org.bluez.'
+
+dbus_introspection_xml = {
+    'object_manager' : freedesktop_prefix,
+    'bluez'          : bluez_prefix,
+}
+
+# The source files to be compiled as part of the connectivity
+# abstraction library.
+glue_files = []
+
+for file, prefix in dbus_introspection_xml.items():
+    source_xml  = file + '.xml'
+    glue        = file + '-glue'
+    glue_source = glue + '.c'
+    glue_header = glue + '.h'
+    targets     = [ glue_source, glue_header ]
+
+    # Include the glue header in the list as well to make sure it is
+    # generated before other source files that depend on it are
+    # compiled.
+    glue_files += targets
+
+    # Generate GDBus skeletons in the variant (build) directory.
+    env.Command(targets,
+                source_xml,
+                'cd %s '
+                '&& gdbus-codegen --generate-c-code %s --interface-prefix %s %s '
+                '&& cd -'
+                % (this_build_dir,
+                   glue,
+                   prefix,
+                   os.path.join(env['SRC_DIR'], '$SOURCE')))
+
+    # Mark generated file for cleaning when running "scons -c".
+    #
+    # @todo Verify that the generated *-glue.[ch] files are removed on
+    #       running "scons -c" once that is working in the master
+    #       branch again.
+    for target in targets:
+        generated_target = os.path.join(this_build_dir, target)
+        env.Clean(target, generated_target)
+
+# The generated "glue" headers are found in the build directory
+# corresponding to this source directory.
+env.AppendUnique(CPPPATH = this_build_dir)
+
+# The Linux BLE transport exports its GATT and LE advertisement
+# related D-Bus interfaces to the D-Bus system bus so that they may be
+# accessed by BlueZ.  Set the bus names here, i.e. in one place, to
+# avoid potential mismatches, and generate the D-Bus policy
+# configuration file and related C preprocessor symbol definitions.
+service_name = '\"org.iotivity.gatt.service\"'
+
+dbus_policy_in = 'org.iotivity.gatt.service.conf.in'
+
+conf_dict = {}
+subst_env = env.Clone(tools = [ 'default', 'textfile' ],
+                      SUBST_DICT = conf_dict)
+
+conf_dict = { '@service_name@' : service_name }
+
+subst_env.Substfile(dbus_policy_in, SUBST_DICT = conf_dict)
+
+# The resulting D-Bus policy file should go in to the appropriate
+# D-Bus configuration directory, such as /etc/dbus-1/system.d/.
+
+dbus_policy    = os.path.splitext(dbus_policy_in)[0]  # Drop '.in' extension.
+generated_dbus_policy = os.path.join(this_build_dir, dbus_policy)
+env.Clean(dbus_policy, generated_dbus_policy)
+
+# Define the D-Bus bus name as a preprocessor symbol.  Note the
+# multiple quote levels to ensure that the double quotes surrounding
+# the string are included as part of the preprocess symbol.
+#
+# Also add a minimum required version of GLib 2.32, which is what the
+# older GNU/Linux distributions supported by IoTivity shipped with.
+env.AppendUnique(
+    CPPDEFINES = [
+        ('CA_DBUS_GATT_SERVICE_NAME', "'%s'" % service_name),
+        ('GLIB_VERSION_MIN_REQUIRED', 'GLIB_VERSION_2_32')
+    ])
+
+src_files = [ 'characteristic.c',
+              'descriptor.c',
+              'service.c',
+              'advertisement.c',
+              'utils.c',
+              'central.c',
+              'peripheral.c',
+              'client.c',
+              'server.c',
+              'recv.c',
+              'caleinterface.c'
+          ]
+src_files = glue_files + src_files
 
 Return('src_files')
+
+
+# Local Variables:
+# mode:python
+# indent-tabs-mode: nil
+# End:
diff --git a/resource/csdk/connectivity/src/bt_le_adapter/linux/advertisement.c b/resource/csdk/connectivity/src/bt_le_adapter/linux/advertisement.c
new file mode 100644 (file)
index 0000000..980d9de
--- /dev/null
@@ -0,0 +1,132 @@
+/* ****************************************************************
+ *
+ * Copyright 2015 Intel Corporation All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+#include "advertisement.h"
+#include "gatt_dbus.h"
+
+#include "cagattservice.h"
+#include "logger.h"
+
+#include <assert.h>
+
+
+// Logging tag.
+static char const TAG[] = "BLE_ADVERTISEMENT";
+
+bool CALEAdvertisementInitialize(CALEAdvertisement * a,
+                                 GDBusConnection * connection,
+                                 GList * managers)
+{
+    assert(a != NULL);
+    assert(connection != NULL);
+
+    /*
+      D-Bus object path for the LEAdvertisement1 object of the form
+      /org/iotivity/gatt/advertisement0.
+
+      The same object path is registered with all
+      org.bluez.LEAdvertisingManager1 objects since the advertisement
+      data is same for all Bluetooth hardware adapters.
+    */
+    static char const object_path[] =
+        CA_GATT_SERVICE_ROOT_PATH "/" CA_LE_ADVERTISEMENT_PATH;
+
+    assert(g_variant_is_object_path(object_path));
+
+    a->advertisement  = leadvertisement1_skeleton_new();
+
+    /*
+      Setting the BlueZ advertisement type to "peripheral" causes the
+      Bluetooth adapter to go into LE connectable and general
+      discoverable modes upon successful registration of the
+      advertisement with BlueZ.
+     */
+    leadvertisement1_set_type_(a->advertisement, "peripheral");
+
+    static char const * service_uuids[] = {
+        CA_GATT_SERVICE_UUID,  // Advertise OIC Transport Profile
+        NULL
+    };
+
+    leadvertisement1_set_service_uuids(a->advertisement, service_uuids);
+    leadvertisement1_set_manufacturer_data(a->advertisement, NULL);
+    leadvertisement1_set_solicit_uuids(a->advertisement, NULL);
+    leadvertisement1_set_service_data(a->advertisement, NULL);
+    leadvertisement1_set_include_tx_power(a->advertisement, FALSE);
+
+    a->managers = managers;
+
+    // Export the LEAdvertisement1 interface skeleton.
+    GError * error = NULL;
+    if (!g_dbus_interface_skeleton_export(
+            G_DBUS_INTERFACE_SKELETON(a->advertisement),
+            connection,
+            object_path,
+            &error))
+    {
+        OIC_LOG_V(ERROR,
+                  TAG,
+                  "Unable to export LE advertisement interface: %s\n",
+                  error->message);
+
+        return false;
+    }
+
+    return true;
+}
+
+void CALEAdvertisementDestroy(CALEAdvertisement * a)
+{
+    if (a->advertisement != NULL)
+    {
+        char const * const advertisement_path =
+            g_dbus_interface_skeleton_get_object_path(
+                G_DBUS_INTERFACE_SKELETON(
+                    a->advertisement));
+
+        if (advertisement_path != NULL)
+        {
+            for (GList * l = a->managers; l != NULL; l = l->next)
+            {
+                GDBusProxy * const manager = G_DBUS_PROXY(l->data);
+
+                GVariant * const parameters =
+                    g_variant_new("(o)", advertisement_path, NULL);
+
+                /*
+                  Unregister our LE advertisement from the BlueZ LE
+                  advertising manager.
+                */
+                g_dbus_proxy_call(
+                    manager,
+                    "UnregisterAdvertisement",
+                    parameters,
+                    G_DBUS_CALL_FLAGS_NONE,
+                    -1,    // timeout (default == -1),
+                    NULL,  // cancellable
+                    NULL,  // callback
+                    NULL);
+            }
+        }
+
+        g_clear_object(&a->advertisement);
+    }
+
+    g_list_free_full(a->managers, g_object_unref);
+    a->managers = NULL;
+}
diff --git a/resource/csdk/connectivity/src/bt_le_adapter/linux/advertisement.h b/resource/csdk/connectivity/src/bt_le_adapter/linux/advertisement.h
new file mode 100644 (file)
index 0000000..87af42c
--- /dev/null
@@ -0,0 +1,79 @@
+/* ****************************************************************
+ *
+ * Copyright 2015 Intel Corporation All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+#ifndef CA_BLE_LINUX_ADVERTISEMENT_H
+#define CA_BLE_LINUX_ADVERTISEMENT_H
+
+#include "bluez-glue.h"
+
+#include <stdbool.h>
+
+
+/**
+ * Information needed for registering an LE advertisement with BlueZ.
+ */
+typedef struct CALEAdvertisement
+{
+    /// OIC LE advertisement D-Bus interface skeleton object.
+    LEAdvertisement1 * advertisement;
+
+    /**
+     * Proxies to the BlueZ D-Bus objects that implement the
+     * "org.bluez.LEAdvertisingManager1" interface with which the @c
+     * advertisement is registered.
+     */
+    GList * managers;
+
+} CALEAdvertisement;
+
+/**
+ * Initialize LE advertisement fields.
+ *
+ * This function initializes the @c CALEAdvertisement object fields.
+ *
+ * @param[out] a          LE advertisement information to be
+ *                        initialized.
+ * @param[in]  connection D-Bus connection to the bus on which the
+ *                        advertisement will be exported.
+ * @param[in]  managers   List of @c org.bluez.LEAdvertisingManager1
+ *                        proxies.
+ *
+ * @return @c true on success, @c false otherwise.
+ *
+ * @note This function does not allocate the @a adv object itself.
+ *       The caller is responsible for allocating that memory.
+ */
+bool CALEAdvertisementInitialize(CALEAdvertisement * a,
+                                 GDBusConnection * connection,
+                                 GList * managers);
+
+/**
+ * Destroy LE advertisement fields.
+ *
+ * This function finalizes the @c CALEAdvertisement object fields.
+ *
+ * @param[in] adv LE advertisement information to be finalized.
+ *
+ * @note This function does not deallocate the @a adv object itself.
+ *       The caller is responsible for deallocating that memory.
+ */
+void CALEAdvertisementDestroy(CALEAdvertisement * adv);
+
+
+#endif  // CA_BLE_LINUX_ADVERTISEMENT_H
+
diff --git a/resource/csdk/connectivity/src/bt_le_adapter/linux/bluez.h b/resource/csdk/connectivity/src/bt_le_adapter/linux/bluez.h
new file mode 100644 (file)
index 0000000..c4b445c
--- /dev/null
@@ -0,0 +1,53 @@
+/******************************************************************
+ *
+ * Copyright 2015 Intel Corporation All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+#ifndef CA_BLE_LINUX_BLUEZ_H
+#define CA_BLE_LINUX_BLUEZ_H
+
+
+/// BlueZ D-Bus service name.
+#define BLUEZ_NAME "org.bluez"
+
+/// BlueZ D-Bus adapter interface name.
+static char const BLUEZ_ADAPTER_INTERFACE[] = BLUEZ_NAME ".Adapter1";
+
+/// BlueZ D-Bus device interface name.
+static char const BLUEZ_DEVICE_INTERFACE[] = BLUEZ_NAME ".Device1";
+
+/// BlueZ D-Bus LE advertising manager interface.
+static char const BLUEZ_ADVERTISING_MANAGER_INTERFACE[] =
+    BLUEZ_NAME ".LEAdvertisingManager1";
+
+/// BlueZ D-Bus GATT manager interface.
+static char const BLUEZ_GATT_MANAGER_INTERFACE[] =
+    BLUEZ_NAME ".GattManager1";
+
+/// BlueZ D-Bus adapter GATT service interface name.
+static char const BLUEZ_GATT_SERVICE_INTERFACE[] =
+    BLUEZ_NAME ".GattService1";
+
+/// BlueZ D-Bus adapter GATT characteristic interface name.
+static char const BLUEZ_GATT_CHARACTERISTIC_INTERFACE[] =
+    BLUEZ_NAME ".GattCharacteristic1";
+
+/// BlueZ D-Bus adapter GATT service interface name.
+static char const BLUEZ_GATT_DESCRIPTOR_INTERFACE[] =
+    BLUEZ_NAME ".GattDescriptor1";
+
+
+#endif  // CA_BLE_LINUX_BLUEZ_H
diff --git a/resource/csdk/connectivity/src/bt_le_adapter/linux/bluez.xml b/resource/csdk/connectivity/src/bt_le_adapter/linux/bluez.xml
new file mode 100644 (file)
index 0000000..356cd56
--- /dev/null
@@ -0,0 +1,170 @@
+<!--
+    Copyright 2015 Intel Corporation All Rights Reserved.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+    ******************************************************************
+
+    The introspection XML found in this file is used to generate GDBus
+    skeleton code that will be used by the IoTivity BlueZ-based GATT
+    Service (OIC Transport Profile) implementation.
+
+    See the GATT and LE Advertisement API documentation in the BlueZ
+    gatt-api.txt and advertisement-api.txt documents, respectively for
+    further details.
+-->
+
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
+"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<node name="/org/iotivity/gatt/service">
+
+  <!--
+      ***********************************************
+      BlueZ GATT Service interface introspection XML.
+      ***********************************************
+  -->
+  <interface name="org.bluez.GattService1">
+    <annotation name="org.freedesktop.DBus.Properties.PropertiesChanged" value="const"/>
+
+    <property name="UUID" type="s" access="read"/>
+    <property name="Primary" type="b" access="read"/>
+    <property name="Characteristics" type="ao" access="read"/>
+
+    <!--
+    ===========================================================
+    The "Device" property is only exposed on the client side by
+    BlueZ itself.  It isn't set by the IoTivity server side.
+    Don't bother generating skeleton code for it.
+    ===========================================================
+    <property name="Device" type="o" access="read">
+      <annotation name="org.freedesktop.DBus.Properties.PropertiesChanged" value="true"/>
+    </property>
+
+    ===========================================================
+    The "Includes" property is not supported as of BlueZ 5.30.
+    It also isn't used by the IoTivity server side
+    implementation.  Don't bother generating skeleton code for
+    it.
+    ===========================================================
+    <property name="Includes" type="ao" access="read"/>
+    -->
+
+  </interface>
+
+  <!--
+      ******************************************************
+      BlueZ GATT Characteristic interface introspection XML.
+      ******************************************************
+  -->
+  <interface name="org.bluez.GattCharacteristic1">
+    <!--
+    ============================================================
+    None of the OIC GATT characteristics support the "ReadValue"
+    method.  Don't bother generating skeleton code for it.
+    ============================================================
+    <method name="ReadValue">
+      <arg name="value" type="ay" direction="out"/>
+      <annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
+    </method>
+    -->
+
+    <method name="WriteValue">
+      <arg name="value" type="ay" direction="in">
+        <annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
+      </arg>
+    </method>
+
+    <method name="StartNotify"/>
+
+    <method name="StopNotify"/>
+
+    <annotation name="org.freedesktop.DBus.Properties.PropertiesChanged" value="const"/>
+
+    <property name="UUID" type="s" access="read"/>
+    <property name="Service" type="o" access="read"/>
+
+    <property name="Value" type="ay" access="read">
+      <annotation name="org.freedesktop.DBus.Properties.PropertiesChanged" value="true"/>
+      <annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
+    </property>
+
+    <property name="Notifying" type="b" access="read">
+      <annotation name="org.freedesktop.DBus.Properties.PropertiesChanged" value="true"/>
+    </property>
+    <property name="Flags" type="as" access="read"/>
+    <property name="Descriptors" type="ao" access="read"/>
+  </interface>
+
+  <!--
+      **************************************************
+      BlueZ GATT Descriptor interface introspection XML.
+      **************************************************
+  -->
+  <interface name="org.bluez.GattDescriptor1">
+    <method name="ReadValue">
+      <arg name="value" type="ay" direction="out">
+        <annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
+      </arg>
+    </method>
+
+    <!--
+    ============================================================
+    None of the OIC GATT descriptors directly supported by
+    IoTivity support the "WriteValue" method.  The OIC Client
+    Characteristic Configuration Descriptor supports writes, but
+    that descriptor is handled by BlueZ, not IoTivity, when the
+    "notify" property is set on a given GATT characteristic.
+    Don't bother generating skeleton code for it.
+    ============================================================
+
+    <method name="WriteValue">
+      <arg name="value" type="ay" direction="in">
+            <annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
+          </arg>
+    </method>
+    -->
+
+    <annotation name="org.freedesktop.DBus.Properties.PropertiesChanged" value="const"/>
+
+    <property name="UUID" type="s" access="read"/>
+    <property name="Characteristic" type="o" access="read"/>
+
+    <property name="Value" type="ay" access="read">
+      <annotation name="org.freedesktop.DBus.Properties.PropertiesChanged" value="true"/>
+      <annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
+    </property>
+
+    <property name="Flags" type="as" access="read"/>
+  </interface>
+
+  <!--
+      ***************************************************
+      BlueZ LE Advertisement interface introspection XML.
+      ***************************************************
+  -->
+  <interface name="org.bluez.LEAdvertisement1">
+    <method name="Release">
+      <annotation name="org.freedesktop.DBus.Method.NoReply" value="true"/>
+    </method>
+
+    <annotation name="org.freedesktop.DBus.Properties.PropertiesChanged" value="const"/>
+
+    <property name="Type" type="s" access="read"/>
+    <property name="ServiceUUIDs" type="as" access="read"/>
+    <property name="ManufacturerData" type="a{sv}" access="read"/>
+    <property name="SolicitUUIDs" type="as" access="read"/>
+    <property name="ServiceData" type="a{sv}" access="read"/>
+    <property name="IncludeTxPower" type="b" access="read"/>
+  </interface>
+
+</node>
diff --git a/resource/csdk/connectivity/src/bt_le_adapter/linux/caleadapter.c b/resource/csdk/connectivity/src/bt_le_adapter/linux/caleadapter.c
deleted file mode 100644 (file)
index 3e8d709..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-/******************************************************************
- *
- * Copyright 2014 Samsung Electronics All Rights Reserved.
- *
- *
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- ******************************************************************/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "caleadapter.h"
-#include "logger.h"
-
-#define TAG PCF("CA")
-
-static CANetworkPacketReceivedCallback g_leReceivedCallback = NULL;
-static ca_thread_pool_t g_threadPoolHandle = NULL;
-
-CAResult_t CAInitializeLE(CARegisterConnectivityCallback registerCallback,
-                          CANetworkPacketReceivedCallback reqRespCallback,
-                          CANetworkChangeCallback netCallback,
-                          CAErrorHandleCallback errorCallback, ca_thread_pool_t handle)
-{
-    OIC_LOG(DEBUG, TAG, "CAInitializeLE");
-
-    g_leReceivedCallback = reqRespCallback;
-    g_threadPoolHandle = handle;
-
-    // register handlers
-    CAConnectivityHandler_t handler = {};
-
-    handler.startAdapter = CAStartLE;
-    handler.startListenServer = CAStartLEListeningServer;
-    handler.startDiscoveryServer = CAStartLEDiscoveryServer;
-    handler.sendData = CASendLEUnicastData;
-    handler.sendDataToAll = CASendLEMulticastData;
-    handler.GetnetInfo = CAGetLEInterfaceInformation;
-    handler.readData = CAReadLEData;
-    handler.stopAdapter = CAStopLE;
-    handler.terminate = CATerminateLE;
-
-    registerCallback(handler, CA_ADAPTER_GATT_BTLE);
-
-    return CA_STATUS_OK;
-}
-
-CAResult_t CAStartLE()
-{
-    OIC_LOG(DEBUG, TAG, "CAStartLE");
-
-    return CA_STATUS_OK;
-}
-
-CAResult_t CAStartLEListeningServer()
-{
-    OIC_LOG(DEBUG, TAG, "CAStartLEListeningServer");
-
-    return CA_STATUS_OK;
-}
-
-CAResult_t CAStartLEDiscoveryServer()
-{
-    OIC_LOG(DEBUG, TAG, "CAStartLEDiscoveryServer");
-
-    return CA_STATUS_OK;
-}
-
-int32_t CASendLEUnicastData(const CAEndpoint_t *endpoint, const void *data, uint32_t dataLen)
-{
-    OIC_LOG(DEBUG, TAG, "CASendLEUnicastData");
-
-    return -1;
-}
-
-int32_t CASendLEMulticastData(const CAEndpoint_t *endpoint, const void *data, uint32_t dataLen)
-{
-    OIC_LOG(DEBUG, TAG, "CASendLEMulticastData");
-
-    return -1;
-}
-
-CAResult_t CAGetLEInterfaceInformation(CAEndpoint_t **info, uint32_t *size)
-{
-    OIC_LOG(DEBUG, TAG, "CAGetLEInterfaceInformation");
-
-    return CA_STATUS_OK;
-}
-
-CAResult_t CAReadLEData()
-{
-    OIC_LOG(DEBUG, TAG, "Read LE Data");
-
-    return CA_STATUS_OK;
-}
-
-CAResult_t CAStopLE()
-{
-    OIC_LOG(DEBUG, TAG, "CAStopLE");
-
-    return CA_STATUS_OK;
-}
-
-void CATerminateLE()
-{
-    OIC_LOG(DEBUG, TAG, "TerminatLE");
-}
-
diff --git a/resource/csdk/connectivity/src/bt_le_adapter/linux/caleinterface.c b/resource/csdk/connectivity/src/bt_le_adapter/linux/caleinterface.c
new file mode 100644 (file)
index 0000000..5c54171
--- /dev/null
@@ -0,0 +1,1330 @@
+/******************************************************************
+ *
+ * Copyright 2015 Intel Corporation All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+#include "caleinterface.h"
+#include "bluez.h"
+#include "central.h"
+#include "peripheral.h"
+#include "client.h"
+#include "server.h"
+#include "utils.h"
+
+#include "cagattservice.h"
+#include "oic_malloc.h"
+#include "oic_string.h"
+#include "logger.h"
+
+#include <string.h>
+#include <strings.h>  // For strcasecmp().
+#include <assert.h>
+
+
+#define MICROSECS_PER_SEC 1000000
+
+// Logging tag.
+static char const TAG[] = "BLE_INTERFACE";
+
+/*
+    The IoTivity adapter interface currently doesn't provide a means to
+    pass context down to the transport layer so rely on a file scope
+    context instead.
+*/
+static CALEContext g_context = {
+    .lock = NULL
+};
+
+// -----------------------------------------------------------------------
+// Functions internal to this BLE adapter implementation.
+// -----------------------------------------------------------------------
+static bool CALESetUpBlueZObjects(CALEContext * context);
+
+static bool CALECheckStarted()
+{
+    ca_mutex_lock(g_context.lock);
+
+    bool const started = (g_context.event_loop != NULL);
+
+    ca_mutex_unlock(g_context.lock);
+
+    /**
+     * @todo Fix potential TOCTOU race condition.  A LE transport
+     *       adapter could have been started or stopped between the
+     *       mutex unlock and boolean check.
+     */
+    return started;
+}
+
+static void CALEDumpDBusSignalParameters(char const * sender_name,
+                                         char const * object_path,
+                                         char const * interface_name,
+                                         char const * signal_name,
+                                         GVariant   * parameters)
+{
+#ifdef TB_LOG
+    gchar * const param_dump =
+        g_variant_print(parameters, TRUE);
+
+    OIC_LOG_V(DEBUG,
+              TAG,
+              "%s()\n"
+              "\tsender_name: %s\n"
+              "\tobject_path: %s\n"
+              "\tinterface_name: %s\n"
+              "\tsignal_name: %s\n"
+              "\tparameters: %s\n",
+              __func__,
+              sender_name,
+              object_path,
+              interface_name,
+              signal_name,
+              param_dump);
+
+    g_free(param_dump);
+#endif  // TB_LOG
+}
+
+static void CALEOnInterfaceProxyPropertiesChanged(
+    GDBusObjectManagerClient * manager,
+    GDBusObjectProxy         * object_proxy,
+    GDBusProxy               * interface_proxy,
+    GVariant                 * changed_properties,
+    gchar const * const      * invalidated_properties,
+    gpointer                   user_data)
+{
+    OIC_LOG_V(DEBUG,
+              TAG,
+              "Properties Changed on %s:\n",
+              g_dbus_object_get_object_path(
+                  G_DBUS_OBJECT(object_proxy)));
+
+    char const * const interface_name =
+        g_dbus_proxy_get_interface_name(interface_proxy);
+
+    bool const is_adapter_interface =
+        (strcmp(BLUEZ_ADAPTER_INTERFACE, interface_name) == 0);
+
+    if (!is_adapter_interface)
+    {
+        /*
+          Only specific org.bluez.Adapter1 property changes are
+          currently supported.
+        */
+        return;
+    }
+
+    CALEContext * const context = user_data;
+
+    GVariantIter iter;
+    gchar const * key   = NULL;
+    GVariant    * value = NULL;
+
+    g_variant_iter_init(&iter, changed_properties);
+    while (g_variant_iter_next(&iter, "{&sv}", &key, &value))
+    {
+        if (strcmp(key, "Powered") == 0)
+        {
+            /*
+              Report a change in the availability of the bluetooth
+              adapter.
+            */
+
+            gboolean const powered = g_variant_get_boolean(value);
+            CAAdapterState_t const status =
+                (powered ? CA_ADAPTER_ENABLED : CA_ADAPTER_DISABLED);
+
+            CAEndpoint_t info =
+                {
+                    .adapter = CA_ADAPTER_GATT_BTLE,
+                };
+
+            GVariant * const prop =
+                g_dbus_proxy_get_cached_property(interface_proxy,
+                                                 "Address");
+
+            gchar const * const address = g_variant_get_string(prop, NULL);
+
+            OICStrcpy(info.addr, sizeof(info.addr), address);
+
+            g_variant_unref(prop);
+
+            /**
+             * @todo Should we acquire the context lock here to
+             *       prevent the @c CALEDeviceStateChangedCallback
+             *       from being potentially yanked out from under us
+             *       if the CA adapters are stopped/terminated as
+             *       we're about to invoke this callback?
+             *
+             * @todo Unfortunately the CA LE interface defined in
+             *       caleinterface.h assumes that only one BLE adapter
+             *       will exist on a given host.  However, this
+             *       implementation can handle multiple BLE adapters.
+             *       The CA LE interface should be updated so that it
+             *       can handle multiple BLE adapters.
+             */
+            context->on_device_state_changed(status);
+        }
+
+#ifdef TB_LOG
+        gchar * const s = g_variant_print(value, TRUE);
+        OIC_LOG_V(DEBUG, TAG, "  %s -> %s", key, s);
+        g_free(s);
+#endif  // TB_LOG
+
+        g_variant_unref(value);
+    }
+}
+
+static void CALEHandleInterfaceAdded(GList ** proxy_list,
+                                     char const * interface,
+                                     GVariant * parameters)
+{
+    /**
+     * @note The @a parameters are of the form "(oa{sv})".
+     */
+    GDBusProxy * const proxy =
+        CAGetBlueZInterfaceProxy(parameters,
+                                 interface,
+                                 g_context.object_manager);
+
+    if (proxy == NULL)
+    {
+        return;
+    }
+
+    ca_mutex_lock(g_context.lock);
+
+    /*
+      Add the object information to the list.
+
+      Note that we prepend instead of append in this case since it
+      is more efficient to do so for linked lists like the one used
+      here.
+    */
+    *proxy_list = g_list_prepend(*proxy_list, proxy);
+
+    ca_mutex_unlock(g_context.lock);
+
+    /**
+     * Let the thread that may be blocked waiting for Devices to be
+     * discovered know that at least one was found.
+     *
+     * @todo It doesn't feel good putting this @c org.bluez.Device1
+     *       specific code here since this function is meant to be
+     *       BlueZ interface neutral.  Look into ways of moving this
+     *       out of here.
+     */
+    if (strcmp(interface, BLUEZ_DEVICE_INTERFACE) == 0)
+    {
+        ca_cond_signal(g_context.condition);
+    }
+}
+
+static void CALEOnInterfacesAdded(GDBusConnection * connection,
+                                  char const * sender_name,
+                                  char const * object_path,
+                                  char const * interface_name,
+                                  char const * signal_name,
+                                  GVariant   * parameters,
+                                  gpointer     user_data)
+{
+    CALEDumpDBusSignalParameters(sender_name,
+                                 object_path,
+                                 interface_name,
+                                 signal_name,
+                                 parameters);
+
+    // The signal should always be InterfacesAdded.
+    assert(strcmp(signal_name, "InterfacesAdded") == 0);
+
+    // Handle addition of a new org.bluez.Adapter1 interface.
+    CALEHandleInterfaceAdded(&g_context.adapters,
+                             BLUEZ_ADAPTER_INTERFACE,
+                             parameters);
+
+    // Handle addition of a new org.bluez.Device1 interface.
+    CALEHandleInterfaceAdded(&g_context.devices,
+                             BLUEZ_DEVICE_INTERFACE,
+                             parameters);
+}
+
+static void CALEOnInterfacesRemoved(GDBusConnection * connection,
+                                    char const * sender_name,
+                                    char const * object_path,
+                                    char const * interface_name,
+                                    char const * signal_name,
+                                    GVariant   * parameters,
+                                    gpointer     user_data)
+{
+    CALEDumpDBusSignalParameters(sender_name,
+                                 object_path,
+                                 interface_name,
+                                 signal_name,
+                                 parameters);
+
+    // The signal should always be InterfacesRemoved.
+    assert(strcmp(signal_name, "InterfacesRemoved") == 0);
+
+    /*
+      The object path is first tuple element, and the interface names
+      the second.  Check if "org.bluez.Adapter1" exists in the
+      interface array.  If it does, remove the corresponding
+      information from the adapter_infos list.
+    */
+    GVariant * const interfaces =
+        g_variant_get_child_value(parameters, 1);
+
+    GVariantIter * iter = NULL;
+    g_variant_get(interfaces, "as", &iter);
+
+    /**
+     * Iterate over the array and remove all BlueZ interface proxies
+     * with a matching D-Bus object path from the corresponding list.
+     *
+     * @todo Determine whether we should optimize this nested loop.
+     *       It may not be worthwhile to do so since the lists being
+     *       iterated over should be very short.
+     */
+    for (GVariant * child = g_variant_iter_next_value(iter);
+         child != NULL;
+         child = g_variant_iter_next_value(iter))
+    {
+        char const * interface = NULL;
+        g_variant_get(child, "&s", &interface);
+
+        GList ** list = NULL;
+
+        if (strcmp(interface, BLUEZ_ADAPTER_INTERFACE) == 0)
+        {
+            list = &g_context.adapters;
+        }
+        else if (strcmp(interface, BLUEZ_DEVICE_INTERFACE) == 0)
+        {
+            list = &g_context.devices;
+        }
+        else
+        {
+            continue;
+        }
+
+        // The object path is the first tuple element.
+        gchar const * path = NULL;
+        g_variant_get_child(parameters, 0, "&o", &path);
+
+        ca_mutex_lock(g_context.lock);
+
+        for (GList * l = *list; l != NULL; l = g_list_next(l))
+        {
+            GDBusProxy * const proxy = G_DBUS_PROXY(l->data);
+
+            if (strcmp(path,
+                       g_dbus_proxy_get_object_path(proxy)) == 0)
+            {
+                // Found a match!
+                g_object_unref(proxy);
+
+                *list = g_list_delete_link(*list, l);
+
+                break;
+            }
+        }
+
+        ca_mutex_unlock(g_context.lock);
+
+        g_variant_unref(child);
+    }
+
+    if (iter != NULL)
+        g_variant_iter_free(iter);
+}
+
+static void CALEOnPropertiesChanged(GDBusConnection * connection,
+                                    char const * sender_name,
+                                    char const * object_path,
+                                    char const * interface_name,
+                                    char const * signal_name,
+                                    GVariant   * parameters,
+                                    gpointer     user_data)
+{
+    CALEDumpDBusSignalParameters(sender_name,
+                                 object_path,
+                                 interface_name,
+                                 signal_name,
+                                 parameters);
+}
+
+static void CALEOnPropertyChanged(GDBusConnection * connection,
+                                  char const * sender_name,
+                                  char const * object_path,
+                                  char const * interface_name,
+                                  char const * signal_name,
+                                  GVariant   * parameters,
+                                  gpointer     user_data)
+{
+    CALEDumpDBusSignalParameters(sender_name,
+                                 object_path,
+                                 interface_name,
+                                 signal_name,
+                                 parameters);
+}
+
+static void CALESubscribeToSignals(CALEContext * context,
+                                   GDBusConnection * connection,
+                                   GDBusObjectManager * object_manager)
+{
+    static char const om_interface[] =
+        "org.freedesktop.DBus.ObjectManager";
+
+    /*
+      Subscribe to D-Bus signals that will allow us to detect changes
+      in BlueZ adapter and device properties.
+     */
+    guint const interfaces_added_sub_id =
+        g_dbus_connection_signal_subscribe(
+            connection,
+            NULL,  // sender
+            om_interface,
+            "InterfacesAdded",
+            NULL,  // object path
+            NULL,  // arg0
+            G_DBUS_SIGNAL_FLAGS_NONE,
+            CALEOnInterfacesAdded,
+            NULL,  // user_data
+            NULL);
+
+    guint const interfaces_removed_sub_id =
+        g_dbus_connection_signal_subscribe(
+            connection,
+            NULL,  // sender
+            om_interface,
+            "InterfacesRemoved",
+            NULL,  // object path
+            NULL,  // arg0
+            G_DBUS_SIGNAL_FLAGS_NONE,
+            CALEOnInterfacesRemoved,
+            NULL,  // user_data
+            NULL);
+
+#if GLIB_CHECK_VERSION(2,38,0)
+    /*
+      The G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH flag was introduced in
+      GLib 2.38.
+    */
+    static GDBusSignalFlags const device_signal_flags =
+        G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH;
+#else
+    static GDBusSignalFlags const device_signal_flags =
+        G_DBUS_SIGNAL_FLAGS_NONE;
+#endif
+
+    /**
+     * @todo Verify that this signal subscription is needed.
+     *
+     * @bug The arg0 argument below should be a D-Bus object path, not
+     *      interface name.
+     */
+    guint const properties_changed_sub_id =
+        g_dbus_connection_signal_subscribe(
+            connection,
+            NULL,  // sender
+            "org.freedesktop.DBus.Properties",
+            "PropertiesChanged",
+            NULL,  // object path
+            "org.bluez.Device1",  // arg0
+            device_signal_flags,
+            CALEOnPropertiesChanged,
+            NULL,  // user_data
+            NULL);
+
+    /**
+     * @todo Verify that this signal subscription is needed.
+     */
+    guint const property_changed_sub_id =
+        g_dbus_connection_signal_subscribe(connection,
+                                           NULL,  // sender
+                                           BLUEZ_ADAPTER_INTERFACE,
+                                           "PropertyChanged",
+                                           NULL,  // object path
+                                           NULL,  // arg0
+                                           G_DBUS_SIGNAL_FLAGS_NONE,
+                                           CALEOnPropertyChanged,
+                                           NULL,  // user_data
+                                           NULL);
+
+    g_signal_connect(object_manager,
+                     "interface-proxy-properties-changed",
+                     G_CALLBACK(CALEOnInterfaceProxyPropertiesChanged),
+                     context);
+
+    ca_mutex_lock(context->lock);
+
+    context->interfaces_added_sub_id   = interfaces_added_sub_id;
+    context->interfaces_removed_sub_id = interfaces_removed_sub_id;
+    context->properties_changed_sub_id = properties_changed_sub_id;
+    context->property_changed_sub_id   = property_changed_sub_id;
+
+    ca_mutex_unlock(context->lock);
+}
+
+static bool CALESetUpDBus(CALEContext * context)
+{
+    assert(context != NULL);
+
+    bool success = false;
+
+    GError * error = NULL;
+
+    /*
+      Set up connection to the D-Bus system bus, where the BlueZ
+      daemon is found.
+    */
+    GDBusConnection * const connection =
+        g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
+
+    if (connection == NULL)
+    {
+        OIC_LOG_V(ERROR,
+                  TAG,
+                  "Connection to D-Bus system bus failed: %s.",
+                  error->message);
+
+        g_error_free(error);
+
+        return success;
+    }
+
+    // Create a proxy to the BlueZ D-Bus ObjectManager.
+    static char const object_manager_path[] = "/";
+
+    GDBusObjectManager * const object_manager =
+        g_dbus_object_manager_client_new_sync(
+            connection,
+            G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
+            BLUEZ_NAME,
+            object_manager_path,
+            NULL,   // get_proxy_type_func
+            NULL,   // get_proxy_type_user_data
+            NULL,   // get_proxy_type_destroy_notify
+            NULL,   // cancellable
+            &error);
+
+    if (object_manager == NULL)
+    {
+        OIC_LOG_V(ERROR,
+                  TAG,
+                  "Unable to create D-Bus ObjectManager client: %s",
+                  error->message);
+
+        g_error_free(error);
+
+        g_object_unref(connection);
+
+        return success;
+    }
+
+    CALESubscribeToSignals(context, connection, object_manager);
+
+    ca_mutex_lock(context->lock);
+    context->connection     = connection;
+    context->object_manager = object_manager;
+    ca_mutex_unlock(context->lock);
+
+    success = CALESetUpBlueZObjects(context);
+
+    return success;
+}
+
+static void CALETearDownDBus(CALEContext * context)
+{
+    assert(context != NULL);
+
+    /*
+      Minimize the time we hold the global lock by only clearing the
+      global state, and pushing resource finalization outside the global
+      lock.
+    */
+    ca_mutex_lock(context->lock);
+
+    GDBusConnection * const connection = context->connection;
+    context->connection = NULL;
+
+    GDBusObjectManager * const object_manager = context->object_manager;
+    context->object_manager = NULL;
+
+    GList * const objects = context->objects;
+    context->objects = NULL;
+
+    GList * const adapters = context->adapters;
+    context->adapters = NULL;
+
+    GList * const devices = context->devices;
+    context->devices = NULL;
+
+    guint const interfaces_added   = context->interfaces_added_sub_id;
+    guint const interfaces_removed = context->interfaces_removed_sub_id;
+    guint const properties_changed = context->properties_changed_sub_id;
+    guint const property_changed   = context->property_changed_sub_id;
+
+    context->interfaces_added_sub_id   = 0;
+    context->interfaces_removed_sub_id = 0;
+    context->properties_changed_sub_id = 0;
+    context->property_changed_sub_id   = 0;
+
+    ca_mutex_unlock(context->lock);
+
+    // Destroy the device proxies list.
+    g_list_free_full(devices, g_object_unref);
+
+    // Destroy the adapter proxies list.
+    g_list_free_full(adapters, g_object_unref);
+
+    // Destroy the list of objects obtained from the ObjectManager.
+    g_list_free_full(objects, g_object_unref);
+
+    // Destroy the ObjectManager proxy.
+    if (object_manager != NULL)
+    {
+        g_object_unref(object_manager);
+    }
+
+    // Tear down the D-Bus connection to the system bus.
+    if (connection != NULL)
+    {
+        g_dbus_connection_signal_unsubscribe(connection,
+                                             interfaces_added);
+        g_dbus_connection_signal_unsubscribe(connection,
+                                             interfaces_removed);
+        g_dbus_connection_signal_unsubscribe(connection,
+                                             properties_changed);
+        g_dbus_connection_signal_unsubscribe(connection,
+                                             property_changed);
+        g_object_unref(connection);
+    }
+}
+
+static bool CALEDeviceFilter(GDBusProxy * device)
+{
+    bool accepted = false;
+
+    /*
+      Filter out any devices that don't support the OIC Transport
+      Profile service.
+    */
+    GVariant * const prop =
+        g_dbus_proxy_get_cached_property(device, "UUIDs");
+
+    if (prop == NULL)
+    {
+        // No remote services available on the device.
+        return accepted;
+    }
+
+    char const ** const UUIDs = g_variant_get_strv(prop, NULL);
+
+    /**
+     * @note It would have been nice to use @c g_strv_contains() here,
+     *       but we would need to run it twice: once for the uppercase
+     *       form of the UUID and once for for the lowercase form.
+     *       Just run the loop manually, and use @c strcasecmp()
+     *       instead.
+     */
+    for (char const * const * u = UUIDs; u != NULL; ++u)
+    {
+        if (strcasecmp(*u, CA_GATT_SERVICE_UUID) == 0)
+        {
+            accepted = true;
+            break;
+        }
+    }
+
+    g_free(UUIDs);
+    g_variant_unref(prop);
+
+    return accepted;
+}
+
+
+static bool CALESetUpBlueZObjects(CALEContext * context)
+{
+    bool success = false;
+
+    // Get the list of BlueZ D-Bus objects.
+    GList * const objects =
+        g_dbus_object_manager_get_objects(context->object_manager);
+
+    if (objects == NULL) {
+        OIC_LOG(ERROR,
+                TAG,
+                "Unable to get objects from ObjectManager.");
+
+        return success;
+    }
+
+    ca_mutex_lock(context->lock);
+    context->objects = objects;
+    ca_mutex_unlock(context->lock);
+
+    /*
+      Create a proxies to the org.bluez.Adapter1 D-Bus objects that
+      will later be used to obtain local bluetooth adapter properties,
+      as well as by the BLE central code to discover peripherals.
+    */
+    GList * adapters = NULL;
+    success = CAGetBlueZManagedObjectProxies(&adapters,
+                                             BLUEZ_ADAPTER_INTERFACE,
+                                             context,
+                                             NULL);
+
+    // An empty adapters list is NULL.
+    if (success && adapters != NULL)
+    {
+        ca_mutex_lock(context->lock);
+        context->adapters = adapters;
+        ca_mutex_unlock(context->lock);
+    }
+
+    /*
+      Create a proxies to the org.bluez.Device1 D-Bus objects that
+      will later be used to establish connections.
+    */
+    GList * devices = NULL;
+    success = CAGetBlueZManagedObjectProxies(&devices,
+                                             BLUEZ_DEVICE_INTERFACE,
+                                             context,
+                                             CALEDeviceFilter);
+
+    // An empty device list is NULL.
+    if (success && devices != NULL)
+    {
+        ca_mutex_lock(context->lock);
+        context->devices = devices;
+        ca_mutex_unlock(context->lock);
+    }
+
+    /* success = CAGattClientInitialize(context); */
+
+    return success;
+}
+
+static void CALEStartEventLoop(void * data)
+{
+    CALEContext * const context = data;
+
+    assert(context != NULL);
+
+    // Create the event loop.
+    GMainContext * const loop_context = g_main_context_new();
+    GMainLoop * const event_loop = g_main_loop_new(loop_context, FALSE);
+
+    ca_mutex_lock(context->lock);
+
+    assert(context->event_loop == NULL);
+    context->event_loop = event_loop;
+
+    ca_mutex_unlock(context->lock);
+
+    g_main_context_push_thread_default(loop_context);
+
+    /*
+      We have to do the BlueZ object manager client initialization and
+      signal subscription here so that the corresponding asynchronous
+      signal handling occurs in the same thread as the one running the
+      GLib event loop.
+    */
+    if (!CALESetUpDBus(&g_context))
+        return;
+
+    ca_cond_signal(g_context.condition);
+
+    g_main_loop_run(event_loop);
+}
+
+static void CALEStopEventLoop(CALEContext * context)
+{
+    ca_mutex_lock(context->lock);
+
+    GMainLoop * const event_loop = context->event_loop;
+    context->event_loop = NULL;
+
+    ca_mutex_unlock(context->lock);
+
+    if (event_loop != NULL)
+    {
+        g_main_loop_quit(event_loop);
+
+        GMainContext * const loop_context =
+            g_main_loop_get_context(event_loop);
+
+        if (loop_context != NULL)
+        {
+            g_main_context_wakeup(loop_context);
+            g_main_context_unref(loop_context);
+        }
+
+        g_main_loop_unref(event_loop);
+    }
+}
+
+/**
+ * Wait for @a list to be non-empty.
+ *
+ * @param[in] list    List that should not be empty.
+ * @param[in] retries Number of times to retry if the @a timeout is
+ *                    reached.
+ * @param[in] timeout Timeout in microseconds to wait between retries.
+ */
+static bool CALEWaitForNonEmptyList(GList * const * list,
+                                    int retries,
+                                    uint64_t timeout)
+{
+    bool success = false;
+
+    ca_mutex_lock(g_context.lock);
+
+    for (int i = 0; *list == NULL && i < retries; ++i)
+    {
+        if (ca_cond_wait_for(g_context.condition,
+                             g_context.lock,
+                             timeout) == 0)
+        {
+            /*
+              Condition variable was signaled before the timeout was
+              reached.
+            */
+            success = true;
+        }
+    }
+
+    ca_mutex_unlock(g_context.lock);
+
+    return success;
+}
+
+static CAResult_t CALEStop()
+{
+    CAResult_t result = CA_STATUS_FAILED;
+
+    OIC_LOG(DEBUG, TAG, "Stop Linux BLE adapter.");
+
+    // Only stop if we were previously started.
+    if (!CALECheckStarted())
+        return result;
+
+    // Stop the event loop thread regardless of previous errors.
+    CALEStopEventLoop(&g_context);
+
+    CALETearDownDBus(&g_context);
+
+    return result;
+}
+
+static void CALETerminate()
+{
+    OIC_LOG(DEBUG, TAG, "Terminate BLE adapter.");
+
+    CAPeripheralFinalize();
+
+    ca_mutex_lock(g_context.lock);
+
+    g_context.on_device_state_changed = NULL;
+    g_context.on_server_received_data = NULL;
+    g_context.on_client_received_data = NULL;
+    g_context.client_thread_pool      = NULL;
+    g_context.server_thread_pool      = NULL;
+    g_context.on_client_error         = NULL;
+    g_context.on_server_error         = NULL;
+
+    ca_mutex_unlock(g_context.lock);
+
+    ca_cond_free(g_context.condition);
+    ca_mutex_free(g_context.lock);
+}
+
+// -----------------------------------------------------------------------
+
+CAResult_t CAInitializeLEAdapter()
+{
+#if !GLIB_CHECK_VERSION(2,36,0)
+    /*
+      Initialize the GLib type system.
+
+      As of GLib 2.36, it is no longer necessary to explicitly call
+      g_type_init().
+    */
+    g_type_init();
+#endif
+
+    g_context.lock      = ca_mutex_new();
+    g_context.condition = ca_cond_new();
+
+    CAPeripheralInitialize();
+
+    return CA_STATUS_OK;
+}
+
+CAResult_t CAStartLEAdapter()
+{
+    /*
+      This function is called by the connectivity abstraction when
+      CASelectNetwork(CA_ADAPTER_GATT_BTLE) is called by the user.
+    */
+
+    OIC_LOG(DEBUG, TAG, __func__);
+
+    CAResult_t result = CA_STATUS_FAILED;
+
+    // Only start if we were previously stopped.
+    if (CALECheckStarted())
+      return result;
+
+    /**
+     * Spawn a thread to run the GLib event loop that will drive D-Bus
+     * signal handling.
+     *
+     * @note Ideally this should be done in the @c CAInitializeLE()
+     *       function so that we can detect local bluetooth adapter
+     *       changes right away, without having to first start this LE
+     *       adapter/transport via @cCASelectNetwork().  However, a
+     *       limitation in the CA termination code that destroys the
+     *       thread pool before the transport adapters prevents us
+     *       from doing that without potentially triggering a
+     *       @c pthread_join() call that blocks indefinitely due to
+     *       this event loop not be stopped.  See the comments in the
+     *       @c CAGetLEInterfaceInformation() function below for
+     *       further details.
+     */
+    result = ca_thread_pool_add_task(g_context.client_thread_pool,
+                                     CALEStartEventLoop,
+                                     &g_context);
+
+    if (result != CA_STATUS_OK)
+        return result;
+
+    /*
+      Wait until initialization completes before continuing, basically
+      until some Bluetooth adapters were found.
+    */
+
+    // Number of times to wait for initialization to complete.
+    static int const retries = 2;
+
+    static uint64_t const timeout =
+        2 * MICROSECS_PER_SEC;  // Microseconds
+
+    if (CALEWaitForNonEmptyList(&g_context.adapters, retries, timeout))
+    {
+        result = CA_STATUS_OK;
+    }
+
+    return result;
+}
+
+CAResult_t CAGetLEAdapterState()
+{
+    /**
+     * @todo To be implemented shortly as part of the effort to
+     *       address a critical code review that stated this BLE
+     *       transport should implement the interface defined in
+     *       caleinterface.h.
+     */
+    return CA_NOT_SUPPORTED;
+}
+
+CAResult_t CAInitializeLENetworkMonitor()
+{
+    /**
+     * @todo To be implemented shortly as part of the effort to
+     *       address a critical code review that stated this BLE
+     *       transport should implement the interface defined in
+     *       caleinterface.h.
+     */
+    return CA_STATUS_OK;
+}
+
+void CATerminateLENetworkMonitor()
+{
+    /**
+     * @todo To be implemented shortly as part of the effort to
+     *       address a critical code review that stated this BLE
+     *       transport should implement the interface defined in
+     *       caleinterface.h.
+     */
+}
+
+CAResult_t CASetLEAdapterStateChangedCb(CALEDeviceStateChangedCallback callback)
+{
+    ca_mutex_lock(g_context.lock);
+    g_context.on_device_state_changed = callback;
+    ca_mutex_unlock(g_context.lock);
+
+    return CA_STATUS_OK;
+}
+
+CAResult_t CAInitLENetworkMonitorMutexVariables()
+{
+    /*
+      This CA LE interface implementation doesn't use a network
+      monitor as the other platform implementationd do.
+    */
+    return CA_STATUS_OK;
+}
+
+void CATerminateLENetworkMonitorMutexVariables()
+{
+    /*
+      This CA LE interface implementation doesn't use a network
+      monitor as the other platform implementationd do.
+    */
+}
+
+CAResult_t CAGetLEAddress(char **local_address)
+{
+    OIC_LOG(DEBUG, TAG, "Get Linux BLE local device information.");
+
+    if (local_address == NULL)
+    {
+        return CA_STATUS_INVALID_PARAM;
+    }
+
+    /**
+     * @bug Attempting to get LE interface information before this
+     *      connectivity abstraction adapter has started (e.g. via
+     *      @c CASelectNetwork()) could result in an inaccurate list
+     *      of LE interfaces.  For example, detection of hot-plugged
+     *      bluetooth adapters will only work after the LE IoTivity
+     *      network has been selected.  If the LE IoTivity network
+     *      hasn't been selected, the hot-plugged bluetooth adapter
+     *      will not be reflected in the @c CALocalConnectivity_t list
+     *      returned by this function.
+     *      @par
+     *      This issue caused by the fact that the event loop that
+     *      handles such events can only be run after this LE
+     *      adapter/transport is started.  The event loop cannot be
+     *      started earlier, e.g. during @c CAInitialize(), due to a
+     *      limitation in the CA transport termination code that
+     *      requires thread pools to be destroyed before transport
+     *      termination.  If the event loop was added as a task to the
+     *      thread pool during @c CAInitialize(), it's possible that
+     *      the thread running that event loop could be blocked
+     *      waiting for events during a later call to
+     *      @c CATerminate() if @c CASelectNetwork() was not called
+     *      beforehand.  The thread pool destruction that occurs
+     *      during @c CATerminate() waits for threads in the pool to
+     *      exit.  However, in this case the event loop thread is
+     *      still blocked waiting for events since it may not have
+     *      been stopped since the transport itself was not stopped,
+     *      meaning termination will also be blocked.
+     *      @par
+     *      Other than refactoring to the termination code to allow
+     *      thread pools to be started during @c CAInitialize(), the
+     *      only other choice we have to prevent the hang at
+     *      termination is to move the event loop creation and
+     *      termination to the @c CAAdapterStart() and
+     *      @c CAAdapterStop() implementations, respectively, which is
+     *      why we have this bug.
+     */
+    if (!CALECheckStarted())
+      return CA_ADAPTER_NOT_ENABLED;
+
+    *local_address = NULL;
+
+    ca_mutex_lock(g_context.lock);
+
+    for (GList * l = g_context.adapters; l != NULL; l = l->next)
+    {
+        GDBusProxy * const adapter = G_DBUS_PROXY(l->data);
+
+        /*
+          The local bluetooth adapter MAC address is stored in the
+          org.bluez.Adapter1.Address property.
+        */
+        GVariant * const prop =
+            g_dbus_proxy_get_cached_property(adapter, "Address");
+
+        /*
+          Unless the org.bluez.Adapter1.Address property no longer
+          exists, prop should not be NULL!  We have bigger problems if
+          this assert() is ever tripped since that would mean the
+          org.bluez.Adapter1 D-Bus interface changed.
+        */
+        assert(prop != NULL);
+
+        gchar const * const address = g_variant_get_string(prop, NULL);
+
+        *local_address = OICStrdup(address);
+
+        /*
+          No longer need the property variant.  The address has been
+          copied.
+        */
+        g_variant_unref(prop);
+
+        /**
+         * @todo Unfortunately the CA LE interface defined in
+         *       caleinterface.h assumes that only one BLE adapter
+         *       will exist on a given host.  However, this
+         *       implementation can handle multiple BLE adapters.  The
+         *       CA LE interface should be updated so that it can
+         *       handle multiple BLE adapters.  For now we'll just
+         *       return the address for the first BLE adapter in the
+         *       list.
+         */
+        break;
+    }
+
+    ca_mutex_unlock(g_context.lock);
+
+    return *local_address != NULL ? CA_STATUS_OK : CA_STATUS_FAILED;
+}
+
+CAResult_t CAStartLEGattServer()
+{
+    return CAPeripheralStart(&g_context);
+}
+
+CAResult_t CAStopLEGattServer()
+{
+    CAResult_t result    = CAPeripheralStop();
+    CAResult_t const tmp = CALEStop();
+
+    if (result == CA_STATUS_OK && tmp != CA_STATUS_OK)
+    {
+        result = tmp;
+    }
+
+    return result;
+}
+
+void CATerminateLEGattServer()
+{
+    CALETerminate();
+}
+
+void CASetLEReqRespServerCallback(CABLEDataReceivedCallback callback)
+{
+    ca_mutex_lock(g_context.lock);
+    g_context.on_server_received_data = callback;
+    ca_mutex_unlock(g_context.lock);
+}
+
+CAResult_t CAUpdateCharacteristicsToGattClient(char const * address,
+                                               char const * charValue,
+                                               uint32_t charValueLen)
+{
+    /**
+     * @todo To be implemented shortly as part of the effort to
+     *       address a critical code review that stated this BLE
+     *       transport should implement the interface defined in
+     *       caleinterface.h.
+     */
+    return CA_NOT_SUPPORTED;
+}
+
+CAResult_t CAUpdateCharacteristicsToAllGattClients(char const * charValue,
+                                                   uint32_t charValueLen)
+{
+    /**
+     * @todo To be implemented shortly as part of the effort to
+     *       address a critical code review that stated this BLE
+     *       transport should implement the interface defined in
+     *       caleinterface.h.
+     */
+    return CA_NOT_SUPPORTED;
+}
+
+CAResult_t CAStartLEGattClient()
+{
+    return CACentralStart(&g_context);
+}
+
+void CAStopLEGattClient()
+{
+    (void) CACentralStop(&g_context);
+    (void) CALEStop();
+}
+
+void CATerminateLEGattClient()
+{
+    CALETerminate();
+}
+
+void CACheckLEData()
+{
+    /*
+      This function is only used in single-threaded builds, but this
+      CA LE adapter implementation is multi-threaded.  Consequently,
+      this function is a no-op.
+     */
+}
+
+CAResult_t CAUpdateCharacteristicsToGattServer(
+    char const * remoteAddress,
+    char const * data,
+    uint32_t dataLen,
+    CALETransferType_t type,
+    int32_t position)
+{
+    /**
+     * @todo To be implemented shortly as part of the effort to
+     *       address a critical code review that stated this BLE
+     *       transport should implement the interface defined in
+     *       caleinterface.h.
+     */
+    return CA_NOT_SUPPORTED;
+}
+
+CAResult_t CAUpdateCharacteristicsToAllGattServers(char const * data,
+                                                   uint32_t length)
+{
+    OIC_LOG(DEBUG, TAG, "Send data to all");
+
+    /*
+      Multicast data is only sent when a request is sent from a client
+      across all endpoints.  We need not worry about sending a
+      response from a server here.
+    */
+
+    CAResult_t result = CA_STATUS_FAILED;
+
+    ca_mutex_lock(g_context.lock);
+    bool found_peripherals = (g_context.devices != NULL);
+    ca_mutex_unlock(g_context.lock);
+
+    if (!found_peripherals)
+    {
+        /*
+          Start discovery of LE peripherals that advertise the OIC
+          Transport Profile.
+        */
+        result = CACentralStartDiscovery(&g_context);
+
+        if (result != CA_STATUS_OK)
+        {
+            return -1;
+        }
+
+        // Wait for LE peripherals to be discovered.
+
+        // Number of times to wait for discovery to complete.
+        static int const retries = 5;
+
+        static uint64_t const timeout =
+            2 * MICROSECS_PER_SEC;  // Microseconds
+
+        if (!CALEWaitForNonEmptyList(&g_context.devices,
+                                     retries,
+                                     timeout))
+        {
+            return -1;
+        }
+
+        ca_mutex_lock(g_context.lock);
+        found_peripherals = (g_context.devices == NULL);
+        ca_mutex_unlock(g_context.lock);
+
+        if (!found_peripherals)
+        {
+            // No peripherals discovered!
+            return -1;
+        }
+    }
+
+    /*
+      Stop discovery so that we can connect to LE peripherals.
+      Otherwise, the bluetooth subsystem will claim the adapter is
+      busy.
+    */
+
+    result = CACentralStopDiscovery(&g_context);
+
+    if (result != CA_STATUS_OK)
+    {
+        return -1;
+    }
+
+    bool const connected = CACentralConnectToAll(&g_context);
+
+    if (!connected)
+    {
+        return -1;
+    }
+
+    /**
+     * @todo Start notifications on all response characteristics.
+     */
+
+    /*
+      Now send the request through all BLE connections through the
+      corresponding OIC GATT request characterstics.
+    */
+
+    CAGattRequestInfo const info =
+        {
+            .characteristic_info = NULL,  // g_context.characteristics
+            .context = &g_context
+        };
+
+    return CAGattClientSendDataToAll(&info, data, length);
+
+    /**
+     * @todo Should we restart discovery after the send?
+     */
+}
+
+void CASetLEReqRespClientCallback(CABLEDataReceivedCallback callback)
+{
+    ca_mutex_lock(g_context.lock);
+    g_context.on_client_received_data = callback;
+    ca_mutex_unlock(g_context.lock);
+}
+
+void CASetLEServerThreadPoolHandle(ca_thread_pool_t handle)
+{
+    ca_mutex_lock(g_context.lock);
+    g_context.server_thread_pool = handle;
+    ca_mutex_unlock(g_context.lock);
+}
+
+void CASetLEClientThreadPoolHandle(ca_thread_pool_t handle)
+{
+    ca_mutex_lock(g_context.lock);
+    g_context.client_thread_pool = handle;
+    ca_mutex_unlock(g_context.lock);
+}
+
+CAResult_t CAUnSetLEAdapterStateChangedCb()
+{
+    ca_mutex_lock(g_context.lock);
+    g_context.on_device_state_changed = NULL;
+    ca_mutex_unlock(g_context.lock);
+
+    return CA_STATUS_OK;
+}
+
+void CASetBLEClientErrorHandleCallback(CABLEErrorHandleCallback callback)
+{
+    ca_mutex_lock(g_context.lock);
+    g_context.on_client_error = callback;
+    ca_mutex_unlock(g_context.lock);
+}
+
+void CASetBLEServerErrorHandleCallback(CABLEErrorHandleCallback callback)
+{
+    ca_mutex_lock(g_context.lock);
+    g_context.on_server_error = callback;
+    ca_mutex_unlock(g_context.lock);
+}
diff --git a/resource/csdk/connectivity/src/bt_le_adapter/linux/central.c b/resource/csdk/connectivity/src/bt_le_adapter/linux/central.c
new file mode 100644 (file)
index 0000000..874e3a2
--- /dev/null
@@ -0,0 +1,444 @@
+/******************************************************************
+ *
+ * Copyright 2015 Intel Corporation All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+#include "central.h"
+#include "utils.h"
+#include "bluez.h"
+
+#include "cagattservice.h"  // For CA_GATT_SERVICE_UUID.
+#include "logger.h"
+
+#include <stdbool.h>
+#include <assert.h>
+
+
+// Logging tag.
+static char const TAG[] = "BLE_CENTRAL";
+
+static bool CACentralGetBooleanProperty(GDBusProxy * device,
+                                        char const * property)
+{
+    GVariant * const cached_property =
+        g_dbus_proxy_get_cached_property(device, property);
+
+    if (cached_property == NULL)
+    {
+        return false;
+    }
+
+    bool const value = g_variant_get_boolean(cached_property);
+
+    g_variant_unref(cached_property);
+
+    return value;
+}
+
+static void CACentralStartDiscoveryImpl(gpointer proxy, gpointer user_data)
+{
+    assert(proxy != NULL);
+    assert(user_data != NULL);
+
+    GDBusProxy * const adapter = G_DBUS_PROXY(proxy);
+    CAResult_t * const result  = user_data;
+
+    *result = CA_STATUS_FAILED;
+
+    bool const is_discovering =
+        CACentralGetBooleanProperty(adapter, "Discovering");
+
+    if (is_discovering)
+    {
+        // Nothing to do.  Avoid invoking a method over D-Bus.
+        *result = CA_STATUS_OK;
+        return;
+    }
+
+
+    // Make sure the adapter is powered on before starting discovery.
+    if (!CASetBlueZObjectProperty(adapter,
+                                  BLUEZ_ADAPTER_INTERFACE,
+                                  "Powered",
+                                  g_variant_new_boolean(TRUE)))
+    {
+        OIC_LOG(ERROR,
+                TAG,
+                "Unable to power on LE central adapter.");
+
+        return;
+    }
+
+    /*
+      Only scan for LE peripherals that advertise the OIC Transport
+      Profile GATT service UUID by setting a discovery filter on the BlueZ
+      org.bluez.Adapter1 object with two parameters:
+
+          (1) "UUIDs": set to an array containing that OIC Transport
+                       Profile GATT service UUID
+          (2) "Transport": set to "le"
+
+      See the documentation for the SetDiscoveryFilter() method in the
+      BlueZ `adapter-api.txt' document for more details.
+    */
+    GVariantBuilder builder;
+    g_variant_builder_init(&builder, G_VARIANT_TYPE("a{sv}"));
+
+    static char const * const UUIDs[] =
+        {
+            CA_GATT_SERVICE_UUID
+        };
+
+    g_variant_builder_add(&builder,
+                          "{sv}",
+                          "UUIDs",
+                          g_variant_new_strv(
+                              UUIDs,
+                              sizeof(UUIDs) / sizeof(UUIDs[0])));
+
+    g_variant_builder_add(&builder,
+                          "{sv}",
+                          "Transport",
+                          g_variant_new_string("le"));
+
+    GVariant * const filter = g_variant_builder_end(&builder);
+
+    /*
+      SetDiscoveryFilter() expects a dictionary but it must be packed
+      into a tuple for the actual call through the proxy.
+    */
+    GVariant * const filter_parameters =
+        g_variant_new("(@a{sv})", filter);
+
+    GError * error = NULL;
+
+    /*
+      This is a synchronous call, but the actually discovery is
+      performed asynchronously.  org.bluez.Device1 objects will
+      reported through the
+      org.freedesktop.DBus.ObjectManager.InterfacesAdded signal as
+      peripherals that match our discovery filter criteria are found.
+     */
+    GVariant * ret =
+        g_dbus_proxy_call_sync(adapter,
+                               "SetDiscoveryFilter",
+                               filter_parameters,
+                               G_DBUS_CALL_FLAGS_NONE,
+                               -1,    // timeout (default == -1),
+                               NULL,  // cancellable
+                               &error);
+
+    if (ret == NULL)
+    {
+        OIC_LOG_V(ERROR,
+                  TAG,
+                  "SetDiscoveryFilter() call failed: %s",
+                  error->message);
+
+        g_error_free(error);
+
+        return;
+    }
+
+    g_variant_unref(ret);
+
+    // Start device discovery.
+    ret = g_dbus_proxy_call_sync(adapter,
+                                 "StartDiscovery",
+                                 NULL,  // parameters
+                                 G_DBUS_CALL_FLAGS_NONE,
+                                 -1,    // timeout (default == -1),
+                                 NULL,  // cancellable
+                                 &error);
+
+    if (ret == NULL)
+    {
+        OIC_LOG_V(ERROR,
+                  TAG,
+                  "StartDiscovery() call failed: %s",
+                  error->message);
+
+        g_error_free(error);
+
+        return;
+    }
+
+    g_variant_unref(ret);
+
+    *result = CA_STATUS_OK;
+}
+
+static void CACentralStopDiscoveryImpl(gpointer proxy, gpointer user_data)
+{
+    assert(proxy != NULL);
+    assert(user_data != NULL);
+
+    GDBusProxy * const adapter = G_DBUS_PROXY(proxy);
+    CAResult_t * const result  = user_data;
+
+    bool const is_discovering =
+        CACentralGetBooleanProperty(adapter, "Discovering");
+
+    if (!is_discovering)
+    {
+        // Nothing to do.  Avoid invoking a method over D-Bus.
+        *result = CA_STATUS_OK;
+        return;
+    }
+
+    *result = CA_STATUS_FAILED;
+
+
+    GError * error = NULL;
+
+    // Stop discovery sessions.
+    GVariant * const ret =
+        g_dbus_proxy_call_sync(adapter,
+                               "StopDiscovery",
+                               NULL,  // parameters
+                               G_DBUS_CALL_FLAGS_NONE,
+                               -1,    // timeout (default == -1)
+                               NULL,  // cancellable
+                               &error);
+
+    if (ret == NULL)
+    {
+        OIC_LOG_V(ERROR,
+                  TAG,
+                  "StopDiscovery() call failed: %s",
+                  error->message);
+
+        g_error_free(error);
+
+        return;
+    }
+
+    g_variant_unref(ret);
+
+    *result = CA_STATUS_OK;
+}
+
+static void CACentralConnectToDevice(gpointer data, gpointer user_data)
+{
+    assert(data != NULL);
+    assert(user_data != NULL);
+
+    GDBusProxy * const device = G_DBUS_PROXY(data);
+    bool * const connected = user_data;
+
+    if (!CACentralConnect(device))
+    {
+        *connected = false;
+    }
+}
+
+/**
+ * Disconnect from all LE peripherals.
+ *
+ * @param[in] context Context containing BlueZ device information.
+ */
+static void CACentralDisconnect(CALEContext * context)
+{
+    assert(context != NULL);
+
+    ca_mutex_lock(context->lock);
+
+    for (GList * l = context->devices; l != NULL; l = l->next)
+    {
+        GDBusProxy * const device = G_DBUS_PROXY(l->data);
+
+        bool const is_connected =
+            CACentralGetBooleanProperty(device, "Connected");
+
+        if (is_connected)
+        {
+            /*
+              Asynchronously disconnect.  We don't care about the
+              result so don't bother passing in a callback.
+            */
+            g_dbus_proxy_call(device,
+                              "Disconnect",
+                              NULL,  // parameters
+                              G_DBUS_CALL_FLAGS_NONE,
+                              -1,    // timeout (default == -1),
+                              NULL,  // cancellable
+                              NULL,  // callback
+                              NULL); // user data
+        }
+    }
+
+    ca_mutex_unlock(context->lock);
+}
+
+// -----------------------------------------------------------------------
+
+CAResult_t CACentralStart(CALEContext * context)
+{
+    assert(context != NULL);
+
+    CAResult_t result = CA_STATUS_FAILED;
+
+    /*
+      Synchronize access to the adapter information using the base
+      context lock since we don't own the adapters.
+     */
+    ca_mutex_lock(context->lock);
+
+    /**
+     * Start discovery on all detected adapters.
+     *
+     * @todo The current start start_discovery() implementation makes
+     *       two synchronous D-Bus calls to each BlueZ @c Adapter1
+     *       object in the @a adapters list.  We may want to make them
+     *       asynchronous to minimize blocking.
+     */
+    g_list_foreach(context->adapters,
+                   CACentralStartDiscoveryImpl,
+                   &result);
+
+    ca_mutex_unlock(context->lock);
+
+    return result;
+}
+
+CAResult_t CACentralStop(CALEContext * context)
+{
+    assert(context != NULL);
+
+    CAResult_t result = CA_STATUS_FAILED;
+
+    // Stop discovery on all detected adapters.
+    result = CACentralStopDiscovery(context);
+
+    // Disconnect from all adapters.
+    CACentralDisconnect(context);
+
+    /**
+     * @todo Stop notifications on all response characteristics.
+     */
+
+    return result;
+}
+
+CAResult_t CACentralStartDiscovery(CALEContext * context)
+{
+    assert(context != NULL);
+
+    CAResult_t result = CA_STATUS_FAILED;
+
+    /*
+      Synchronize access to the adapter information using the base
+      context lock since we don't own the adapters.
+     */
+    ca_mutex_lock(context->lock);
+
+    // Start discovery on all detected adapters.
+    g_list_foreach(context->adapters,
+                   CACentralStartDiscoveryImpl,
+                   &result);
+
+    ca_mutex_unlock(context->lock);
+
+    return result;
+}
+
+CAResult_t CACentralStopDiscovery(CALEContext * context)
+{
+    assert(context != NULL);
+
+    CAResult_t result = CA_STATUS_FAILED;
+
+    /*
+      Synchronize access to the adapter information using the base
+      context lock since we don't own the adapters.
+     */
+    ca_mutex_lock(context->lock);
+
+    // Stop discovery on all detected adapters.
+    g_list_foreach(context->adapters,
+                   CACentralStopDiscoveryImpl,
+                   &result);
+
+    /**
+     * @todo Stop notifications on all response characteristics.
+     */
+
+    ca_mutex_unlock(context->lock);
+
+    return result;
+}
+
+bool CACentralConnect(GDBusProxy * device)
+{
+    assert(device != NULL);
+
+    /*
+      Check if a connection to the LE peripheral was already
+      established.  If not, establish a connection.
+     */
+    bool const is_connected =
+        CACentralGetBooleanProperty(device, "Connected");
+
+    if (is_connected)
+    {
+        return true;
+    }
+
+    GError * error = NULL;
+
+    // Connect to the discovered LE peripheral asynchronously.
+    GVariant * const ret =
+        g_dbus_proxy_call_sync(device,
+                               "Connect",
+                               NULL,  // parameters
+                               G_DBUS_CALL_FLAGS_NONE,
+                               -1,    // timeout (default == -1),
+                               NULL,  // cancellable
+                               &error);
+
+    if (ret == NULL)
+    {
+        OIC_LOG_V(ERROR,
+                  TAG,
+                  "%s.Connect() call failed: %s",
+                  BLUEZ_DEVICE_INTERFACE,
+                  error->message);
+
+        g_error_free(error);
+
+        return false;
+    }
+
+    g_variant_unref(ret);
+
+    return true;
+}
+
+bool CACentralConnectToAll(CALEContext * context)
+{
+    bool connected = true;
+
+    ca_mutex_lock(context->lock);
+
+    // Connect to the LE peripherals, if we're not already connected.
+    g_list_foreach(context->devices,
+                   CACentralConnectToDevice,
+                   &connected);
+
+    ca_mutex_unlock(context->lock);
+
+    return connected;
+}
diff --git a/resource/csdk/connectivity/src/bt_le_adapter/linux/central.h b/resource/csdk/connectivity/src/bt_le_adapter/linux/central.h
new file mode 100644 (file)
index 0000000..72a8db6
--- /dev/null
@@ -0,0 +1,88 @@
+/******************************************************************
+ *
+ * Copyright 2015 Intel Corporation All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+#ifndef CA_BLE_LINUX_CENTRAL_H
+#define CA_BLE_LINUX_CENTRAL_H
+
+#include "context.h"
+
+#include "cacommon.h"
+
+
+/**
+ * Initialize and start a Linux BLE "central".
+ *
+ * Initialize all Linux BLE "central" state (i.e. a global
+ * @c CACentralContext instance), as well as start
+ * discovery of OIC GATT transport service capable peripherals.
+ *
+ * @param[in] context Context containing BlueZ adapter information.
+ *
+ * @return @c CA_STATUS_OK on success.
+ */
+CAResult_t CACentralStart(CALEContext * context);
+
+/**
+ * Stop the Linux BLE "central".
+ *
+ * @param[in] context Context containing BlueZ adapter information.
+ *
+ * @return @c CA_STATUS_OK on success.
+ */
+CAResult_t CACentralStop(CALEContext * context);
+
+/**
+ * Start discovery of OIC Transport Profile capable LE peripherals.
+ *
+ * @param[in] context Context containing BlueZ adapter information.
+ *
+ * @return @c CA_STATUS_OK on success.
+ */
+CAResult_t CACentralStartDiscovery(CALEContext * context);
+
+/**
+ * Stop discovery of OIC Transport Profile capable LE peripherals.
+ *
+ * @param[in] context Context containing BlueZ adapter information.
+ *
+ * @return @c CA_STATUS_OK on success.
+ */
+CAResult_t CACentralStopDiscovery(CALEContext * context);
+
+/**
+ * Connect to the LE peripheral pointed by @a device.
+ *
+ * @param[in] device Proxy to the BlueZ @c org.bluez.Device1 object
+ *                   through which the connection to the LE peripheral
+ *                   will be established.
+ *
+ * @return @c true on success, @c false otherwise.
+ */
+bool CACentralConnect(GDBusProxy * device);
+
+/**
+ * Connect to all discovered LE peripherals.
+ *
+ * @param[in] context Context containing BlueZ adapter information.
+ *
+ * @return @c true on success, @c false otherwise.
+ */
+bool CACentralConnectToAll(CALEContext * context);
+
+
+#endif  /* CA_BLE_LINUX_CENTRAL_H */
diff --git a/resource/csdk/connectivity/src/bt_le_adapter/linux/characteristic.c b/resource/csdk/connectivity/src/bt_le_adapter/linux/characteristic.c
new file mode 100644 (file)
index 0000000..1b05ed9
--- /dev/null
@@ -0,0 +1,622 @@
+/*****************************************************************
+ *
+ * Copyright 2015 Intel Corporation All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+#include "characteristic.h"
+#include "service.h"
+#include "gatt_dbus.h"
+#include "utils.h"
+#include "bluez.h"
+#include "server.h"
+
+#include "oic_malloc.h"
+#include "oic_string.h"
+#include "logger.h"
+#include "cagattservice.h"
+#include "caremotehandler.h"
+
+#include <inttypes.h>
+#include <string.h>
+#include <assert.h>
+
+
+// Logging tag.
+static char const TAG[] = "BLE_CHARACTERISTIC";
+
+// ---------------------------------------------------------------------
+//                      GATT Request Handling
+// ---------------------------------------------------------------------
+/**
+ * Handle @c org.bluez.GattCharacterstic1.WriteValue() method call.
+ *
+ * This handler is triggered when the
+ * @c org.bluez.GattCharacterstic1.WriteValue() method is called by a
+ * client on the BlueZ-based OIC GATT request characteristic.  In
+ * particular, IoTivity request data is sent by the GATT client to the
+ * GATT server through this call.  The server will retrieve the data
+ * that was sent from the @a value argument.  Reassembly of any
+ * request data fragments will begin here.
+ *
+ * @param[in] object     @c org.bluez.GattCharacteristic1 skeleton
+ *                       object associated with this method call.
+ * @param[in] invocation D-Bus method invocation related object used
+ *                       when sending results/errors asynchronously.
+ * @param[in] value      The @c GVariant containing the byte array
+ *                       (ay) with th request data inside.
+ * @param[in] user_data  Pointer to request
+ *                       @c CAGattCharacteristic object.
+ *
+ * @return @c TRUE to indicate that
+ *         @c org.bluez.Characteristic.WriteValue() method is
+ *         implemented.
+ */
+static gboolean CAGattCharacteristicHandleWriteValue(
+    GattCharacteristic1 * object,
+    GDBusMethodInvocation * invocation,
+    GVariant * value,
+    gpointer user_data)
+{
+    /*
+      This method is only trigged in a GATT server when receiving
+      data sent by a GATT client, i.e. the client wrote a value to
+      the server, and the server is handling that write request.
+    */
+
+    gsize len = 0;
+    gconstpointer const data =
+        g_variant_get_fixed_array(value,
+                                  &len,
+                                  1);  // sizeof(guchar) == 1
+
+    CAGattCharacteristic * const c = user_data;
+
+    if (CAGattRecv(&c->recv_info, data, (uint32_t) len))
+    {
+        gatt_characteristic1_complete_write_value(object, invocation);
+    }
+    else
+    {
+        g_dbus_method_invocation_return_dbus_error(
+            invocation,
+            "org.bluez.Error.Failed",
+            "Error when handling GATT request data fragment");
+    }
+
+    return TRUE;
+}
+
+// ---------------------------------------------------------------------
+//                      GATT Response Handling
+// ---------------------------------------------------------------------
+/**
+ * Make the peer address corresponding to the given GATT
+ * characteristic.
+ *
+ * @param[in] c Information about GATT characteristic for which the
+ *              peer (client) @c CAEndpoint_t object is being
+ *              created.
+ *
+ * @return @c String containing an encoded address associated with the
+ *         peer connected to the peripheral on which the characteristic
+ *         implementation resides, or @c NULL on error.
+ */
+static char * CAGattCharacteristicMakePeerAddress(
+    CAGattCharacteristic * c)
+{
+    assert(c != NULL);
+
+    /*
+      Length of stringified pointer in hexadecimal format, plus one
+      for null terminator.
+    */
+    static size_t const PSEUDO_ADDR_LEN = sizeof(intptr_t) / 4 + 1;
+
+    assert(MAX_ADDR_STR_SIZE_CA > PSEUDO_ADDR_LEN);
+
+    /*
+      Since there is no direct way to obtain the client endpoint
+      associated with the GATT characterstics on the server side,
+      embed a stringified pointer to the response charactertistic of
+      the form "&ABCDEF01" is the CAEndpoint_t instead.  This works
+      since:
+          1) only one LE central is ever connected to an LE peripheral
+          2) the CA layer doesn't directly interpret the address
+     */
+    char * const addr = OICMalloc(PSEUDO_ADDR_LEN);
+    int const count = snprintf(addr,
+                               PSEUDO_ADDR_LEN,
+                               "&%" PRIxPTR,
+                               (uintptr_t) c);
+
+    if (count >= (int) PSEUDO_ADDR_LEN)
+    {
+        OIC_LOG(ERROR,
+                TAG,
+                "Error creating peer address on server side.");
+
+        return NULL;
+    }
+
+    return addr;
+}
+
+/**
+ * Handle @c org.bluez.GattCharacterstic1.StartNotify() method call.
+ *
+ * This handler is triggered when the
+ * @c org.bluez.GattCharacterstic1.StartNotify() method is called by a
+ * client on the BlueZ-based OIC GATT response characteristic.  It
+ * sets the @c org.bluez.GattCharacterstic1.Notifying property to
+ * @c TRUE, and enables responses from the server.
+ *
+ * @note This handler is not available in the OIC GATT request
+ *       characteristic implementation.
+ *
+ * @param[in] object     @c org.bluez.GattCharacteristic1 skeleton
+ *                       object associated with this method call.
+ * @param[in] invocation D-Bus method invocation related object used
+ *                       when sending results/errors asynchronously.
+ * @param[in] user_data  Pointer to the response
+ *                       @c CAGattCharacteristic object.
+ *
+ * @return @c TRUE to indicate that
+ *         @c org.bluez.Characteristic.StartNotify() method is
+ *         implemented.
+ */
+static gboolean CAGattCharacteristicHandleStartNotify(
+    GattCharacteristic1 * object,
+    GDBusMethodInvocation * invocation,
+    gpointer user_data)
+{
+    /**
+     * Only allow the client to start notifications once.
+     *
+     * @todo Does BlueZ already prevent redundant calls to
+     *       @c org.bluez.GattCharacteristic1.StartNotify()?
+     */
+    if (gatt_characteristic1_get_notifying(object))
+    {
+        g_dbus_method_invocation_return_dbus_error(
+            invocation,
+            "org.bluez.Error.Failed",
+            "Notifications are already enabled.");
+
+        return TRUE;
+    }
+
+    // Retrieve the response characteristic information.
+    CAGattCharacteristic * const characteristic = user_data;
+
+    char * const peer =
+        CAGattCharacteristicMakePeerAddress(characteristic);
+
+    if (peer == NULL)
+    {
+        g_dbus_method_invocation_return_dbus_error(
+            invocation,
+            "org.bluez.Error.Failed",
+            "Error creating peer endpoint information");
+
+        return TRUE;
+    }
+
+    /*
+      Create an entry in the endpoint-to-characteristic map so that
+      responses may be sent to the GATT client through the OIC GATT
+      response characteristic through this BLE adapter's
+      CAAdapterSendUnicastData() implementation.
+     */
+    CALEContext * const context = characteristic->context;
+
+    ca_mutex_lock(context->lock);
+
+#if GLIB_CHECK_VERSION(2,40,0)
+    /*
+      GLib hash table functions started returning a boolean result in
+       version 2.40.x.
+    */
+    bool const inserted =
+#endif
+        g_hash_table_insert(context->characteristic_map,
+                            peer,
+                            characteristic);
+
+    ca_mutex_unlock(context->lock);
+
+#if GLIB_CHECK_VERSION(2,40,0)
+    if (!inserted)
+    {
+        g_dbus_method_invocation_return_dbus_error(
+            invocation,
+            "org.bluez.Error.Failed",
+            "Unable to set response endpoint.");
+
+        OICFree(peer);
+
+        return TRUE;
+    }
+#endif
+
+    /**
+     * @todo Do we need to explicitly emit the @c GObject @c notify or
+     *       @c org.freedesktop.Dbus.Properties.PropertiesChanged
+     *       signal here?
+     */
+    gatt_characteristic1_set_notifying(object, TRUE);
+
+    /*
+      Set the client endpoint field in the request characteristic so
+      that it may pass the appropriate endpoint object up the stack
+      through the CA request/response callback once a request has been
+      completely received and reassembled.
+    */
+    CAGattRecvInfo * const recv_info =
+        &characteristic->service->request_characteristic.recv_info;
+
+    recv_info->peer = peer;
+
+    ca_mutex_lock(context->lock);
+    recv_info->on_packet_received = context->on_server_received_data;
+    recv_info->context            = context;
+    ca_mutex_unlock(context->lock);
+
+    gatt_characteristic1_complete_start_notify(object, invocation);
+
+    return TRUE;
+}
+
+/**
+ * Handle @c org.bluez.GattCharacterstic1.StopNotify() method call.
+ *
+ * This handler is triggered when the
+ * @c org.bluez.GattCharacterstic1.StopNotify() method is called by a
+ * client on the BlueZ-based OIC GATT response characteristic.  It
+ * sets the @c org.bluez.GattCharacterstic1.Notifying property to
+ * @c FALSE, and disables responses from the server.
+ *
+ * @param[in] object     @c org.bluez.GattCharacteristic1 skeleton
+ *                       object associated with this method call.
+ * @param[in] invocation D-Bus method invocation related object used
+ *                       when sending results/errors asynchronously.
+ * @param[in] user_data  Pointer to the response
+ *                       @c CAGattCharacteristic object.
+ *
+ * @return @c TRUE to indicate that
+ *         @c org.bluez.Characteristic.StopNotify() method is
+ *         implemented.
+ */
+static gboolean CAGattCharacteristicHandleStopNotify(
+    GattCharacteristic1 * object,
+    GDBusMethodInvocation * invocation,
+    gpointer user_data)
+{
+    assert(user_data != NULL);
+
+    /**
+     * @todo Does BlueZ already prevent redundant calls to
+     *       @c org.bluez.GattCharacteristic1.StopNotify()?
+     */
+    if (!gatt_characteristic1_get_notifying(object))
+    {
+        g_dbus_method_invocation_return_dbus_error(
+            invocation,
+            "org.bluez.Error.Failed",
+            "Notifications were not previously enabled.");
+
+        return TRUE;
+    }
+
+    CAGattCharacteristic * const characteristic = user_data;
+
+    // Clear the client endpoint from the request characteristic.
+    CAGattRecvInfo * const recv_info =
+        &characteristic->service->request_characteristic.recv_info;
+
+    /*
+      Remove the appropriate entry from the endpoint-to-characteristic
+      map so that attempts to send a response through it will fail.
+    */
+    CALEContext * const context = characteristic->context;
+    ca_mutex_lock(context->lock);
+
+    bool const removed =
+        g_hash_table_remove(context->characteristic_map, recv_info->peer);
+
+    ca_mutex_unlock(context->lock);
+
+    CAGattRecvInfoDestroy(recv_info);
+
+    /**
+     * @todo Do we need to explicitly emit the @c GObject @c notify or
+     *       @c org.freedesktop.Dbus.Properties.PropertiesChanged
+     *       signal here?
+     */
+    gatt_characteristic1_set_notifying(object, FALSE);
+
+    if (removed)
+    {
+        gatt_characteristic1_complete_stop_notify(object, invocation);
+    }
+    else
+    {
+        g_dbus_method_invocation_return_dbus_error(
+            invocation,
+            "org.bluez.Error.Failed",
+            "Error removing peer address information");
+    }
+
+    return TRUE;
+}
+
+// ---------------------------------------------------------------------
+//                   GATT Characteristic Lifecyle
+// ---------------------------------------------------------------------
+
+/**
+ * Initialize GATT characteristic fields.
+ *
+ * This function initializes the @c CAGattCharacteristic object fields.
+ *
+ * @param[out] c                   GATT characteristic information to
+ *                                 be initialized.
+ * @param[in]  context             Object containing the D-Bus
+ *                                 connection to the bus on which the
+ *                                 characteristic will be exported, as
+ *                                 well as the list of connected
+ *                                 devices.
+ * @param[in]  s                   Information about GATT service
+ *                                 to which the characteristic
+ *                                 belongs.
+ * @param[in]  characteristic_path @c GattCharacteristic1 object
+ *                                 path.
+ * @param[in]  uuid                GATT characteristic UUID.
+ * @param[in]  flag                GATT characteristic property flag,
+ *                                 i.e. @c "write-without-response"
+ *                                 for the request characteristic, and
+ *                                 @c "notify" for the response
+ *                                 characteristic.
+ *
+ * @note This function does not allocate the @a characteristic object
+ *       itself.  The caller is responsible for allocating that
+ *       memory.
+ *
+ * @todo Too many parameters.  Perhaps pass in a pointer to a struct
+ *       instead.
+ */
+static bool CAGattCharacteristicInitialize(
+    CAGattCharacteristic * c,
+    CALEContext * context,
+    CAGattService * s,
+    char const * characteristic_path,
+    char const * uuid,
+    char const * flag)
+{
+    // Path of the form /org/iotivity/gatt/hci0/service0/char0.
+    c->object_path =
+        g_strdup_printf("%s/%s", s->object_path, characteristic_path);
+
+    assert(g_variant_is_object_path(c->object_path));
+
+    c->context = context;
+    c->service = s;
+
+    c->characteristic = gatt_characteristic1_skeleton_new();
+
+    gatt_characteristic1_set_uuid(c->characteristic, uuid);
+    gatt_characteristic1_set_service(c->characteristic, s->object_path);
+    gatt_characteristic1_set_notifying(c->characteristic, FALSE);
+
+    char const * flags[] = { flag, NULL };
+    gatt_characteristic1_set_flags(c->characteristic, flags);
+
+    CAGattRecvInfoInitialize(&c->recv_info);
+
+    // Export the characteristic interface on the bus.
+    GError * error = NULL;
+    if (!g_dbus_interface_skeleton_export(
+            G_DBUS_INTERFACE_SKELETON(c->characteristic),
+            context->connection,
+            c->object_path,
+            &error))
+    {
+        CAGattCharacteristicDestroy(c);
+
+        OIC_LOG_V(ERROR,
+                  TAG,
+                  "Unable to export D-Bus GATT characteristic "
+                  "interface: %s",
+                  error->message);
+
+        g_error_free(error);
+
+        return false;
+    }
+
+    return true;
+}
+
+// ------------------------------------------------------------
+
+bool CAGattRequestCharacteristicInitialize(struct CAGattService * s,
+                                           CALEContext * context)
+{
+    CAGattCharacteristic * const c = &s->request_characteristic;
+
+    if (!CAGattCharacteristicInitialize(c,
+                                        context,
+                                        s,
+                                        CA_GATT_REQUEST_CHRC_PATH,
+                                        CA_GATT_REQUEST_CHRC_UUID,
+                                        "write-without-response"))
+    {
+        return false;
+    }
+
+    if (!CAGattRequestDescriptorInitialize(s, context->connection))
+    {
+        CAGattCharacteristicDestroy(c);
+        return false;
+    }
+
+    /*
+      The descriptor object path is not fixed at compile-time.
+      Retrieve the object path that was set at run-time.
+    */
+    char const * descriptor_paths[] = {
+        c->descriptor.object_path,
+        NULL
+    };
+
+    gatt_characteristic1_set_descriptors(c->characteristic,
+                                         descriptor_paths);
+
+    // The request characteristic only handles writes.
+    g_signal_connect(c->characteristic,
+                     "handle-write-value",
+                     G_CALLBACK(CAGattCharacteristicHandleWriteValue),
+                     c);
+
+    return true;
+}
+
+// ------------------------------------------------------------
+
+bool CAGattResponseCharacteristicInitialize(struct CAGattService * s,
+                                            CALEContext * context)
+{
+    CAGattCharacteristic * const c = &s->response_characteristic;
+
+    if (!CAGattCharacteristicInitialize(c,
+                                        context,
+                                        s,
+                                        CA_GATT_RESPONSE_CHRC_PATH,
+                                        CA_GATT_RESPONSE_CHRC_UUID,
+                                        "notify"))
+    {
+        return false;
+    }
+
+    c->service = s;
+
+    if (!CAGattResponseDescriptorInitialize(s, context->connection))
+    {
+        CAGattCharacteristicDestroy(c);
+        return false;
+    }
+
+    /*
+      The descriptor object path is not fixed at compile-time.
+      Retrieve the object path that was set at run-time.
+
+      Note that we don't explicitly add the Client Characteristic
+      Configuration Descriptor for the response characteristic since
+      that is done by BlueZ when the "notify" property is set.
+      Furthermore, a client requests notifications by calling the
+      org.bluez.GattCharacteristic1.StartNotify() method.
+      Consequently, there is no need for the client to explicitly
+      enable notifications by writing to the client characteristic
+      configuration descriptor.
+    */
+    char const * descriptor_paths[] = {
+        c->descriptor.object_path,
+        NULL
+    };
+
+    gatt_characteristic1_set_descriptors(c->characteristic,
+                                         descriptor_paths);
+
+    // The response characteristic only handles notifications.
+    g_signal_connect(
+        c->characteristic,
+        "handle-start-notify",
+        G_CALLBACK(CAGattCharacteristicHandleStartNotify),
+        c);
+
+    g_signal_connect(
+        c->characteristic,
+        "handle-stop-notify",
+        G_CALLBACK(CAGattCharacteristicHandleStopNotify),
+        c);
+
+    return true;
+}
+
+void CAGattCharacteristicDestroy(CAGattCharacteristic * c)
+{
+    assert(c != NULL);  // As designed, c is always non-NULL.
+
+    CAGattRecvInfoDestroy(&c->recv_info);
+
+    CAGattDescriptorDestroy(&c->descriptor);
+
+    g_clear_object(&c->characteristic);
+
+    g_free(c->object_path);
+    c->object_path = NULL;
+
+    c->service = NULL;
+    c->context = NULL;
+}
+
+// ---------------------------------------------------------------------
+//                  GATT Characteristic Properties
+// ---------------------------------------------------------------------
+
+
+GVariant * CAGattCharacteristicGetProperties(
+    GattCharacteristic1 * characteristic)
+{
+    /**
+     * Create a variant containing the @c GattCharacteristic1
+     * properties, of the form @c a{sa{sv}}.
+     *
+     * @note We don't care about the "Value" property here since it is
+     *       automatically made available by BlueZ on the client
+     *       side.
+     *
+     * @todo Should we care about "Notifying" property here?
+     */
+
+    /*
+      Populate the property table, and create the variant to be
+      embedded in the results of the
+      org.freedesktop.Dbus.ObjectManager.GetManagedObjects() method
+      call.
+    */
+    CADBusSkeletonProperty const properties[] = {
+        { "UUID",
+          g_variant_new_string(
+              gatt_characteristic1_get_uuid(characteristic)) },
+        { "Service",
+          g_variant_new_object_path(
+              gatt_characteristic1_get_service(characteristic)) },
+        { "Flags",
+          g_variant_new_strv(
+              gatt_characteristic1_get_flags(characteristic),
+              -1) },
+        { "Descriptors",
+          g_variant_new_objv(
+              gatt_characteristic1_get_descriptors(characteristic),
+              -1) }
+    };
+
+    return
+        CAMakePropertyDictionary(
+            BLUEZ_GATT_CHARACTERISTIC_INTERFACE,
+            properties,
+            sizeof(properties) / sizeof(properties[0]));
+}
diff --git a/resource/csdk/connectivity/src/bt_le_adapter/linux/characteristic.h b/resource/csdk/connectivity/src/bt_le_adapter/linux/characteristic.h
new file mode 100644 (file)
index 0000000..f7a4a37
--- /dev/null
@@ -0,0 +1,146 @@
+/* ****************************************************************
+ *
+ * Copyright 2015 Intel Corporation All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+#ifndef CA_BLE_LINUX_CHARACTERISTIC_H
+#define CA_BLE_LINUX_CHARACTERISTIC_H
+
+#include "bluez-glue.h"
+#include "descriptor.h"
+#include "recv.h"
+#include "context.h"
+
+
+/**
+ * OIC GATT Characteristic Information
+ *
+ * OIC GATT characteristics contain one user description descriptor.
+ *
+ * @note The response characteristic should also have a client
+ *       characteristic configuration descriptor.  However, BlueZ
+ *       implicitly adds that descriptor to the characteristic when
+ *       the characteristic "notify" property is set.  There is no
+ *       need to explicitly add that descriptor.
+ */
+typedef struct CAGattCharacteristic
+{
+
+    /**
+     * Object containing the D-Bus connection list of connected
+     * devices.
+     */
+    CALEContext * context;
+
+    /**
+     * IoTivity OIC GATT service information.
+     *
+     * @note This is currently only used by the response
+     *       characteristic to gain access to the request
+     *       characteristic @c client endpoint field.
+     *
+     * @todo It seems somewhat wasteful have a field available to both
+     *       response and request characteristics, but used by only
+     *       one of them.
+     */
+    struct CAGattService * service;
+
+    /// D-Bus object path for the GattCharacteristic1 object.
+    char * object_path;
+
+    /// OIC GATT service D-Bus interface skeleton object.
+    GattCharacteristic1 * characteristic;
+
+    /// OIC GATT user description descriptor information.
+    CAGattDescriptor descriptor;
+
+    /**
+     * Information used to keep track of received data fragments.
+     *
+     * @note This is only used by the OIC GATT request characteristic
+     *       skeleton implementation.  It is not needed by the
+     *       response characteristic skeleton.
+     *
+     * @todo It seems somewhat wasteful have a field available to both
+     *       response and request characteristics, but used by only
+     *       one of them.
+     */
+    CAGattRecvInfo recv_info;
+
+} CAGattCharacteristic;
+
+/**
+ * Initialize GATT request characteristic fields.
+ *
+ * This function initializes the request @c CAGattCharacteristic
+ * object fields.
+ *
+ * @param[in,out] s       Information about GATT service to which the
+ *                        characteristic belongs.
+ * @param[in]     context Object containing the D-Bus connection to
+ *                        the bus on which the characteristic will be
+ *                        exported, as well as the list of connected
+ *                        devices.
+ *
+ * @return @c true on success, @c false otherwise.
+ */
+bool CAGattRequestCharacteristicInitialize(struct CAGattService * s,
+                                           CALEContext * context);
+
+/**
+ * Initialize GATT response characteristic fields.
+ *
+ * This function initializes the response @c CAGattCharacteristic
+ * object fields.
+ *
+ * @param[in,out] s        Information about GATT service to which the
+ *                         characteristic belongs.
+ * @param[in]     context  Object containing the D-Bus connection to
+ *                         the bus on which the characteristic will be
+ *                         exported, as well as the list of connected
+ *                         devices.
+ *
+ * @return @c true on success, @c false otherwise.
+ */
+bool CAGattResponseCharacteristicInitialize(struct CAGattService * s,
+                                            CALEContext * context);
+
+/**
+ * Destroy GATT characteristic fields.
+ *
+ * This function finalizes the @c CAGattCharacteristic object fields.
+ *
+ * @param[in] characteristic GATT characteristic information to be
+ *                           finalized.
+ */
+void CAGattCharacteristicDestroy(CAGattCharacteristic * characteristic);
+
+/**
+ * Get all characteristic properties.
+ *
+ * @param[in] characteristic The D-Bus skeleton object from which the
+ *                           characteristic properties will be extracted.
+ * @return A variant of the form a{sa{sv}}, suitable for use in the
+ *         result of the
+ *         @c org.freedesktop.DBus.ObjectManager.GetManagedObjects()
+ *         method provided by the IoTivity the
+ *         @c org.bluez.GattService1 implementation.
+ */
+GVariant * CAGattCharacteristicGetProperties(
+    GattCharacteristic1 * characteristic);
+
+
+#endif  // CA_BLE_LINUX_CHARACTERISTIC_H
diff --git a/resource/csdk/connectivity/src/bt_le_adapter/linux/client.c b/resource/csdk/connectivity/src/bt_le_adapter/linux/client.c
new file mode 100644 (file)
index 0000000..6d5adba
--- /dev/null
@@ -0,0 +1,274 @@
+/******************************************************************
+ *
+ * Copyright 2015 Intel Corporation All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+#include "client.h"
+#include "recv.h"
+#include "context.h"
+#include "bluez.h"
+#include "utils.h"
+
+#include "cafragmentation.h"
+#include "logger.h"
+#include "oic_malloc.h"
+#include "oic_string.h"
+
+#include <gio/gio.h>
+
+#include <string.h>
+#include <assert.h>
+
+
+// Logging tag.
+static char const TAG[] = "BLE_CLIENT";
+
+// ---------------------------------------------------------------------
+//                        GATT Client Set-up
+// ---------------------------------------------------------------------
+static bool CAGattClientServiceFilter(GDBusProxy * service)
+{
+    /*
+      On the client side, we only care about the GATT services on
+      remote devices.  Ignore the locally created ones by checking for
+      the existence of the org.bluez.GattService1.Device property in
+      the service proxy.  GATT services on remote devices will have
+      that property.
+    */
+    GVariant * const remote_device =
+        g_dbus_proxy_get_cached_property(service, "Device");
+
+    if (remote_device == NULL)
+    {
+        return false;
+    }
+
+    /*
+      org.bluez.GattService1.Device property exists, meaning the
+      GATT service was advertised from a remote object.
+    */
+    g_object_unref(remote_device);
+    return true;
+}
+
+bool CAGattClientsInitialize(CALEContext * context)
+{
+    /*
+      Create a proxies to the org.bluez.GattService1 D-Bus objects that
+      will later be used to send requests and receive responses on the
+      client side.
+    */
+    GList * services = NULL;
+    bool success =
+        CAGetBlueZManagedObjectProxies(&services,
+                                       BLUEZ_GATT_SERVICE_INTERFACE,
+                                       context,
+                                       CAGattClientServiceFilter);
+
+    /**
+     * @todo Is this really an error?
+     */
+    if (!success)
+    {
+        return success;
+    }
+
+    /*
+      Map Bluetooth MAC address to OIC Transport Profile
+      characteristics.
+    */
+    GHashTable * const characteristic_map =
+        g_hash_table_new_full(g_str_hash,
+                              g_str_equal,
+                              OICFree,
+                              g_object_unref);
+
+    char const * const address = NULL;  // OICMalloc(...);
+    GDBusProxy * const client = NULL;
+
+#if GLIB_CHECK_VERSION(2,40,0)
+    /*
+      GLib hash table functions started returning a boolean result in
+       version 2.40.x.
+    */
+    success =
+#endif
+        g_hash_table_insert(characteristic_map,
+                            OICStrdup(address),
+                            client);
+
+    // An empty services list is NULL.
+    if (success && services != NULL)
+    {
+        ca_mutex_lock(context->lock);
+        context->characteristic_map = characteristic_map;
+        ca_mutex_unlock(context->lock);
+    }
+
+    return success;
+}
+
+bool CAGattClientsDestroy(CALEContext * context)
+{
+    /* g_hash_table_destroy(...); */   // FIXME
+    return false;
+}
+
+// ---------------------------------------------------------------------
+//                        GATT Request Send
+// ---------------------------------------------------------------------
+/**
+ * Send data to the GATT server through the given request
+ * @a characteristic proxy.
+ *
+ * @param[in] characteristic The D-Bus proxy of the request
+ *                           characteristic through which the
+ *                           @c WriteValue() method will be invoked.
+ * @param[in] data           The byte array to be sent.
+ * @param[in] length         The number of elements in the byte
+ *                           array.
+ */
+static bool CAGattClientSendRequestData(GDBusProxy * characteristic,
+                                        CALEContext * context,
+                                        char const * data,
+                                        size_t length)
+{
+    assert(context != NULL);
+
+    GVariant * const value =
+        g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE,
+                                  data,
+                                  length,
+                                  1);  // sizeof(data[0]) == 1
+
+    GError * error = NULL;
+
+    GVariant * const ret =
+        g_dbus_proxy_call_sync(characteristic,
+                               "WriteValue",
+                               value,  // parameters
+                               G_DBUS_CALL_FLAGS_NONE,
+                               -1,    // timeout (default == -1),
+                               NULL,  // cancellable
+                               &error);
+
+    if (ret == NULL)
+    {
+        OIC_LOG_V(ERROR,
+                  TAG,
+                  "[%p] WriteValue() call failed: %s",
+                  characteristic,
+                  error->message);
+
+        g_error_free(error);
+
+        ca_mutex_lock(context->lock);
+
+        if (context->on_client_error != NULL)
+        {
+            /*
+              At this point endpoint and send data information is
+              available.
+            */
+            context->on_client_error(NULL,   // endpoint
+                                     data,
+                                     length,
+                                     CA_STATUS_FAILED);
+        }
+
+        ca_mutex_unlock(context->lock);
+
+        return false;
+    }
+
+    g_variant_unref(ret);
+
+    return true;
+}
+
+CAResult_t CAGattClientSendData(void const * method_info,
+                                void const * data,
+                                size_t length)
+{
+    assert(method_info != NULL);
+
+    CAGattRequestInfo const * const info = method_info;
+
+    GDBusProxy * const characteristic =
+        G_DBUS_PROXY(info->characteristic_info);
+
+    return CAGattClientSendRequestData(characteristic,
+                                       info->context,
+                                       (char const *) data,
+                                       length);
+}
+
+CAResult_t CAGattClientSendDataToAll(void const * method_info,
+                                     void const * data,
+                                     size_t length)
+{
+    assert(method_info != NULL);
+
+    CAResult_t result = CA_STATUS_OK;
+
+    CAGattRequestInfo const * const info = method_info;
+
+    for (GList const * l = info->characteristic_info;
+         l != NULL && result == CA_STATUS_OK;
+         l = l->next)
+    {
+        GDBusProxy * const characteristic = G_DBUS_PROXY(l->data);
+
+        result = CAGattClientSendRequestData(characteristic,
+                                             info->context,
+                                             (char const *) data,
+                                             length);
+    }
+
+    return result;
+}
+
+// ---------------------------------------------------------------------
+//                      GATT Response Receive
+// ---------------------------------------------------------------------
+void CAGattReceiveResponse(GDBusConnection * connection,
+                           char const * sender_name,
+                           char const * object_path,
+                           char const * interface_name,
+                           char const * signal_name,
+                           GVariant   * parameters,
+                           gpointer     user_data)
+{
+    /*
+      This handler is only trigged in a GATT client when receiving
+      data sent by a GATT server through a notification, e.g. such as
+      when a GATT server sent a response.
+    */
+    gsize fragment_len = 0;
+    gconstpointer const fragment =
+        g_variant_get_fixed_array(parameters,
+                                  &fragment_len,
+                                  1);  // sizeof(guchar) == 1
+
+    CAGattRecvInfo * const info = user_data;
+
+    if (CAGattRecv(info, fragment, fragment_len))
+    {
+    }
+    else
+    {
+    }
+}
diff --git a/resource/csdk/connectivity/src/bt_le_adapter/linux/client.h b/resource/csdk/connectivity/src/bt_le_adapter/linux/client.h
new file mode 100644 (file)
index 0000000..46d260c
--- /dev/null
@@ -0,0 +1,91 @@
+/******************************************************************
+ *
+ * Copyright 2015 Intel Corporation All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+#ifndef CA_BLE_LINUX_CLIENT_H
+#define CA_BLE_LINUX_CLIENT_H
+
+#include "context.h"
+
+
+/**
+ * Information needed to when sending a request through a GATT
+ * client.
+ */
+typedef struct _CAGattRequestInfo
+{
+    /**
+     * Proxy or list of proxies to @c org.bluez.GattCharacteristic1
+     * object(s) through which request data will be sent to the GATT
+     * server.
+     *
+     * In the case of a unicast-style send, @c info will be a
+     * @c GDBusProxy* to an @c org.bluez.GattCharacteristic1 object.
+     * For a multicast-style send, @c info will be a * @c GList* of
+     * @c GDBusProxy* to @c GattCharacterstic1 objects on all GATT
+     * servers to which a connection exists.
+     */
+    void * const characteristic_info;
+
+    /**
+     * Context containing additional information that may be needed
+     * when sending a request.
+     */
+    CALEContext * const context;
+
+} CAGattRequestInfo;
+
+/**
+ * Send request data through a single user-specified BLE connection.
+ *
+ * @param[in] method_info Information necessary to send request.
+ * @param[in] data        Octet array of request data to be sent.
+ * @param[in] length      Length of the @a data octet array.
+ *
+ * @see @c CAGattSendMethod() for further details.
+ */
+bool CAGattSendRequest(void const * method_info,
+                       void const * data,
+                       size_t length);
+
+// ---------------------------------------------------------------
+//                   Multicast-style Request Send
+// ---------------------------------------------------------------
+/**
+ * Send request data through all BLE connections.
+ *
+ * Send the @a data to the GATT server found in all discovered LE
+ * peripherals.
+ *
+ * @param[in] method_info Information necessary to send request.
+ * @param[in] data        Octet array of request data to be sent.
+ * @param[in] length      Length of the @a data octet array.
+
+ * @note Since a multicast-like operation is being performed, an
+ *       assumption is made that a GATT client is sending data to a
+ *       server.  It makes no sense to multicast a response from a
+ *       single GATT server to multiple GATT clients in IoTivity's
+ *       case.
+ *
+ * @return @c CA_STATUS_OK on success, @c CA_STATUS_FAILED otherwise.
+ */
+CAResult_t CAGattClientSendDataToAll(void const * method_info,
+                                     void const * data,
+                                     size_t length);
+
+
+#endif  /* CA_BLE_LINUX_CLIENT_H */
diff --git a/resource/csdk/connectivity/src/bt_le_adapter/linux/context.h b/resource/csdk/connectivity/src/bt_le_adapter/linux/context.h
new file mode 100644 (file)
index 0000000..ce1ec01
--- /dev/null
@@ -0,0 +1,196 @@
+/******************************************************************
+ *
+ * Copyright 2015 Intel Corporation All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+#ifndef CA_BLE_LINUX_CONTEXT_H
+#define CA_BLE_LINUX_CONTEXT_H
+
+#include "caadapterinterface.h"
+#include "camutex.h"
+#include "cathreadpool.h"
+#include "caleinterface.h"
+
+#include <gio/gio.h>
+
+
+/**
+ * @internal
+ *
+ * BLE Linux adapter base context.
+ */
+typedef struct _CALEContext
+{
+    /// Connection to the D-Bus system bus.
+    GDBusConnection * connection;
+
+    /**
+     * Proxy to the BlueZ D-Bus object that implements the
+     * "org.freedesktop.DBus.ObjectManager" interface.
+     *
+     * @todo There's probably no need to keep this around after we've
+     *       retrieved the managed objects the first time around since
+     *       we can rely on signals to alert us to any subsequent
+     *       changes.
+     */
+    GDBusObjectManager * object_manager;
+
+    /**
+     * List of @c GDBusObject objects obtained from the BlueZ
+     * @c ObjectManager.
+     *
+     * @note This list will be updated later on as needed if changes
+     *       in the BlueZ ObjectManager are detected.
+     */
+    GList * objects;
+
+    /**
+     * BlueZ adapter list.
+     *
+     * List of @c GDBusProxy objects for all BlueZ adapters (i.e.
+     * @c org.bluez.Adapter1).  More than one adapter can exist if
+     * multiple Bluetooth hardware interfaces are detected by BlueZ.
+     */
+    GList * adapters;
+
+    /**
+     * BlueZ device list.
+     *
+     * List of @c GDBusProxy objects for all BlueZ devices (i.e.
+     * @c org.bluez.Device1), such as those that matched the discovery
+     * criteria.
+     */
+    GList * devices;
+
+    /**
+     * Bluetooth MAC address to GATT characteristic map.
+     *
+     * Hash table that maps Bluetooth MAC address to a OIC Transport
+     * Profile GATT characteristic.  The key is a string containing
+     * the peer Bluetooth adapter MAC address.   The value is an
+     * interface proxy (@c GDBusProxy) to an
+     * @c org.bluez.GattCharacteristic1 object.
+     *
+     * On the client side, this maps a Bluetooth peripheral MAC
+     * address to the corresponding request characteristic proxy.  On
+     * the server side, this maps Bluetooth central MAC address to the
+     * corresponding response characteristic proxy.
+     *
+     * @note On the server side a map is overkill since only one
+     *       client is ever connected to the server.  No?
+     *
+     * @todo We may want to have a seperate server-side map to reduce
+     *       contention on this map.
+     */
+    GHashTable * characteristic_map;
+
+    /**
+     * GATT characteristics to Bluetooth MAC address map.
+     *
+     * Hash table that maps OIC Transport Profile GATT characteristic
+     * to a Bluetooth MAC address.  The key is an interface proxy
+     * (@c GDBusProxy) to an @c org.bluez.GattCharacteristic1 object.
+     * The value is a pointer to the peer @c CAEndpoint_t object.
+     *
+     * On the client side, this maps a response characteristic to the
+     * corresponding MAC address.  On the server side, this maps
+     * request characteristic to the corresponding MAC address.
+     *
+     * @note On the server side a map is overkill since only one
+     *       client is ever connected to the server.  No?
+     *
+     * @todo We may want to have a seperate server-side map to reduce
+     *       contention on this map.
+     */
+    GHashTable * address_map;
+
+    /**
+     * D-Bus signal subscription identifiers.
+     *
+     * The Linux BLE transport implementation subscribes to three
+     * D-Bus signals:
+     *
+     * @li @c org.freedesktop.DBus.ObjectManager.InterfacesAdded
+     * @li @c org.freedesktop.DBus.ObjectManager.InterfacesRemoved
+     * @li @c org.freedesktop.DBus.Properties.PropertiesChanged
+     * @li @c org.bluez.Adapter1.PropertyChanged
+     *
+     * These subscription identifiers are only used when unsubscribing
+     * from the signals when stopping the LE transport.
+     *
+     * @todo Verify if we need the two property related signals at
+     *       this level.
+     */
+    //@{
+    guint interfaces_added_sub_id;
+    guint interfaces_removed_sub_id;
+    guint properties_changed_sub_id;
+    guint property_changed_sub_id;
+    //@}
+
+    /// Glib event loop that drives D-Bus signal handling.
+    GMainLoop * event_loop;
+
+    /**
+     * Callback invoked upon change in local Bluetooth adapter state.
+     */
+    CALEDeviceStateChangedCallback on_device_state_changed;
+
+    /// Callback invoked upon server receiving request data.
+    CABLEDataReceivedCallback on_server_received_data;
+
+    /// Callback invoked upon client receiving response data.
+    CABLEDataReceivedCallback on_client_received_data;
+
+    /**
+     * Handle to thread pool to which client side tasks will be
+     * added.
+     */
+    ca_thread_pool_t client_thread_pool;
+
+    /**
+     * Handle to thread pool to which server side tasks will be
+     * added.
+     */
+    ca_thread_pool_t server_thread_pool;
+
+    /// Callback invoked when reporting a client side error.
+    CABLEErrorHandleCallback on_client_error;
+
+    /// Callback invoked when reporting a server side error.
+    CABLEErrorHandleCallback on_server_error;
+
+    /// Mutex used to synchronize access to context fields.
+    ca_mutex lock;
+
+    /**
+     * BlueZ adapter list initialization condition variable.
+     *
+     * This condition variable is used to prevent the BLE adapter
+     * "start" from completing until the thread performing BlueZ
+     * adapter query completes.  Initialization is performed in the
+     * same thread that will run the event loop.  The condition
+     * variable is also used to wait for peripheral devices to be
+     * discovered.
+     *
+     * @see @c GMainLoop documentation for further details.
+     */
+    ca_cond condition;
+
+} CALEContext;
+
+
+#endif  /* CA_BLE_LINUX_CONTEXT_H */
diff --git a/resource/csdk/connectivity/src/bt_le_adapter/linux/descriptor.c b/resource/csdk/connectivity/src/bt_le_adapter/linux/descriptor.c
new file mode 100644 (file)
index 0000000..190d192
--- /dev/null
@@ -0,0 +1,225 @@
+/* ****************************************************************
+ *
+ * Copyright 2015 Intel Corporation All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+#include "descriptor.h"
+#include "service.h"
+#include "gatt_dbus.h"
+#include "utils.h"
+#include "bluez.h"
+
+#include "logger.h"
+#include "cagattservice.h"
+
+#include <assert.h>
+
+
+// Logging tag.
+static char const TAG[] = "BLE_DESCRIPTOR";
+
+/**
+ * Implementation of the @c org.bluez.GattDescriptor1.ReadValue()
+ * method.
+ *
+ * This function is implemented as a GDBus signal handler that returns
+ * a byte array containing the @c Value property of the GATT
+ * descriptor.
+ *
+ * @param[in] object     @c org.bluez.GattDescriptoror1 skeleton
+ *                       object associated with this method call.
+ * @param[in] invocation D-Bus method invocation related object used
+ *                       when sending results/errors asynchronously.
+ * @param[in] user_data  Unused.
+ *
+ * @return @c TRUE to indicate that
+ *         @c org.bluez.Descriptor.ReadValue()
+ *         method is implemented.
+ */
+static gboolean CAGattDescriptorReadValue(
+    GattDescriptor1 * object,
+    GDBusMethodInvocation * invocation,
+    gpointer user_data)
+{
+    /**
+     * @todo The @c GattDescriptor1 object still owns the returned
+     *       variant when using the below call.  Should be we use
+     *       @c gatt_descriptor1_dup_value() instead?
+     */
+    GVariant * const value = gatt_descriptor1_get_value(object);
+
+    gatt_descriptor1_complete_read_value(object, invocation, value);
+
+    return TRUE;
+}
+
+/**
+ * Initialize GATT descriptor fields.
+ *
+ * This function initializes the @c CAGattDescriptor object fields.
+ *
+ * @param[out] c               Information about GATT characteristic
+ *                             to which the descriptor belongs.
+ * @param[in]  connection      D-Bus connection to the bus on which
+ *                             the descriptor will be exported.
+ * @param[in]  s               Information about GATT service
+ *                             information to which the descriptor
+ *                             belongs.
+ * @param[in]  descriptor_path @c GattDescriptor1 object path for the
+ *                             user description descriptor.
+ * @param[in]  value           User description descriptor value,
+ *                             e.g. @c "OIC Node Request" or
+ *                             @c "OIC Node Response".
+ *
+ * @note This function does not allocate the @a descriptor object
+ *       itself.  The caller is responsible for allocating that
+ *       memory.
+ *
+ * @todo Too many parameters.  Perhaps pass in a pointer to a struct
+ *       instead.
+ */
+static bool CAGattDescriptorInitialize(CAGattCharacteristic * c,
+                                       GDBusConnection * connection,
+                                       CAGattService * s,
+                                       char const * descriptor_path,
+                                       char const * value)
+{
+    CAGattDescriptor * const d = &c->descriptor;
+
+    // Path of the form /org/iotivity/gatt/hci0/service0/char0/desc0.
+    d->object_path =
+        g_strdup_printf("%s/%s", c->object_path, descriptor_path);
+    assert(g_variant_is_object_path(d->object_path));
+
+    d->descriptor = gatt_descriptor1_skeleton_new();
+
+    gatt_descriptor1_set_uuid(
+        d->descriptor,
+        CA_GATT_CHRC_USER_DESCRIPTION_DESC_UUID);
+
+    gatt_descriptor1_set_characteristic(d->descriptor,
+                                        c->object_path);
+
+    gatt_descriptor1_set_value (d->descriptor,
+                                g_variant_new_bytestring(value));
+
+    // Readable, no encryption, no authorization.
+    static char const * flags[] = { "read", NULL };
+    gatt_descriptor1_set_flags(d->descriptor, flags);
+
+    /*
+      Connect the signal handler that implements the
+      orb.bluez.GattDescriptor1.ReadValue() method.
+    */
+    g_signal_connect(d->descriptor,
+                     "handle-read-value",
+                     G_CALLBACK(CAGattDescriptorReadValue),
+                     NULL);
+
+    // Export the descriptor interface on the bus.
+    GError * error = NULL;
+    if (!g_dbus_interface_skeleton_export(
+            G_DBUS_INTERFACE_SKELETON(d->descriptor),
+            connection,
+            d->object_path,
+            &error))
+    {
+        CAGattDescriptorDestroy(d);
+
+        OIC_LOG_V(ERROR,
+                  TAG,
+                  "Unable to export D-Bus GATT descriptor "
+                  "interface: %s",
+                  error->message);
+
+        g_error_free(error);
+
+        return false;
+    }
+
+    return true;
+}
+
+bool CAGattRequestDescriptorInitialize(struct CAGattService * s,
+                                       GDBusConnection * connection)
+{
+    CAGattCharacteristic * const c = &s->request_characteristic;
+
+    return CAGattDescriptorInitialize(c,
+                                      connection,
+                                      s,
+                                      CA_GATT_REQUEST_USER_DESC_PATH,
+                                      CA_GATT_REQUEST_USER_DESCRIPTION);
+}
+
+bool CAGattResponseDescriptorInitialize(struct CAGattService * s,
+                                        GDBusConnection * connection)
+{
+    CAGattCharacteristic * const c = &s->response_characteristic;
+
+    return CAGattDescriptorInitialize(c,
+                                      connection,
+                                      s,
+                                      CA_GATT_RESPONSE_USER_DESC_PATH,
+                                      CA_GATT_RESPONSE_USER_DESCRIPTION);
+}
+
+void CAGattDescriptorDestroy(CAGattDescriptor * d)
+{
+    assert(d != NULL);  // As designed, d is always non-NULL.
+
+    g_clear_object(&d->descriptor);
+
+    g_free(d->object_path);
+    d->object_path = NULL;
+}
+
+GVariant * CAGattDescriptorGetProperties(GattDescriptor1 * descriptor)
+{
+    /**
+     * Create a variant containing the @c GattDescriptor1 properties,
+     * of the form @c a{sa{sv}}.
+     *
+     * @note We don't care about the "Value" property here since it is
+     *       automatically made available by BlueZ on the client
+     *       side.
+     */
+
+    /*
+      Populate the property table, and create the variant to be
+      embedded in the results of the
+      org.freedesktop.Dbus.ObjectManager.GetManagedObjects() method
+      call.
+    */
+    CADBusSkeletonProperty const properties[] = {
+        { "UUID",
+          g_variant_new_string(
+              gatt_descriptor1_get_uuid(descriptor)) },
+        { "Characteristic",
+          g_variant_new_object_path(
+              gatt_descriptor1_get_characteristic(descriptor)) },
+        { "Flags",
+          g_variant_new_strv(
+              gatt_descriptor1_get_flags(descriptor),
+              -1) }
+    };
+
+    return
+        CAMakePropertyDictionary(
+            BLUEZ_GATT_DESCRIPTOR_INTERFACE,
+            properties,
+            sizeof(properties) / sizeof(properties[0]));
+}
diff --git a/resource/csdk/connectivity/src/bt_le_adapter/linux/descriptor.h b/resource/csdk/connectivity/src/bt_le_adapter/linux/descriptor.h
new file mode 100644 (file)
index 0000000..8856eb4
--- /dev/null
@@ -0,0 +1,100 @@
+/* ****************************************************************
+ *
+ * Copyright 2015 Intel Corporation All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+#ifndef CA_BLE_LINUX_DESCRIPTOR_H
+#define CA_BLE_LINUX_DESCRIPTOR_H
+
+#include "bluez-glue.h"
+
+#include <stdbool.h>
+
+
+/**
+ * OIC GATT Descriptor Information
+ */
+typedef struct CAGattDescriptor
+{
+    /// D-Bus object path for the GattCharacteristic1 object.
+    char * object_path;
+
+    /// OIC GATT service D-Bus interface skeleton object.
+    GattDescriptor1 * descriptor;
+
+} CAGattDescriptor;
+
+// Forward declarations.
+struct CAGattService;
+
+/**
+ * Initialize GATT request descriptor fields.
+ *
+ * This function initializes the request @c CAGattDescriptor object
+ * fields.
+ *
+ * @param[in,out] s          Information about GATT service to which the
+ *                           characteristic and descriptor belong.
+ * @param[in]     connection D-Bus connection to the bus on which the
+ *                           descriptor will be exported.
+ *
+ * @return @c true on success, @c false otherwise.
+ */
+bool CAGattRequestDescriptorInitialize(struct CAGattService * s,
+                                       GDBusConnection * connection);
+
+/**
+ * Initialize GATT response descriptor fields.
+ *
+ * This function initializes the response @c CAGattDescriptor object
+ * fields.
+ *
+ * @param[in,out] s          Information about GATT service to which the
+ *                           characteristic and descriptor belong.
+ * @param[in]     connection D-Bus connection to the bus on which the
+ *                           descriptor will be exported.
+ *
+ * @return @c true on success, @c false otherwise.
+ */
+bool CAGattResponseDescriptorInitialize(struct CAGattService *s,
+                                        GDBusConnection * connection);
+
+/**
+ * Destroy GATT descriptor fields.
+ *
+ * This function finalizes the @c CAGattDescriptor object fields.
+ *
+ * @param[in] descriptor GATT characteristic information to be
+ *                       finalized.
+ */
+void CAGattDescriptorDestroy(CAGattDescriptor * descriptor);
+
+/**
+ * Get all descriptor properties.
+ *
+ * @param[in] descriptor The D-Bus skeleton object from which the
+ *                       descriptor properties will be extracted.
+ *
+ * @return A variant of the form a{sa{sv}}, suitable for use in the
+ *         result of the
+ *         @c org.freedesktop.DBus.ObjectManager.GetManagedObjects()
+ *         method provided by the IoTivity the
+ *         @c org.bluez.GattService1 implementation.
+ */
+GVariant * CAGattDescriptorGetProperties(GattDescriptor1 * descriptor);
+
+
+#endif  // CA_BLE_LINUX_DESCRIPTOR_H
diff --git a/resource/csdk/connectivity/src/bt_le_adapter/linux/gatt_dbus.h b/resource/csdk/connectivity/src/bt_le_adapter/linux/gatt_dbus.h
new file mode 100644 (file)
index 0000000..5d55a8a
--- /dev/null
@@ -0,0 +1,89 @@
+/******************************************************************
+ *
+ * Copyright 2015 Intel Corporation All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+#ifndef CA_BLE_LINUX_GATT_DBUS_H
+#define CA_BLE_LINUX_GATT_DBUS_H
+
+
+/**
+ * @name BlueZ GATT Service D-Bus Object Paths
+ *
+ * The IoTivity BlueZ GATT Service hierarchy is the following:
+ *
+ *  -> /org/iotivity/gatt/advertisement0
+ *
+ *  -> /org/iotivity/gatt/<hciX>/service0
+ *    |   - OIC GATT Service
+ *    |
+ *    -> /org/iotivity/gatt/<hciX>/service0/char0
+ *    | |   - OIC GATT Request Characteristic Value
+ *    | |
+ *    | -> /org/iotivity/gatt/<hciX>/service0/char0/desc0
+ *    |       - OIC GATT Request User Description Descriptor
+ *    |
+ *    -> /org/iotivity/gatt/<hciX>/service0/char1
+ *      |   - OIC GATT Response Characteristic Value
+ *      |
+ *      -> /org/iotivity/gatt/<hciX>/service0/char1/desc0
+ *            - OIC GATT Response User Description Descriptor
+ *
+ * where <hciX> corresponds to the bluetooth hardware adapter with
+ * which the GATT service is being registered, e.g. "hci0".
+ *
+ * @note The OIC GATT Client Characterstic Configuration Descriptor is
+ *       implicitly added to the response characteristic hierarchy by
+ *       BlueZ since its "notify" property is set.
+ */
+//@{
+
+/**
+ * Root object path of the GATT service hierarchy.
+ *
+ * The GATT service object manager (i.e. implementation of
+ * @c org.freedesktop.DBus.ObjectManager) is found at this object
+ * path.
+ */
+#define CA_GATT_SERVICE_ROOT_PATH "/org/iotivity/gatt"
+
+// ------------------------
+
+#define CA_LE_ADVERTISEMENT_PATH "advertisement0"
+
+// ------------------------
+
+/// GATT service object path basename.
+#define CA_GATT_SERVICE_PATH  "service0"
+
+// ------------------------
+
+/// Request GATT characteristic object path basename.
+#define CA_GATT_REQUEST_CHRC_PATH "char0"
+
+/// Request GATT user description descriptor object path basename.
+#define CA_GATT_REQUEST_USER_DESC_PATH "desc0"
+
+// ------------------------
+
+/// Response GATT characteristic object path basename.
+#define CA_GATT_RESPONSE_CHRC_PATH "char1"
+
+/// Response GATT user description descriptor object path basename.
+#define CA_GATT_RESPONSE_USER_DESC_PATH "desc0"
+//@}
+
+#endif // CA_BLE_LINUX_GATT_DBUS_H
diff --git a/resource/csdk/connectivity/src/bt_le_adapter/linux/object_manager.xml b/resource/csdk/connectivity/src/bt_le_adapter/linux/object_manager.xml
new file mode 100644 (file)
index 0000000..58666c9
--- /dev/null
@@ -0,0 +1,45 @@
+<!--
+    Copyright 2015 Intel Corporation All Rights Reserved.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+    ******************************************************************
+
+    D-Bus introspection XML for the standard
+    org.freedesktop.DBus.ObjectManager interface.
+
+    The introspection XML found in this file is used to generate GDBus
+    skeleton code that will be used by the IoTivity BlueZ-based GATT
+    Service implementation.
+-->
+
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
+"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<node>
+  <interface name="org.freedesktop.DBus.ObjectManager">
+    <method name="GetManagedObjects">
+      <arg name="objects" type="a{oa{sa{sv}}}" direction="out"/>
+    </method>
+
+    <signal name="InterfacesAdded">
+      <arg name="object" type="o"/>
+      <arg name="interfaces" type="a{sa{sv}}"/>
+    </signal>
+
+    <signal name="InterfacesRemoved">
+      <arg name="object" type="o"/>
+      <arg name="interfaces" type="as"/>
+    </signal>
+  </interface>
+
+</node>
diff --git a/resource/csdk/connectivity/src/bt_le_adapter/linux/org.iotivity.gatt.service.conf.in b/resource/csdk/connectivity/src/bt_le_adapter/linux/org.iotivity.gatt.service.conf.in
new file mode 100644 (file)
index 0000000..a3f0a23
--- /dev/null
@@ -0,0 +1,19 @@
+<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+
+<!-- D-Bus policy for the IoTivity Linux BLE transport. -->
+<busconfig>
+  <policy context="default">
+    <allow own=@service_name@/>
+    <allow send_destination=@service_name@/>
+
+    <allow send_interface="org.freedesktop.DBus.ObjectManager"
+           send_type="method_call" send_member="GetManagedObjects"/>
+
+    <allow send_interface="org.bluez.GattService1"/>
+    <allow send_interface="org.bluez.GattCharacteristic1"/>
+    <allow send_interface="org.bluez.GattDescriptor1"/>
+
+    <allow send_interface="org.bluez.LEAdvertisement1"/>
+  </policy>
+</busconfig>
diff --git a/resource/csdk/connectivity/src/bt_le_adapter/linux/peripheral.c b/resource/csdk/connectivity/src/bt_le_adapter/linux/peripheral.c
new file mode 100644 (file)
index 0000000..0054767
--- /dev/null
@@ -0,0 +1,702 @@
+/******************************************************************
+ *
+ * Copyright 2015 Intel Corporation All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+#include "peripheral.h"
+#include "utils.h"
+#include "bluez.h"
+#include "service.h"
+#include "characteristic.h"
+#include "descriptor.h"
+
+#include "oic_malloc.h"
+#include "logger.h"
+
+#include <string.h>
+#include <assert.h>
+
+
+#define MICROSECS_PER_SEC 1000000
+
+// Logging tag.
+static char const TAG[] = "BLE_PERIPHERAL";
+
+static CAPeripheralContext g_context = {
+    .lock = NULL
+};
+
+static bool CAPeripheralCheckStarted()
+{
+    ca_mutex_lock(g_context.lock);
+
+    bool const started = (g_context.base != NULL);
+
+    ca_mutex_unlock(g_context.lock);
+
+    /**
+     * @todo Fix potential TOCTOU race condition.  A peripheral could
+     *       have been started or stopped between the mutex unlock and
+     *       boolean check.
+     */
+    return started;
+}
+
+
+static bool CAPeripheralAdaptersFound(CALEContext * context)
+{
+    // Check if BlueZ detected bluetooth hardware adapters.
+    ca_mutex_lock(context->lock);
+
+    bool const found = (context->adapters != NULL);
+
+    ca_mutex_unlock(context->lock);
+
+    if (!found)
+    {
+        OIC_LOG(WARNING, TAG, "No bluetooth hardware found.");
+    }
+
+    return found;
+}
+
+static void CAPeripheralDestroyGattServices(gpointer data)
+{
+    CAGattService * const service = data;
+
+    CAGattServiceDestroy(service);
+
+    OICFree(service);
+}
+
+static GList * CAPeripheralInitializeGattServices(CALEContext * context)
+{
+    GList * result = NULL;
+
+    /*
+      Create a proxies to the org.bluez.GattManager1 D-Bus objects that
+      will later be used to register the OIC GATT service.
+    */
+    GList * gatt_managers = NULL;
+    if (!CAGetBlueZManagedObjectProxies(&gatt_managers,
+                                        BLUEZ_GATT_MANAGER_INTERFACE,
+                                        context,
+                                        NULL))
+        return result;
+
+    GList * gatt_services = NULL;
+
+    for (GList * l = gatt_managers; l != NULL; )
+    {
+        CAGattService * const service = OICCalloc(1, sizeof(*service));
+
+        if (service == NULL)
+        {
+            g_list_free_full(gatt_services,
+                             CAPeripheralDestroyGattServices);
+            g_list_free_full(gatt_managers, g_object_unref);
+            return result;
+        }
+
+        /*
+          Use the HCI device name (e.g. hci0) in GattManager1 object
+          path (e.g. /org/bluez/hci0) as a means to differentiate the
+          GATT service hierarchy for each GattManager1 object.
+        */
+        GDBusProxy * const manager = G_DBUS_PROXY(l->data);
+        char const * const path = g_dbus_proxy_get_object_path(manager);
+
+        /*
+          The return value will actually be a pointer to a substring
+          starting with the '/' before the HCI name.  We add 1 later
+          on to skip that character.
+        */
+        char const * const hci_name = strrchr(path, '/');
+
+        if (hci_name == NULL
+            || !CAGattServiceInitialize(service, context, hci_name + 1))
+        {
+            g_list_free_full(gatt_services,
+                             CAPeripheralDestroyGattServices);
+            g_list_free_full(gatt_managers, g_object_unref);
+            return result;
+        }
+
+        service->gatt_manager = manager;
+
+        /*
+          The GattManager1 proxies are now owned by the CAGattService
+          objects.
+        */
+        GList * const tmp = l;
+        l = l->next;
+        gatt_managers = g_list_delete_link(gatt_managers, tmp);
+
+        // Prepend for efficiency.
+        gatt_services = g_list_prepend(gatt_services, service);
+    }
+
+    result = gatt_services;
+
+    return result;
+}
+
+static bool CAPeripheralRegisterGattServices(
+    CAPeripheralContext * context)
+{
+    assert(context != NULL);
+
+    bool success = false;
+
+    ca_mutex_lock(context->lock);
+
+    for (GList * l = context->gatt_services; l != NULL; l = l->next)
+    {
+        CAGattService * const service = l->data;
+
+        // Register the OIC service with the corresponding BlueZ Gatt
+        // Manager.
+
+        /*
+          org.bluez.GattManager1.RegisterService() accepts two
+          parameters: the service object path, and an options
+          dictionary.  No options are used so pass a NULL pointer to
+          reflect an empty dictionary.
+        */
+        GVariant * const parameters =
+            g_variant_new("(oa{sv})", service->object_path, NULL);
+
+        GError * error = NULL;
+
+        GVariant * const ret =
+            g_dbus_proxy_call_sync(
+                service->gatt_manager,
+                "RegisterService",
+                parameters,
+                G_DBUS_CALL_FLAGS_NONE,
+                -1,    // timeout (default == -1),
+                NULL,  // cancellable
+                &error);
+
+        if (ret == NULL)
+        {
+            OIC_LOG_V(ERROR,
+                      TAG,
+                      "GATT service registration failed: %s",
+                      error->message);
+
+            g_error_free(error);
+
+            success = false;
+
+            break;
+        }
+
+        g_variant_unref(ret);
+    }
+
+    ca_mutex_unlock(context->lock);
+
+    success = true;
+
+    return success;
+}
+
+static bool CAPeripheralRegisterAdvertisements(
+    CAPeripheralContext * context)
+{
+    bool success = false;
+
+    /*
+      Register the OIC LE advertisement service with each BlueZ
+      LE Advertisement Manager.
+    */
+
+    ca_mutex_lock(context->lock);
+
+    char const * const advertisement_path =
+        g_dbus_interface_skeleton_get_object_path(
+            G_DBUS_INTERFACE_SKELETON(
+                context->advertisement.advertisement));
+
+    GList * managers = context->advertisement.managers;
+
+    for (GList * l = managers; l != NULL; )
+    {
+        GDBusProxy * const manager = G_DBUS_PROXY(l->data);
+
+        /**
+         * @c org.bluez.LEAdvertisingManager1.RegisterService()
+         * accepts two parameters: the advertisement object path, and
+         * an options dictionary.  No options are used so pass a NULL
+         * pointer to reflect an empty dictionary.
+         *
+         *  @todo The parameters don't change between loop iterations.
+         *        Ideally we should initialize this variable before
+         *        the loop is executed, but g_dbus_proxy_call_sync()
+         *        takes ownership of the variant.  Is there anyway to
+         *        create a non-floating GVariant and pass it to that
+         *        function?
+         */
+        GVariant * const parameters =
+            g_variant_new("(oa{sv})", advertisement_path, NULL);
+
+        GError * error = NULL;
+
+        GVariant * const ret =
+            g_dbus_proxy_call_sync(
+                manager,
+                "RegisterAdvertisement",
+                parameters,
+                G_DBUS_CALL_FLAGS_NONE,
+                -1,    // timeout (default == -1),
+                NULL,  // cancellable
+                &error);
+
+        if (ret == NULL)
+        {
+            OIC_LOG_V(WARNING,
+                      TAG,
+                      "LE advertisement registration on %s failed: %s",
+                      g_dbus_proxy_get_object_path(manager),
+                      error->message);
+
+            g_error_free(error);
+
+            // We can't use the LE advertising manager.  Drop it.
+            g_object_unref(manager);
+
+            GList * const tmp = l;
+            l = l->next;
+            managers = g_list_delete_link(managers, tmp);
+
+            continue;
+        }
+
+        g_variant_unref(ret);
+
+        /*
+          Note that we can do this in the for-statement because of
+          the similar code in the error case above.
+        */
+        l = l->next;
+    }
+
+    // Use the updated list of managers.
+    context->advertisement.managers = managers;
+
+    if (managers == NULL)   // Empty
+    {
+        OIC_LOG(ERROR,
+                TAG,
+                "LE advertisment registration failed for all "
+                "Bluetooth adapters.");
+    }
+    else
+    {
+
+        success = true;
+    }
+
+    ca_mutex_unlock(context->lock);
+
+    return success;
+}
+
+static void CAPeripheralSetDiscoverable(gpointer data,
+                                        gpointer user_data,
+                                        gboolean discoverable)
+{
+    assert(data != NULL);
+    assert(user_data != NULL);
+
+    GDBusProxy * const adapter = G_DBUS_PROXY(data);
+    CAResult_t * const result = (CAResult_t *) user_data;
+    *result = CA_STATUS_FAILED;
+
+    /*
+      Make sure the adapter is powered on before making it
+      discoverable.
+    */
+    if (!CASetBlueZObjectProperty(adapter,
+                                  BLUEZ_ADAPTER_INTERFACE,
+                                  "Powered",
+                                  g_variant_new_boolean(discoverable)))
+    {
+        OIC_LOG_V(ERROR,
+                  TAG,
+                  "Unable to power %s LE peripheral adapter.",
+                  discoverable ? "on" : "off");
+
+        return;
+    }
+
+    /**
+     * @note Enabling LE advertising used to be done here using the
+     *       kernel bluetooth management API.  However, we now
+     *       leverage the BlueZ LE Advertisment D-Bus API instead
+     *       since it handles all of the desired advertising
+     *       operations without need of the calling process to have
+     *       @c CAP_NET_ADMIN capabilities.  Advertisment registration
+     *       is performed in this source file.
+     */
+
+    *result = CA_STATUS_OK;
+}
+
+static void CAPeripheralMakeDiscoverable(gpointer adapter,
+                                         gpointer result)
+{
+    CAPeripheralSetDiscoverable(adapter, result, TRUE);
+}
+
+static void CAPeripheralMakeUndiscoverable(gpointer adapter,
+                                           gpointer result)
+{
+    CAPeripheralSetDiscoverable(adapter, result, FALSE);
+}
+
+static CAResult_t CAPeripheralSetDiscoverability(
+    CALEContext * context,
+    GFunc discoverability_func)
+{
+    CAResult_t result = CA_STATUS_FAILED;
+
+    /*
+      Synchronize access to the adapter information using the base
+      context lock since we don't own the adapter_infos.
+     */
+    ca_mutex_lock(context->lock);
+
+    // Make all detected adapters discoverable.
+    g_list_foreach(context->adapters,
+                   discoverability_func,
+                   &result);
+
+    ca_mutex_unlock(context->lock);
+
+    return result;
+}
+
+/**
+ * Callback function invoked when a D-Bus bus name is acquired.
+ *
+ * @param[in] connection The D-Bus connection on which the name was
+ *                       acquired.
+ * @param[in] name       The bus name that was acquired.
+ * @param[in] user_data  User-provided data.
+ */
+static void CAPeripheralOnNameAcquired(GDBusConnection * connection,
+                                       gchar const * name,
+                                       gpointer user_data)
+{
+    OIC_LOG_V(DEBUG,
+              TAG,
+              "Name \"%s\" acquired on D-Bus.", name);
+}
+
+/**
+ * Callback function invoked when a D-Bus bus name is no longer owned
+ * or the D-Bus connection has been closed.
+ *
+ * @param[in] connection The D-Bus connection on which the bus name
+ *                       should have been acquired.
+ * @param[in] name       The bus name that was not acquired.
+ * @param[in] user_data  User-provided data.
+ */
+static void CAPeripheralOnNameLost(GDBusConnection * connection,
+                                   gchar const * name,
+                                   gpointer user_data)
+{
+    /*
+      This can happen if the appropriate D-Bus policy is not
+      installed, for example.
+    */
+    OIC_LOG_V(WARNING,
+              TAG,
+              "Lost name \"%s\" on D-Bus!", name);
+}
+
+static void CAPeripheralStartEventLoop(void * data)
+{
+    CALEContext * const context = data;
+
+    assert(context != NULL);
+
+    // Create the event loop.
+    GMainContext * const loop_context = g_main_context_new();
+    GMainLoop * const event_loop = g_main_loop_new(loop_context, FALSE);
+
+    g_main_context_push_thread_default(loop_context);
+
+    // Acquire the bus name after exporting our D-Bus objects.
+    guint const owner_id =
+        g_bus_own_name_on_connection(context->connection,
+                                     CA_DBUS_GATT_SERVICE_NAME,
+                                     G_BUS_NAME_OWNER_FLAGS_NONE,
+                                     CAPeripheralOnNameAcquired,
+                                     CAPeripheralOnNameLost,
+                                     NULL, // user_data,
+                                     NULL);
+
+    /**
+     * Create proxies to the @c org.bluez.LEAdvertisingManager1 D-Bus
+     * objects that will later be used to register the OIC LE
+     * advertisement data.
+     *
+     * @todo Failure to retrieve the LE advertising managers is
+     *       currently ignored.  We should propagate the failure to
+     *       the thread that spawned this one.
+     *
+     * @note Retrieval of the @c org.bluez.LEAdvertisingManager1
+     *       proxies must be done in a thread separate from the one
+     *       that makes calls through those proxies since the
+     *       underlying GDBusObjectManagerClient sets up signal
+     *       subscriptions that are used when dispatching D-Bus method
+     *       handling calls (e.g. property retrieval, etc).
+     *       Otherwise, a distributed deadlock situation could occur
+     *       if a synchronous D-Bus proxy call is made that causes the
+     *       recipient (like BlueZ) to call back in to the thread that
+     *       handles signals.  For example, registration of our LE
+     *       advertisment with BlueZ causes BlueZ itself to make a
+     *       call to our own @c org.bluez.LEAdvertisement1 object.
+     *       However, the thread that initiated the advertisement
+     *       registration is blocked waiting for BlueZ to respond, but
+     *       BlueZ is blocked waiting for that same thread to respond
+     *       to its own advertisement property retrieval call.
+     */
+    GList * advertising_managers = NULL;
+    if (!CAGetBlueZManagedObjectProxies(
+            &advertising_managers,
+            BLUEZ_ADVERTISING_MANAGER_INTERFACE,
+            context,
+            NULL))
+    {
+        OIC_LOG(ERROR,
+                TAG,
+                "Failed to retrieve BlueZ LE advertising "
+                "manager interface.");
+    }
+
+    /**
+     * Initialize all GATT services.
+     *
+     * @todo Failure to initialize the OIC GATT services is currently
+     *       ignored.  We should propagate the failure to the thread
+     *       that spawned this one.
+     *
+     * @note See the @c org.bluez.LEAdvertisingManager1 note above to
+     *       understand why the GATT services must be initialized in
+     *       a thread seperate from the one that initiates GATT
+     *       service registration.
+     */
+    GList * const gatt_services =
+        CAPeripheralInitializeGattServices(context);
+
+    ca_mutex_lock(g_context.lock);
+
+    assert(g_context.event_loop == NULL);
+    g_context.event_loop = event_loop;
+
+    g_context.base = context;
+
+    g_context.owner_id = owner_id;
+
+    CALEAdvertisementInitialize(&g_context.advertisement,
+                                context->connection,
+                                advertising_managers);
+
+    g_context.gatt_services = gatt_services;
+
+    ca_mutex_unlock(g_context.lock);
+
+    ca_cond_signal(g_context.condition);
+
+    g_main_loop_run(event_loop);
+}
+
+static void CAPeripheralStopEventLoop(CAPeripheralContext * context)
+{
+    ca_mutex_lock(context->lock);
+
+    GMainLoop * const event_loop = context->event_loop;
+    context->event_loop = NULL;
+
+    ca_mutex_unlock(context->lock);
+
+    if (event_loop != NULL)
+    {
+        g_main_loop_quit(event_loop);
+
+        GMainContext * const loop_context =
+            g_main_loop_get_context(event_loop);
+
+        if (loop_context != NULL)
+        {
+            g_main_context_wakeup(loop_context);
+            g_main_context_unref(loop_context);
+        }
+
+        g_main_loop_unref(event_loop);
+    }
+}
+
+// ------------------------------------------------------
+
+void CAPeripheralInitialize()
+{
+    g_context.lock      = ca_mutex_new();
+    g_context.condition = ca_cond_new();
+}
+
+void CAPeripheralFinalize()
+{
+    ca_cond_free(g_context.condition);
+    ca_mutex_free(g_context.lock);
+}
+
+CAResult_t CAPeripheralStart(CALEContext * context)
+{
+    /**
+     * @todo Bluetooth adapters that are hot-plugged after the
+     *       peripheral has started will not be started!
+     */
+
+    CAResult_t result = CA_STATUS_FAILED;
+
+    // Only start if we were previously stopped.
+    if (CAPeripheralCheckStarted())
+    {
+        result = CA_SERVER_STARTED_ALREADY;
+        return result;
+    }
+
+    if (!CAPeripheralAdaptersFound(context))
+    {
+        // No Bluetooth adapters.  Don't bother continuing.
+        return result;
+    }
+
+    /*
+      Spawn a thread to run the Glib event loop that will drive D-Bus
+      signal handling.
+     */
+    result = ca_thread_pool_add_task(context->server_thread_pool,
+                                     CAPeripheralStartEventLoop,
+                                     context);
+
+    if (result != CA_STATUS_OK)
+    {
+        return result;
+    }
+
+    /*
+      Wait until initialization completes before proceeding to
+      service and advertisement registration.
+    */
+
+    // Number of times to wait for initialization to complete.
+    static int const max_retries = 2;
+
+    static uint64_t const timeout =
+        2 * MICROSECS_PER_SEC;  // Microseconds
+
+    ca_mutex_lock(g_context.lock);
+
+    for (int i = 0;
+         g_context.gatt_services == NULL && i < max_retries;
+         ++i)
+    {
+        if (ca_cond_wait_for(g_context.condition,
+                             g_context.lock,
+                             timeout) == 0)
+        {
+            result = CA_STATUS_OK;
+        }
+    }
+
+    ca_mutex_unlock(g_context.lock);
+
+    if (result == CA_STATUS_FAILED)
+    {
+        return result;
+    }
+
+    /**
+     * First register the GATT services, then register the LE
+     * advertisments with BlueZ to make sure the service we're
+     * advertising actually exists.
+     */
+    if (result == CA_STATUS_OK
+        && !(CAPeripheralRegisterGattServices(context)
+             && CAPeripheralRegisterAdvertisements(&g_context)))
+    {
+        result = CA_STATUS_FAILED;
+    }
+
+    /*
+      Make the local bluetooth adapters discoverable over LE by
+      enabling LE, enabling advertising, and making the LE device
+      connectable.
+    */
+    result = CAPeripheralSetDiscoverability(context,
+                                            CAPeripheralMakeDiscoverable);
+
+    return result;
+}
+
+CAResult_t CAPeripheralStop()
+{
+    CAResult_t result = CA_STATUS_FAILED;
+
+    // Only stop if we were previously started.
+    if (!CAPeripheralCheckStarted())
+    {
+        result = CA_STATUS_OK;
+        return result;
+    }
+
+    /*
+      Make the local bluetooth adapters undiscoverable.
+
+      This function also sets the base context to NULL.
+    */
+    result =
+        CAPeripheralSetDiscoverability(g_context.base,
+                                       CAPeripheralMakeUndiscoverable);
+
+    CAPeripheralStopEventLoop(&g_context);
+
+    ca_mutex_lock(g_context.lock);
+
+    guint const owner_id = g_context.owner_id;
+    g_context.owner_id = 0;
+
+    GList * const gatt_services = g_context.gatt_services;
+    g_context.gatt_services = NULL;
+
+    g_context.base = NULL;
+
+    ca_mutex_unlock(g_context.lock);
+
+    CALEAdvertisementDestroy(&g_context.advertisement);
+
+    g_list_free_full(gatt_services, CAPeripheralDestroyGattServices);
+
+    g_bus_unown_name(owner_id);
+
+    return result;
+}
diff --git a/resource/csdk/connectivity/src/bt_le_adapter/linux/peripheral.h b/resource/csdk/connectivity/src/bt_le_adapter/linux/peripheral.h
new file mode 100644 (file)
index 0000000..89d9318
--- /dev/null
@@ -0,0 +1,128 @@
+/******************************************************************
+ *
+ * Copyright 2015 Intel Corporation All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+#ifndef CA_BLE_LINUX_PERIPHERAL_H
+#define CA_BLE_LINUX_PERIPHERAL_H
+
+#include "context.h"
+#include "advertisement.h"
+
+#include "cacommon.h"
+
+
+/**
+ * @internal
+ *
+ * Linux BLE "peripheral" context.
+ */
+typedef struct _CAPeripheralContext
+{
+    /**
+     * Base context.
+     *
+     * The base context contains core state used throughout the Linux
+     * BLE adapter implementation.
+     */
+    CALEContext * base;
+
+    /// D-Bus bus name owner ID.
+    guint owner_id;
+
+    /**
+     * LE advertising information.
+     *
+     * The LE advertising information will be registered with BlueZ,
+     * which BlueZ will then use to add advertising data to each of
+     * the detected Bluetooth hardware adapters.  Only one set of
+     * advertising data is needed since the data is the same for all
+     * adapters.
+     */
+    CALEAdvertisement advertisement;
+
+    /**
+     * List of @c CAGattService objects containing information for all
+     * exported and registered IoTivity BlueZ GATT related D-Bus
+     * objects.
+     */
+    GList * gatt_services;
+
+    /**
+     * Glib event loop that drives peripheral D-Bus signal
+     * handling.
+     *
+     * @note A seperate thread drives this event loop.  This is
+     *       necessitated by the need for signal subscriptions to be
+     *       done in what the GLib documentation refers to as the
+     *       "thread-default main context".  By the time the
+     *       peripheral is started it's too late the use the main loop
+     *       that was run when this Linux BLE transport adapter itself
+     *       was started through @c CASelectNetwork() and the @c
+     *       CAAdapterStart() callback the peripheral must have its
+     *       own main loop.
+     */
+    GMainLoop * event_loop;
+
+    /// Mutex used to synchronize access to context fields.
+    ca_mutex lock;
+
+    /**
+     * Service registration condition variable.
+     *
+     * This condition variable is used to delay service registration
+     * until the thread performing service initialization completes.
+     * Initialization is performed in the same thread that will run
+     * the peripheral's event loop.
+     *
+     * @see @c GMainLoop documentation for further details.
+     */
+    ca_cond condition;
+
+} CAPeripheralContext;
+
+/**
+ * Initialize global state.
+ */
+void CAPeripheralInitialize();
+
+/**
+ * Finalize global state.
+ */
+void CAPeripheralFinalize();
+
+/**
+ * Initialize and start a Linux BLE "peripheral".
+ *
+ * Initialize all Linux BLE "peripheral" state (i.e. a global
+ * @c CAPeripheralContext instance), as well as register the OIC
+ * GATT transport service with BlueZ to begin advertising.
+ *
+ * @param[in] context Base context.
+ *
+ * @return @c CA_STATUS_OK on success.
+ */
+CAResult_t CAPeripheralStart(CALEContext * context);
+
+/**
+ * Stop the Linux BLE "peripheral".
+ *
+ * @return @c CA_STATUS_OK on success.
+ */
+CAResult_t CAPeripheralStop();
+
+
+#endif  /* CA_BLE_LINUX_PERIPHERAL_H */
diff --git a/resource/csdk/connectivity/src/bt_le_adapter/linux/recv.c b/resource/csdk/connectivity/src/bt_le_adapter/linux/recv.c
new file mode 100644 (file)
index 0000000..9cadb89
--- /dev/null
@@ -0,0 +1,64 @@
+/******************************************************************
+ *
+ * Copyright 2015 Intel Corporation All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+#include "recv.h"
+
+#include "caremotehandler.h"
+#include "cafragmentation.h"
+#include "oic_malloc.h"
+#include "oic_string.h"
+
+#include <string.h>
+#include <assert.h>
+
+
+// Logging tag.
+static char const TAG[] = "BLE_RECV";
+
+static CAGattRecvInfo const g_null_info =
+    {
+        .peer = NULL
+    };
+
+void CAGattRecvInfoInitialize(CAGattRecvInfo * info)
+{
+    *info = g_null_info;
+}
+
+void CAGattRecvInfoDestroy(CAGattRecvInfo * info)
+{
+    OICFree(info->peer);
+    *info = g_null_info;
+}
+
+bool CAGattRecv(CAGattRecvInfo * info, char const * data, uint32_t length)
+{
+    uint32_t sent_length = 0;
+
+    ca_mutex_lock(info->context->lock);
+
+    bool const success =
+        info->on_packet_received(info->peer,
+                                 data,
+                                 length,
+                                 &sent_length) == CA_STATUS_OK;
+
+    ca_mutex_unlock(info->context->lock);
+
+    return success && length == sent_length;
+}
diff --git a/resource/csdk/connectivity/src/bt_le_adapter/linux/recv.h b/resource/csdk/connectivity/src/bt_le_adapter/linux/recv.h
new file mode 100644 (file)
index 0000000..a017c5a
--- /dev/null
@@ -0,0 +1,98 @@
+/******************************************************************
+ *
+ * Copyright 2015 Intel Corporation All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+#ifndef CA_BLE_LINUX_RECV_H
+#define CA_BLE_LINUX_RECV_H
+
+#include "context.h"
+
+#include "caleinterface.h"
+
+#include <stdint.h>
+#include <stdlib.h>
+
+
+/**
+ * Information used to keep track of received data fragments.
+ */
+typedef struct _CAGattRecvInfo
+{
+
+    /**
+     * @name Peer Connection-specific Fields
+     *
+     * These fields are valid only as long as the peer is connected.
+     */
+    //@{
+    /// Peer address.
+    char * peer;
+
+    /// Callback invoked upon receiving all data from GATT peer.
+    CABLEDataReceivedCallback on_packet_received;
+
+    /**
+     * Context object containing lock used for synchronized access to
+     * the @c on_packet_received callback since that callback is actually
+     * owned by it.
+     */
+    CALEContext * context;
+    //@}
+
+} CAGattRecvInfo;
+
+/**
+ * Initialize a @c CAGattRecvInfo object.
+ *
+ * @param[in] info Pointer to @c CAGattRecvInfo object being
+ *                 initialized.  No memory is allocated by this
+ *                 function.  The caller is responsible for
+ *                 instantiating the object prior to calling this
+ *                 function.
+ */
+void CAGattRecvInfoInitialize(CAGattRecvInfo * info);
+
+/**
+ * Destroy a @c CAGattRecvInfo object.
+ *
+ * Destruction of @a info involves deallocating and clearing out all
+ * fields, as necessary.
+ *
+ * @param[in] info Pointer to @c CAGattRecvInfo object being
+ *                 destroyed.  Only the @a info fields are finalized.
+ *                 Memory of @a info itself is retained by the
+ *                 caller.
+ */
+void CAGattRecvInfoDestroy(CAGattRecvInfo * info);
+
+/**
+ * Handle data received from GATT a peer.
+ *
+ * @param[in] info        Information required to complete the receive
+ *                        operation.
+ * @param[in] data        Octet array containing received data
+ *                        fragment.
+ * @param[in] length      Length of the @a data array.
+ *
+ * @return @c true on success, @c false otherwise.
+ */
+bool CAGattRecv(CAGattRecvInfo * info,
+                char const * data,
+                uint32_t length);
+
+
+#endif  /* CA_BLE_LINUX_RECV_H */
diff --git a/resource/csdk/connectivity/src/bt_le_adapter/linux/server.c b/resource/csdk/connectivity/src/bt_le_adapter/linux/server.c
new file mode 100644 (file)
index 0000000..828183c
--- /dev/null
@@ -0,0 +1,110 @@
+/******************************************************************
+ *
+ * Copyright 2015 Intel Corporation All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+#include "server.h"
+
+#include "cacommon.h"
+#include "logger.h"
+
+#include <assert.h>
+
+
+// Logging tag.
+static char const TAG[] = "BLE_SERVER";
+
+// ---------------------------------------------------------------------
+//                      GATT Request Handling
+// ---------------------------------------------------------------------
+void CAGattServerHandleRequestData()
+{
+}
+
+// ---------------------------------------------------------------------
+//                      GATT Response Handling
+// ---------------------------------------------------------------------
+/**
+ * Send response data to the GATT client.
+ *
+ * Respone data will be sent to the client through the given response
+ * @a characteristic proxy as a GATT characteristic notification.
+ *
+ * @param[in] characteristic The D-Bus proxy for the response
+ *                           characteristic through which the
+ *                           notification will be sent.
+ * @param[in] data           The byte array to be sent.
+ * @param[in] length         The number of elements in the byte
+ *                           array.
+ */
+static bool CAGattServerSendResponseNotification(
+    GattCharacteristic1 * characteristic,
+    char const * data,
+    size_t length)
+{
+    if (!gatt_characteristic1_get_notifying(characteristic))
+    {
+        OIC_LOG(WARNING,
+                TAG,
+                "Attempt to send response with notifications "
+                "disabled.\n"
+                "Client must enable notifications. "
+                "No response was sent.");
+
+        return false;
+    }
+
+    GVariant * const value =
+        g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE,
+                                  data,
+                                  length,
+                                  sizeof(data[0]));
+
+    /**
+     * Send the response fragment by setting the "Value" property on
+     * the response characteristic, and emitting the
+     * @c org.freedesktop.Dbus.Properties.PropertiesChanged signal,
+     * accordingly.
+     *
+     * @todo Do we need to explicitly emit the @c GObject @c notify or
+     *       @c org.freedesktop.Dbus.Properties.PropertiesChanged
+     *       signal here?
+     */
+    gatt_characteristic1_set_value(characteristic, value);
+
+    return true;
+}
+
+bool CAGattServerSendResponse(void const * method_info,
+                              void const * data,
+                              size_t length)
+{
+    assert(method_info != NULL);
+
+    CAGattResponseInfo const * const info = method_info;
+
+    GattCharacteristic1 * const characteristic =
+        info->characteristic;
+
+    if (!CAGattServerSendResponseNotification(characteristic,
+                                              (char const *) data,
+                                              length))
+    {
+        return false;
+    }
+
+    return true;
+}
diff --git a/resource/csdk/connectivity/src/bt_le_adapter/linux/server.h b/resource/csdk/connectivity/src/bt_le_adapter/linux/server.h
new file mode 100644 (file)
index 0000000..91dcc26
--- /dev/null
@@ -0,0 +1,56 @@
+/******************************************************************
+ *
+ * Copyright 2015 Intel Corporation All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+#ifndef CA_BLE_LINUX_SERVER_H
+#define CA_BLE_LINUX_SERVER_H
+
+#include "bluez-glue.h"
+
+#include <stdbool.h>
+#include <sys/types.h>
+
+/**
+ * Information needed to complete a GATT server response send.
+ */
+typedef struct _CAGattResponseInfo
+{
+    /**
+     * The BlueZ @c org.bluez.GattCharacteristic1 skeleton object
+     * through which data will be sent.
+     */
+    GattCharacteristic1 * const characteristic;
+
+} CAGattResponseInfo;
+
+/**
+ * Send response notification to the GATT client.
+ *
+ * @param[in] method_info Pointer to @c GattResponseInfo object that
+ *                        contains information necessary to complete
+ *                        send of response.
+ * @param[in] data        Octet array of response data to be sent.
+ * @param[in] length      Length of the @a data octet array.
+ *
+ * @see @c CAGattSendMethod() for further details.
+ */
+bool CAGattServerSendResponse(void const * method_info,
+                              void const * data,
+                              size_t length);
+
+
+#endif  /* CA_BLE_LINUX_SERVER_H */
diff --git a/resource/csdk/connectivity/src/bt_le_adapter/linux/service.c b/resource/csdk/connectivity/src/bt_le_adapter/linux/service.c
new file mode 100644 (file)
index 0000000..ef204e5
--- /dev/null
@@ -0,0 +1,264 @@
+/* ****************************************************************
+ *
+ * Copyright 2015 Intel Corporation All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+#include "service.h"
+#include "gatt_dbus.h"
+#include "utils.h"
+#include "bluez.h"
+
+#include "cagattservice.h"
+#include "logger.h"
+
+#include <assert.h>
+
+
+// Logging tag.
+static char const TAG[] = "BLE_SERVICE";
+
+static GVariant * CAGattServiceGetProperties(GattService1 * service)
+{
+    /*
+      Create a variant containing the @c GattService1 properties, of
+      the form @c a{sa{sv}}.
+    */
+
+    /**
+     * Populate the property table, and create the variant to be
+     * embedded in the results of the
+     * @c org.freedesktop.Dbus.ObjectManager.GetManagedObjects()
+     * method call.
+     *
+     * The @c "Device" property is only available on the client side
+     * so we don't bother returning it here.
+     *
+     * @todo Do we care about the @c "Includes" property?
+     *       @c "Includes" isn't implemented by BlueZ as of version
+     *       5.30, so we can leave it out.
+    */
+    CADBusSkeletonProperty const properties[] = {
+        { "UUID",
+          g_variant_new_string(gatt_service1_get_uuid(service)) },
+        { "Primary",
+          g_variant_new_boolean(gatt_service1_get_primary(service)) },
+        { "Characteristics",
+          g_variant_new_objv(
+              gatt_service1_get_characteristics(service),
+              -1) }
+    };
+
+    return
+        CAMakePropertyDictionary(
+            BLUEZ_GATT_SERVICE_INTERFACE,
+            properties,
+            sizeof(properties) / sizeof(properties[0]));
+}
+
+/**
+ * Implementation of the
+ * @c org.freedesktop.DBus.ObjectManager.GetManagedObjects() method
+ * for the @c org.bluez.GattService1 interface.
+ */
+static gboolean CAGattServiceHandleGetManagedObjects(
+    ObjectManager * object,
+    GDBusMethodInvocation * invocation,
+    gpointer user_data)
+{
+    /**
+     * @note Ideally we shouldn't need this implementation, and should
+     *       be able to simply rely GDBusObjectManagerServer instead.
+     *       Unfortunately, BlueZ expects the @c
+     *       org.bluez.GattService1 object to implement the @c
+     *       ObjectManager interface, and both interfaces must rooted
+     *       at the same object path, as well.  That requirement
+     *       prevents us from using @c GDBusObjectManagerServer since
+     *       it won't allow us to export more than interface on a
+     *       given object path.
+     */
+
+    /*
+      Build the object array containing the IoTivity
+      org.bluez.GattService1 hierarchy.
+
+      a{oa{sa{sv}}}
+    */
+    CAGattService * const service = user_data;
+
+    GVariantBuilder builder;
+    g_variant_builder_init(&builder, G_VARIANT_TYPE("a{oa{sa{sv}}}"));
+
+    // Start out with the service itself.
+    g_variant_builder_add(&builder,
+                          "{o@a{sa{sv}}}",
+                          service->object_path,
+                          CAGattServiceGetProperties(service->service));
+
+    /*
+      Add the request characteristic and user description
+      descriptor.
+    */
+    CAGattCharacteristic * const request_chrc =
+        &service->request_characteristic;
+
+    g_variant_builder_add(&builder,
+                          "{o@a{sa{sv}}}",
+                          request_chrc->object_path,
+                          CAGattCharacteristicGetProperties(
+                              request_chrc->characteristic));
+
+    CAGattDescriptor * const request_desc = &request_chrc->descriptor;
+
+    g_variant_builder_add(&builder,
+                          "{o@a{sa{sv}}}",
+                          request_desc->object_path,
+                          CAGattDescriptorGetProperties(
+                              request_desc->descriptor));
+
+    /*
+      Add the response characteristic and user description
+      descriptor.
+    */
+    CAGattCharacteristic * const response_chrc =
+        &service->response_characteristic;
+
+    g_variant_builder_add(&builder,
+                          "{o@a{sa{sv}}}",
+                          response_chrc->object_path,
+                          CAGattCharacteristicGetProperties(
+                              response_chrc->characteristic));
+
+    CAGattDescriptor * const response_desc = &response_chrc->descriptor;
+
+    g_variant_builder_add(&builder,
+                          "{o@a{sa{sv}}}",
+                          response_desc->object_path,
+                          CAGattDescriptorGetProperties(
+                              response_desc->descriptor));
+
+    GVariant * const objects = g_variant_builder_end(&builder);
+
+    object_manager_complete_get_managed_objects(object,
+                                                invocation,
+                                                objects);
+
+    return TRUE;
+}
+
+bool CAGattServiceInitialize(CAGattService * s,
+                             CALEContext * context,
+                             char const * hci_name)
+{
+    assert(s != NULL);
+    assert(context != NULL);
+    assert(hci_name != NULL);
+
+    // Path of the form /org/iotivity/gatt/hci0/service0.
+    s->object_path =
+        g_strdup_printf("%s/%s/%s",
+                        CA_GATT_SERVICE_ROOT_PATH,
+                        hci_name,
+                        CA_GATT_SERVICE_PATH);
+
+    assert(g_variant_is_object_path(s->object_path));
+
+    s->object_manager = object_manager_skeleton_new();
+    s->service = gatt_service1_skeleton_new();
+
+    gatt_service1_set_uuid(s->service, CA_GATT_SERVICE_UUID);
+    gatt_service1_set_primary(s->service, TRUE);
+
+    if (!CAGattRequestCharacteristicInitialize(s, context)
+        || !CAGattResponseCharacteristicInitialize(s, context))
+    {
+        CAGattServiceDestroy(s);
+        return false;
+    }
+
+    /*
+      The characteristic object paths are not fixed at compile-time.
+      Retrieve the object paths that were set at run-time.
+    */
+    char const * characteristic_paths[] = {
+        s->request_characteristic.object_path,
+        s->response_characteristic.object_path,
+        NULL
+    };
+
+    gatt_service1_set_characteristics(s->service, characteristic_paths);
+
+    /*
+      Set the org.freedesktop.DBus.ObjectManager.GetManagedObjects()
+      handler for our BlueZ GATT service.
+    */
+    g_signal_connect(
+        s->object_manager,
+        "handle-get-managed-objects",
+        G_CALLBACK(CAGattServiceHandleGetManagedObjects),
+        s);
+
+    /*
+      BlueZ expects both the org.freedesktop.DBus.ObjectManager and
+      org.bluez.GattService1 interfaces to be rooted at the same
+      object path.  Export the service and object manager interface
+      skeletons with the same object path.
+     */
+    GError * error = NULL;
+    if (!g_dbus_interface_skeleton_export(
+            G_DBUS_INTERFACE_SKELETON(s->object_manager),
+            context->connection,
+            s->object_path,
+            &error)
+        || !g_dbus_interface_skeleton_export(
+            G_DBUS_INTERFACE_SKELETON(s->service),
+            context->connection,
+            s->object_path,
+            &error))
+    {
+        OIC_LOG_V(ERROR,
+                  TAG,
+                  "Unable to export GATT service interfaces: %s",
+                  error->message);
+
+        return false;
+    }
+
+    return true;
+}
+
+void CAGattServiceDestroy(CAGattService * s)
+{
+    /**
+     * @todo If necessary, emit the
+     *       @c org.freedesktop.DBus.ObjectManager.InterfacesRemoved
+     *       signal via @c object_manager_emit_interfaces_removed() if
+     *       the CA GATT service objects were removed from the
+     *       @c ObjectManager.
+     */
+
+    assert(s != NULL);  // As designed, s is always non-NULL.
+
+    g_clear_object(&s->gatt_manager);
+
+    CAGattCharacteristicDestroy(&s->response_characteristic);
+    CAGattCharacteristicDestroy(&s->request_characteristic);
+
+    g_clear_object(&s->service);
+    g_clear_object(&s->object_manager);
+
+    g_free(s->object_path);
+    s->object_path = NULL;
+}
diff --git a/resource/csdk/connectivity/src/bt_le_adapter/linux/service.h b/resource/csdk/connectivity/src/bt_le_adapter/linux/service.h
new file mode 100644 (file)
index 0000000..2cfbc3e
--- /dev/null
@@ -0,0 +1,93 @@
+/******************************************************************
+ *
+ * Copyright 2015 Intel Corporation All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+#ifndef CA_BLE_LINUX_SERVICE_H
+#define CA_BLE_LINUX_SERVICE_H
+
+#include "bluez-glue.h"
+#include "object_manager-glue.h"
+#include "characteristic.h"
+
+
+/**
+ * GATT Service Information
+ */
+typedef struct CAGattService
+{
+    /// D-Bus object path for the GattService1 object.
+    char * object_path;
+
+    /**
+     * OIC GATT service object_manager D-Bus interface skeleton
+     * object.
+     */
+    ObjectManager * object_manager;
+
+    /// OIC GATT service D-Bus interface skeleton object.
+    GattService1 * service;
+
+    /// OIC GATT request characteristic information.
+    CAGattCharacteristic request_characteristic;
+
+    /// OIC GATT response characteristic information.
+    CAGattCharacteristic response_characteristic;
+
+    /**
+     * org.bluez.GattManager1 object with which the service is
+     * registered.
+     */
+    GDBusProxy * gatt_manager;
+
+} CAGattService;
+
+/**
+ * Initialize GATT service fields.
+ *
+ * This function initializes the @c CAGattService object fields.
+ *
+ * @param[out] service  GATT service information to be initialized.
+ * @param[in]  context  Object containing the D-Bus connection to the
+ *                      bus on which the service will be exported.
+ * @param[in]  hci_name Name of the bluetooth adapter installed on the
+ *                      system, e.g. @c "hci0".
+ *
+ * @return @c true on success, @c false otherwise.
+ *
+ * @note This function does not allocate the @a service object
+ *       itself.  The caller is responsible for allocating that
+ *       memory.
+ */
+bool CAGattServiceInitialize(CAGattService * service,
+                             CALEContext * context,
+                             char const * hci_name);
+
+/**
+ * Destroy GATT service fields.
+ *
+ * This function finalizes the @c CAGattService object fields.
+ *
+ * @param[in] service GATT service information to be finalized.
+ *
+ * @note This function does not deallocate the @a service object
+ *       itself.  The caller is responsible for deallocating that
+ *       memory.
+ */
+void CAGattServiceDestroy(CAGattService * service);
+
+
+#endif  // CA_BLE_LINUX_SERVICE_H
diff --git a/resource/csdk/connectivity/src/bt_le_adapter/linux/utils.c b/resource/csdk/connectivity/src/bt_le_adapter/linux/utils.c
new file mode 100644 (file)
index 0000000..40708f1
--- /dev/null
@@ -0,0 +1,245 @@
+/******************************************************************
+ *
+ * Copyright 2015 Intel Corporation All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+#include "utils.h"
+#include "bluez.h"
+
+#include "logger.h"
+
+#include <assert.h>
+
+
+// Logging tag.
+static char const TAG[] = "BLE_UTILS";
+
+bool CAGetBlueZManagedObjectProxies(GList ** proxies,
+                                    char const * interface,
+                                    CALEContext * context,
+                                    CALEProxyFilter filter)
+{
+    assert(interface != NULL);
+    assert(proxies != NULL);
+    assert(context != NULL);
+
+    /*
+      Failure is only reported if an error occurred.  An empty
+      returned list, for example, is not an error since it could
+      be updated at a later time when handling D-Bus signals related
+      to the given interface.
+    */
+    bool success = true;
+
+    ca_mutex_lock(context->lock);
+
+    if (context->objects == NULL)
+    {
+        ca_mutex_unlock(context->lock);
+        return success;
+    }
+
+    /*
+      Iterate over the objects to find those that implement the given
+      BlueZ interface and them to the given list.
+    */
+    for (GList * l = context->objects; l != NULL; l = l->next)
+    {
+        GDBusProxy * const proxy =
+            G_DBUS_PROXY(g_dbus_object_get_interface(
+                G_DBUS_OBJECT(l->data),
+                interface));
+
+        if (proxy != NULL)
+        {
+            if (filter == NULL || filter(proxy))
+            {
+                /*
+                  Add the object information to the list.
+
+                  Note that we prepend instead of append in this case
+                  since it is more efficient to do so for linked lists
+                  like the one used here.
+                */
+                *proxies = g_list_prepend(*proxies, proxy);
+            }
+            else
+            {
+                // Rejected by filter.
+                g_object_unref(proxy);
+            }
+        }
+    }
+
+    ca_mutex_unlock(context->lock);
+
+    return success;
+}
+
+GDBusProxy * CAGetBlueZInterfaceProxy(GVariant * tuple,
+                                      char const * interface,
+                                      GDBusObjectManager * object_manager)
+{
+    /*
+      The tuple is of the form "(oa{sv})".
+
+      The object path is first tuple element, and the properties the
+      second.  Check if the given interface exists in the properties.
+      Return the object path (the dictionary item key) of the found
+      property (the dictionary item value).
+    */
+    GVariant * const props = g_variant_get_child_value(tuple, 1);
+
+    GVariant * const value =
+        g_variant_lookup_value(props, interface, NULL);
+
+    GDBusProxy * proxy = NULL;
+
+    if (value != NULL)
+    {
+        /*
+          A set of properties corresponding to the given D-Bus
+          interface was found.  Create a proxy to the object that
+          implements that interface.  Store that proxy, the D-Bus
+          object path and properties in the given list.
+        */
+
+        gchar const * path = NULL;
+
+        // The object path is the first tuple element.
+        g_variant_get_child(tuple, 0, "&o", &path);
+
+        /*
+          Create a proxy to the object that implements the given
+          interface.
+        */
+        proxy =
+            G_DBUS_PROXY(
+                g_dbus_object_manager_get_interface(object_manager,
+                                                    path,
+                                                    interface));
+
+        g_variant_unref(value);
+    }
+
+    g_variant_unref(props);
+
+    return proxy;
+}
+
+bool CASetBlueZObjectProperty(GDBusProxy * proxy,
+                              char const * interface,
+                              char const * property,
+                              GVariant * value)
+{
+    /*
+      Only make the D-Bus call to set the property if we need to
+      change it.
+     */
+    GVariant * const cached_value =
+        g_dbus_proxy_get_cached_property(proxy, property);
+
+    if (cached_value != NULL)
+    {
+        bool const already_set = g_variant_equal(cached_value, value);
+
+        g_variant_unref(cached_value);
+
+        if (already_set)
+        {
+            /*
+              Ownership of the value GVariant was transferred when
+              this function was called.  It won't be used since the
+              property with the same value is already set, so release
+              our reference to it.
+            */
+            g_variant_unref(value);
+
+            return true;
+        }
+    }
+
+    /*
+      Either the property wasn't previously set or it is being
+      changed.  Set property on the given interface.
+    */
+    GError * error = NULL;
+
+    GVariant * const ret =
+        g_dbus_proxy_call_sync(proxy,
+                               "org.freedesktop.DBus.Properties.Set",
+                               g_variant_new("(ssv)",
+                                             interface,
+                                             property,
+                                             value),
+                               G_DBUS_CALL_FLAGS_NONE,
+                               -1,    // timeout (default == -1),
+                               NULL,  // cancellable
+                               &error);
+
+    if (ret == NULL)
+    {
+        OIC_LOG_V(ERROR,
+                  TAG,
+                  "Attempt to set \"%s\" property for "
+                  "\"%s\" interface failed.: %s",
+                  error->message);
+
+        g_error_free(error);
+
+        return false;
+    }
+
+    g_variant_unref(ret);
+
+    return true;
+}
+
+GVariant * CAMakePropertyDictionary(
+    char const * interface_name,
+    CADBusSkeletonProperty const * properties,
+    size_t count)
+{
+    /*
+      Create a variant containing the proxy properties, of the form
+      a{sa{sv}}.
+    */
+
+    GVariantBuilder builder;
+
+    // Create the inner (property) dictionary.
+    g_variant_builder_init(&builder, G_VARIANT_TYPE("a{sv}"));
+
+    CADBusSkeletonProperty const * const end =
+        properties + count;
+
+    for (CADBusSkeletonProperty const * prop = properties;
+         prop != end;
+         ++prop)
+    {
+        g_variant_builder_add(&builder, "{sv}", prop->name, prop->value);
+    }
+
+    GVariant * const props = g_variant_builder_end(&builder);
+
+    // Now create the dictionary with the above property dictionary
+    // embedded.
+    g_variant_builder_init(&builder, G_VARIANT_TYPE("a{sa{sv}}"));
+
+    g_variant_builder_add(&builder, "{s@a{sv}}", interface_name, props);
+
+    return g_variant_builder_end(&builder);
+}
diff --git a/resource/csdk/connectivity/src/bt_le_adapter/linux/utils.h b/resource/csdk/connectivity/src/bt_le_adapter/linux/utils.h
new file mode 100644 (file)
index 0000000..04292b6
--- /dev/null
@@ -0,0 +1,147 @@
+/******************************************************************
+ *
+ * Copyright 2015 Intel Corporation All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+#ifndef CA_BLE_LINUX_UTILS_H
+#define CA_BLE_LINUX_UTILS_H
+
+#include "context.h"
+
+
+/**
+ * Proxy retrieval filter function type.
+ *
+ * A function that implements this interface may be passed to
+ * @c CAGetBlueZManagedObjectProxies() to filter proxies to be added
+ * to the returned list.
+ *
+ * @return @c true if the proxy should be added to the proxy list,
+ *         @c false otherwise.
+ */
+typedef bool(*CALEProxyFilter)(GDBusProxy * proxy);
+
+/**
+ * Get information for all BlueZ managed objects with a given
+ * interface.
+ *
+ * @param[out] proxies   List containing @a proxies (@c GDBusProxy)
+ *                       for all found BlueZ objects that match the
+ *                       given D-Bus @a interface.
+ * @param[in]  interface D-Bus interface of BlueZ object for which a
+ *                       proxy will be created.
+ * @param[in]  context   BLE Linux adapter context.
+ * @param[in]  filter    Filter function used to determine whether or
+ *                       not a proxy retrieved from the BlueZ
+ *                       @c ObjectManager should be added to the
+ *                       returned @a proxies list.
+ *
+ * @return @c true if objects were found.
+ */
+bool CAGetBlueZManagedObjectProxies(GList ** proxies,
+                                    char const * interface,
+                                    CALEContext * context,
+                                    CALEProxyFilter filter);
+
+
+/**
+ * Get the proxy to a object that implements the given D-Bus
+ * @a interface.
+ *
+ * @param[in] tuple      A D-Bus tuple that contains the D-Bus object
+ *                       path and corresponding dictionary of
+ *                       properties, i.e. with the format specifier
+ *                       @c "(oa{sv})".
+ * @param[in] interface  The D-Bus interface in which we're
+ *                       interested.  A @c GDBusProxy object will be
+ *                       create using the properties found in the
+ *                       dictionary item whose key matches this
+ *                       interface name.
+ * @param[in] manager    The D-Bus object manager that contains the
+ *                       information about the object in question.
+ */
+GDBusProxy * CAGetBlueZInterfaceProxy(GVariant * tuple,
+                                      char const * interface,
+                                      GDBusObjectManager * object_manager);
+
+/**
+ * Set @a property on BlueZ object to given @a value.
+ *
+ * Using the @c org.freedesktop.DBus.Properties.Set() method
+ * implemented by BlueZ objects, set the desired @a property on the
+ * object pointed to by @a proxy to the given @a value.
+ *
+ * @param[in] proxy     D-Bus proxy to the BlueZ object.
+ * @param[in] interface Interface name of the object on which the
+ *                      property is being set.
+ * @param[in] property  Property name.
+ * @param[in] value     Property value.  Ownership is transferred from
+ *                      the caller.
+ */
+bool CASetBlueZObjectProperty(GDBusProxy * proxy,
+                              char const * interface,
+                              char const * property,
+                              GVariant * value);
+
+/**
+ * D-Bus skeleton propery name/value pair.
+ *
+ * This name value pair will be used when constructing the property
+ * dictionary embedded in
+ * @c org.freedesktop.DBus.ObjectManager.GetManagedObjects() results.
+ */
+typedef struct _CADBusSkeletonProperty
+{
+    /// Property name.
+    char const * const name;
+
+    /**
+     * Property value.
+     *
+     * @c Ownership is transferred to the function this variant passed
+     * to.
+     */
+    GVariant * const value;
+} CADBusSkeletonProperty;
+
+/**
+ * Construct property dictionary suitable for place in ObjectManager
+ * results.
+ *
+ * @param[in] interface_name The name of the interface to which the
+ *                           properties correspond.
+ * @param[in] properties     Array of property name/value pairs.
+ *                           Ownership of the value variant will be
+ *                           transferred to this function.
+ * @param[in] count          Number of elements in the @a properties
+ *                           array.
+ *
+ * @return A variant of the form a{sa{sv}}, suitable for use in the
+ *         results of
+ *         @c org.freedesktop.DBus.ObjectManager.GetManagedObjects()
+ *         or @c org.freedesktop.DBus.Properties.GetAll() method
+ *         implementations.
+ *
+ * @note Ownership of the returned @c GVariant is transferred to the
+ *       caller.
+ */
+GVariant * CAMakePropertyDictionary(
+    char const * interface_name,
+    CADBusSkeletonProperty const * properties,
+    size_t count);
+
+
+#endif  // CA_BLE_LINUX_UTILS_H
index 1f02fd3..ffebf4d 100644 (file)
@@ -35,6 +35,7 @@
 #include "caqueueingthread.h"
 #include "caadapterutils.h"
 #include "cafragmentation.h"
+#include "cagattservice.h"
 #include "oic_string.h"
 #include "oic_malloc.h"
 
 #define TZ_BLE_CLIENT_TAG "TZ_BLE_GATT_CLIENT"
 
 /**
- * Its the constant value for characteristic descriptor from spec.
- */
-#define BLE_UUID_DESCRIPTOR_CLIENT_CHAR_CONFIG "2902"
-
-/**
- * This contains the list of OIC services a client connect tot.
+ * @var g_bLEServiceList
+ * @brief This contains the list of OIC services a client connect to.
  */
 static BLEServiceList *g_bLEServiceList = NULL;
 
@@ -101,7 +98,7 @@ static ca_mutex g_bleClientThreadPoolMutex = NULL;
  * Maintains the callback to be notified on receival of network packets
  *    from other BLE devices
  */
-static CABLEClientDataReceivedCallback g_bleClientDataReceivedCallback = NULL;
+static CABLEDataReceivedCallback g_bleClientDataReceivedCallback = NULL;
 
 /**
  * callback to update the error to le adapter
@@ -152,8 +149,8 @@ void CABleGattCharacteristicChangedCb(bt_gatt_attribute_h characteristic,
 
     ca_mutex_lock(g_bleServerBDAddressMutex);
     uint32_t sentLength = 0;
-    g_bleClientDataReceivedCallback(g_remoteAddress, OIC_BLE_SERVICE_ID,
-                                     value, valueLen, &sentLength);
+    g_bleClientDataReceivedCallback(g_remoteAddress, value, valueLen,
+                                    &sentLength);
 
     OIC_LOG_V(DEBUG, TZ_BLE_CLIENT_TAG, "Sent data Length is %d", sentLength);
     ca_mutex_unlock(g_bleServerBDAddressMutex);
@@ -262,7 +259,7 @@ bool CABleGattCharacteristicsDiscoveredCb(int result,
     OIC_LOG_V(DEBUG, TZ_BLE_CLIENT_TAG, "New Characteristics[%s] of uuid[%s] is obtained",
               (char *)characteristic, uuid);
 
-    if(0 == strcasecmp(uuid, CA_BLE_READ_CHAR_UUID)) // Server will read on this characterisctics
+    if(0 == strcasecmp(uuid, CA_GATT_RESPONSE_CHRC_UUID)) // Server will read on this characterisctics
     {
         OIC_LOG(DEBUG, TZ_BLE_CLIENT_TAG , "Read characteristics is obtained");
         OICFree(uuid);
@@ -314,7 +311,7 @@ bool CABleGattCharacteristicsDiscoveredCb(int result,
         }
         ca_mutex_unlock(g_bleClientThreadPoolMutex);
     }
-    else if (0 == strcasecmp(uuid, CA_BLE_WRITE_CHAR_UUID)) // Server will write on this characteristics.
+    else if (0 == strcasecmp(uuid, CA_GATT_REQUEST_CHRC_UUID)) // Server will write on this characteristics.
     {
         OICFree(uuid);
         OIC_LOG(DEBUG, TZ_BLE_CLIENT_TAG , "Write characteristics is obtained");
@@ -634,7 +631,7 @@ void CASetLEClientThreadPoolHandle(ca_thread_pool_t handle)
     OIC_LOG(DEBUG, TZ_BLE_CLIENT_TAG, "OUT");
 }
 
-void CASetLEReqRespClientCallback(CABLEClientDataReceivedCallback callback)
+void CASetLEReqRespClientCallback(CABLEDataReceivedCallback callback)
 {
     OIC_LOG(DEBUG, TZ_BLE_CLIENT_TAG, "IN");
 
@@ -1352,9 +1349,9 @@ CAResult_t CASetCharacteristicDescriptorValue(stGattCharDescriptor_t *stGattChar
     OIC_LOG_V(DEBUG, TZ_BLE_CLIENT_TAG, "desc x3 [%x]", stGattCharDescInfo->desc[3]);
 
 
-    OIC_LOG_V(DEBUG, TZ_BLE_CLIENT_TAG, "BLE_UUID_DESCRIPTOR_CLIENT_CHAR_CONFIG strUUID is [%s]",
+    OIC_LOG_V(DEBUG, TZ_BLE_CLIENT_TAG, "CA_GATT_CONFIGURATION_DESC_UUID strUUID is [%s]",
               strUUID);
-    //if (!strncmp(strUUID, BLE_UUID_DESCRIPTOR_CLIENT_CHAR_CONFIG, 2))
+    //if (!strncmp(strUUID, CA_GATT_CONFIGURATION_DESC_UUID, 2))
     {
         OIC_LOG(DEBUG, TZ_BLE_CLIENT_TAG, "setting notification/indication for descriptor");
 
@@ -1377,8 +1374,8 @@ CAResult_t CASetCharacteristicDescriptorValue(stGattCharDescriptor_t *stGattChar
 }
 
 CAResult_t  CAUpdateCharacteristicsToGattServer(const char *remoteAddress,
-        const char  *data, const uint32_t dataLen,
-        CALETransferType_t type, const int32_t position)
+        const char  *data, uint32_t dataLen,
+        CALETransferType_t type, int32_t position)
 {
     OIC_LOG(DEBUG, TZ_BLE_CLIENT_TAG, "IN");
 
index 790a079..6d54736 100644 (file)
@@ -125,6 +125,13 @@ CAResult_t CAInitializeLEAdapter()
     return CA_STATUS_OK;
 }
 
+CAResult_t CAStartLEAdapter()
+{
+    // Nothing to do.
+
+    return CA_STATUS_OK;
+}
+
 CAResult_t CAGetLEAdapterState()
 {
     OIC_LOG(DEBUG, TZ_LE_NWK_MONITOR_TAG, "IN");
index 98e709c..88e365a 100644 (file)
@@ -31,6 +31,7 @@
 #include "caqueueingthread.h"
 #include "caadapterutils.h"
 #include "cafragmentation.h"
+#include "cagattservice.h"
 #include "cableutil.h"
 #include "oic_string.h"
 #include "oic_malloc.h"
@@ -76,7 +77,7 @@ static bt_advertiser_h g_hAdvertiser = NULL;
  * @brief  Maintains the callback to be notified on receival of network packets from other
  *           BLE devices
  */
-static CABLEServerDataReceivedCallback g_bleServerDataReceivedCallback = NULL;
+static CABLEDataReceivedCallback g_bleServerDataReceivedCallback = NULL;
 
 /**
  * @var g_serverErrorCallback
@@ -207,7 +208,7 @@ void CAStartBleGattServerThread(void *data)
 
     sleep(5); // Sleep is must because of the platform issue.
 
-    char *serviceUUID = OIC_BLE_SERVICE_ID;
+    char *serviceUUID = CA_GATT_SERVICE_UUID;
 
     ret  = CAAddNewBleServiceInGattServer(serviceUUID);
     if (CA_STATUS_OK != ret )
@@ -218,7 +219,7 @@ void CAStartBleGattServerThread(void *data)
         return;
     }
 
-    char *charReadUUID = CA_BLE_READ_CHAR_UUID;
+    char *charReadUUID = CA_GATT_RESPONSE_CHRC_UUID;
     char charReadValue[] = {33, 44, 55, 66}; // These are initial random values
 
     ret = CAAddNewCharacteristicsToGattServer(g_gattSvcPath, charReadUUID, charReadValue,
@@ -231,7 +232,7 @@ void CAStartBleGattServerThread(void *data)
         return;
     }
 
-    char *charWriteUUID = CA_BLE_WRITE_CHAR_UUID;
+    char *charWriteUUID = CA_GATT_REQUEST_CHRC_UUID;
     char charWriteValue[] = {33, 44, 55, 66}; // These are initial random values
 
 
@@ -610,8 +611,8 @@ void CABleGattRemoteCharacteristicWriteCb(char *charPath,
 
     OIC_LOG(DEBUG, TZ_BLE_SERVER_TAG, "Sending data up !");
     uint32_t sentLength = 0;
-    g_bleServerDataReceivedCallback(remoteAddress, OIC_BLE_SERVICE_ID,
-                                     data, charValueLen, &sentLength);
+    g_bleServerDataReceivedCallback(remoteAddress, data, charValueLen,
+                                    &sentLength);
 
     ca_mutex_unlock(g_bleReqRespCbMutex);
 
@@ -705,8 +706,9 @@ CAResult_t CARemoveCharacteristicsFromGattServer(const char *charPath)
     return CA_STATUS_OK;
 }
 
-CAResult_t CAUpdateCharacteristicsToGattClient(const char* address, const char *charValue,
-        const uint32_t charValueLen)
+CAResult_t CAUpdateCharacteristicsToGattClient(const char *address,
+                                               const char *charValue,
+                                               uint32_t charValueLen)
 {
     OIC_LOG(DEBUG, TZ_BLE_SERVER_TAG, "IN");
 
@@ -800,7 +802,7 @@ CAResult_t CAUpdateCharacteristicsToAllGattClients(const char *charValue, uint32
     return CA_STATUS_OK;
 }
 
-void CASetLEReqRespServerCallback(CABLEServerDataReceivedCallback callback)
+void CASetLEReqRespServerCallback(CABLEDataReceivedCallback callback)
 {
     OIC_LOG(DEBUG, TZ_BLE_SERVER_TAG, "IN");
 
index 1f8da50..a2e4ff6 100644 (file)
@@ -30,6 +30,7 @@
 
 
 #include "caadapterutils.h"
+#include "cagattservice.h"
 #include "oic_string.h"
 #include "oic_malloc.h"
 
@@ -329,7 +330,7 @@ CAResult_t CAVerifyOICServiceByUUID(const char* serviceUUID)
 
     VERIFY_NON_NULL(serviceUUID, TZ_BLE_CLIENT_UTIL_TAG, "Param serviceHandle is NULL");
 
-    if (strcasecmp(serviceUUID, OIC_BLE_SERVICE_ID) != 0)
+    if (strcasecmp(serviceUUID, CA_GATT_SERVICE_UUID) != 0)
     {
         OIC_LOG(ERROR, TZ_BLE_CLIENT_UTIL_TAG, "It is not OIC service!");
         return CA_STATUS_FAILED;
@@ -353,7 +354,7 @@ CAResult_t CAVerifyOICServiceByServiceHandle(bt_gatt_attribute_h serviceHandle)
         return CA_STATUS_FAILED;
     }
 
-    if (strcasecmp(uuid, OIC_BLE_SERVICE_ID) != 0)
+    if (strcasecmp(uuid, CA_GATT_SERVICE_UUID) != 0)
     {
         OIC_LOG(ERROR, TZ_BLE_CLIENT_UTIL_TAG, "It is not OIC service!");
         OICFree(uuid);
index cfa63b1..a4847c7 100644 (file)
@@ -91,21 +91,6 @@ typedef struct gattCharDescriptor
     int total;                          /**< The total number of descriptor in a characteristic */
 } stGattCharDescriptor_t;
 
-#define OIC_BLE_SERVICE_ID "ADE3D529-C784-4F63-A987-EB69F70EE816"
-///TODO: OIC_BLE_SERVICE_ID  will be generated by invoking API in future.
-
-/**
- * @def CA_BLE_READ_CHAR_UUID
- * @brief UUID of read characteristic. This UUID is common across all platform for LE transport.
- */
-#define CA_BLE_READ_CHAR_UUID "E9241982-4580-42C4-8831-95048216B256"
-
-/**
- * @def CA_BLE_WRITE_CHAR_UUID
- * @brief UUID of write characteristic. This UUID is common across all platform for LE transport.
- */
-#define CA_BLE_WRITE_CHAR_UUID "AD7B334F-4637-4B86-90B6-9D787F03D218"
-
 /**
  * @brief  Used to increment the registered service count.
  * @return NONE
index 0d9f023..5ec0bad 100644 (file)
@@ -48,6 +48,11 @@ def run_test(env, xml_file, test):
         # Valgrind run.
         valgrind_environment = ''
 
+        # GLib uses a custom memory allocation scheme that can
+        # sometimes confuse Valgrind.  Configure GLib to be Valgrind
+        # friendly.
+        valgrind_environment += 'G_DEBUG=gc-friendly G_SLICE=always-malloc'
+
         # Valgrind suppressions file.
         suppression_file = env.File('#tools/valgrind/iotivity.supp').srcnode().path
 
index bc2289e..474bb6b 100644 (file)
 # limitations under the License.
 # ------------------------------------------------------------------------
 
+# ************************************************************************
 # This file contains Valgrind suppressions.  It is meant to make
 # Valgrind ignore memory violations that are out of the control of
 # IoTivity developers.  Do NOT abuse this file by adding suppressions
 # for memory violations that can be addressed in IoTivity itself.
+# ************************************************************************
+
+# ************************************************************************
+# GLib related suppressions
+#
+# These suppressions hide "possibly lost" leak diagnostics from
+# Valgrind that occur from running simple  code like the following:
+#     GError * error = NULL;
+#     GDBusConnection * const connection =
+#         g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
+#     g_object_unref(connection);
+# ************************************************************************
+
+# gdbus-codegen generated code
+{
+   gdbus-codegen/*-skeleton-new
+   Memcheck:Leak
+   ...
+   fun:*_skeleton_new
+}
+# GLib >= 2.44.1
+{
+   glib/gobject-init-ctor
+   Memcheck:Leak
+   ...
+   fun:gobject_init_ctor
+}
+{
+   glib/g-dbus-auth-run-client
+   Memcheck:Leak
+   ...
+   fun:_g_dbus_auth_run_client
+}
+{
+   glib/g-main-context-iterate-
+   Memcheck:Leak
+   ...
+   fun:g_main_context_iterate.*
+}
+{
+   glib/g-main-context-dispatch
+   Memcheck:Leak
+   ...
+   fun:g_main_context_dispatch
+}
+{
+   glib/g-bus-get-sync
+   Memcheck:Leak
+   ...
+   fun:g_bus_get_sync
+}
+{
+   glib/get-uninitialized-connection
+   Memcheck:Leak
+   ...
+   fun:get_uninitialized_connection
+}
+{
+   glib/g-dbus-address-get-stream-sync
+   Memcheck:Leak
+   ...
+   fun:g_dbus_address_get_stream_sync
+}
+{
+   glib/g-type-register-static-simple
+   Memcheck:Leak
+   ...
+   fun:g_type_register_static_simple
+}
+{
+   glib/g-type-add-interface-static
+   Memcheck:Leak
+   ...
+   fun:g_type_add_interface_static
+}
+{
+   glib/complete-in-idle-cb
+   Memcheck:Leak
+   ...
+   fun:complete_in_idle_cb
+}
+{
+   glib/g-dbus-address-try-connect-one
+   Memcheck:Leak
+   ...
+   fun:g_dbus_address_try_connect_one
+}
+{
+   glib/g-initable-new
+   Memcheck:Leak
+   ...
+   fun:g_initable_new
+}
+# GLib < 2.36
+{
+   glib/g-type-register-fundamental
+   Memcheck:Leak
+   ...
+   fun:g_type_register_fundamental
+}
+{
+   glib/g-type-register-static
+   Memcheck:Leak
+   ...
+   fun:g_type_register_static
+}
+{
+   glib/g-malloc0
+   Memcheck:Leak
+   ...
+   fun:g_malloc0
+   obj:/usr/lib/*/libgobject-2.0*.so.*
+}
+# ************************************************************************