Update snapshot(2017-11-14)
[platform/upstream/iotivity.git] / resource / csdk / connectivity / src / cainterfacecontroller.c
old mode 100644 (file)
new mode 100755 (executable)
index 0e06e6b..c892289
 #include "cainterfacecontroller.h"
 #include "caedradapter.h"
 #include "caleadapter.h"
+#include "canfcadapter.h"
 #include "caremotehandler.h"
 #include "cathreadpool.h"
 #include "caipadapter.h"
 #include "cainterface.h"
+#include "caipinterface.h"
+#include <coap/utlist.h>
+#include "octhread.h"
 
 #ifdef RA_ADAPTER
 #include "caraadapter.h"
 #include "catcpadapter.h"
 #endif
 
-#define TAG "CA_INTRFC_CNTRLR"
+#if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
+#include "ca_adapter_net_ssl.h"
+#endif
+
+#define TAG "OIC_CA_INF_CTR"
 
 #define CA_MEMORY_ALLOC_CHECK(arg) {if (arg == NULL) \
     {OIC_LOG(ERROR, TAG, "memory error");goto memory_error_exit;} }
 
-#ifdef TCP_ADAPTER
-#define CA_TRANSPORT_TYPE_NUM   5
-#elif RA_ADAPTER
-#define CA_TRANSPORT_TYPE_NUM   4
-#else
-#define CA_TRANSPORT_TYPE_NUM   3
-#endif
+static CAConnectivityHandler_t *g_adapterHandler = NULL;
 
-static CAConnectivityHandler_t g_adapterHandler[CA_TRANSPORT_TYPE_NUM] = {};
+static uint32_t g_numberOfAdapters = 0;
 
 static CANetworkPacketReceivedCallback g_networkPacketReceivedCallback = NULL;
 
-static CANetworkChangeCallback g_networkChangeCallback = NULL;
-
 static CAErrorHandleCallback g_errorHandleCallback = NULL;
 
-static int CAGetAdapterIndex(CATransportAdapter_t cType)
-{
-    switch (cType)
-    {
-        case CA_ADAPTER_IP:
-            return 0;
-        case CA_ADAPTER_GATT_BTLE:
-            return 1;
-        case CA_ADAPTER_RFCOMM_BTEDR:
-            return 2;
+static struct CANetworkCallback_t * g_networkChangeCallbackList = NULL;
 
-#ifdef RA_ADAPTER
-        case CA_ADAPTER_REMOTE_ACCESS:
-            return 3;
-#endif
+/**
+ * Mutex to synchronize network change list.
+ */
+static oc_mutex g_mutexNetCallbackList = NULL;
 
-#ifdef TCP_ADAPTER
-        case CA_ADAPTER_TCP:
-            return 4;
-#endif
+/**
+ * network callback structure is handling
+ * for adapter state changed and connection state changed event.
+ */
+typedef struct CANetworkCallback_t {
+
+    /** Linked list; for multiple callback list.*/
+    struct CANetworkCallback_t * next;
+
+    /** Adapter state changed event callback. */
+    CAAdapterStateChangedCB adapter;
+
+    /** Connection state changed event callback. */
+    CAConnectionStateChangedCB conn;
 
-        default:
-            break;
+} CANetworkCallback_t;
+
+static int CAGetAdapterIndex(CATransportAdapter_t cType)
+{
+    for (uint32_t index=0 ; index < g_numberOfAdapters ; index++)
+    {
+        if (cType == g_adapterHandler[index].cType )
+         {
+             return index;
+         }
     }
+    OIC_LOG_V(ERROR, TAG, "adapter info [%d]", g_numberOfAdapters);
     return -1;
 }
 
-static void CARegisterCallback(CAConnectivityHandler_t handler, CATransportAdapter_t cType)
+static void CARegisterCallback(CAConnectivityHandler_t handler)
 {
-    OIC_LOG(DEBUG, TAG, "IN");
-
-    if(handler.startAdapter == NULL ||
+    if (handler.startAdapter == NULL ||
         handler.startListenServer == NULL ||
+        handler.stopListenServer == NULL ||
         handler.startDiscoveryServer == NULL ||
         handler.sendData == NULL ||
         handler.sendDataToAll == NULL ||
@@ -108,19 +117,100 @@ static void CARegisterCallback(CAConnectivityHandler_t handler, CATransportAdapt
         OIC_LOG(ERROR, TAG, "connectivity handler is not enough to be used!");
         return;
     }
+    uint32_t numberofAdapters = g_numberOfAdapters + 1;
+    CAConnectivityHandler_t *adapterHandler = OICRealloc(g_adapterHandler,
+                                   (numberofAdapters) * sizeof(*adapterHandler));
+    if (NULL == adapterHandler)
+    {
+        OIC_LOG(ERROR, TAG, "Memory allocation failed during registration");
+        return;
+    }
+    g_adapterHandler = adapterHandler;
+    g_numberOfAdapters = numberofAdapters;
+    g_adapterHandler[g_numberOfAdapters-1] = handler;
 
-    int index = CAGetAdapterIndex(cType);
+    OIC_LOG_V(DEBUG, TAG, "%d type adapter, register complete!", handler.cType);
+}
 
-    if (index == -1)
+/**
+ * Add a network callback from caller to the network callback list
+ *
+ * @param adapterCB  adapter state changed callback
+ * @param connCB     connection state changed callback
+ *
+ * @return
+ *     CAResult_t
+ */
+static CAResult_t AddNetworkStateChangedCallback(CAAdapterStateChangedCB adapterCB,
+                                                 CAConnectionStateChangedCB connCB)
+{
+    OIC_LOG(DEBUG, TAG, "Add NetworkStateChanged Callback");
+
+    if (!adapterCB || !connCB)
     {
-        OIC_LOG(ERROR, TAG, "unknown connectivity type!");
-        return;
+        OIC_LOG(ERROR, TAG, "parameter is null");
+        return CA_STATUS_INVALID_PARAM;
+    }
+
+    oc_mutex_lock(g_mutexNetCallbackList);
+    CANetworkCallback_t* callback = NULL;
+    LL_FOREACH(g_networkChangeCallbackList, callback)
+    {
+        if (callback && adapterCB == callback->adapter && connCB == callback->conn)
+        {
+            OIC_LOG(DEBUG, TAG, "this callback is already added");
+            oc_mutex_unlock(g_mutexNetCallbackList);
+            return CA_STATUS_OK;
+        }
     }
 
-    g_adapterHandler[index] = handler;
+    callback = (CANetworkCallback_t *) OICCalloc(1, sizeof(CANetworkCallback_t));
+    if (NULL == callback)
+    {
+        OIC_LOG(ERROR, TAG, "Memory allocation failed during registration");
+        oc_mutex_unlock(g_mutexNetCallbackList);
+        return CA_MEMORY_ALLOC_FAILED;
+    }
+
+    callback->adapter = adapterCB;
+    callback->conn = connCB;
+    LL_APPEND(g_networkChangeCallbackList, callback);
+    oc_mutex_unlock(g_mutexNetCallbackList);
+    OIC_LOG_V(INFO, TAG, "Added NetworkStateChanged Callback [%p]", callback);
+
+    return CA_STATUS_OK;
+}
+
+/**
+ * Remove a network callback from the network callback list
+ *
+ * @param adapterCB  adapter state changed callback
+ * @param connCB     connection state changed callback
+ *
+ * @return
+ *     CAResult_t
+ */
+static CAResult_t RemoveNetworkStateChangedCallback(CAAdapterStateChangedCB adapterCB,
+                                                    CAConnectionStateChangedCB connCB)
+{
+    OIC_LOG(DEBUG, TAG, "Remove NetworkStateChanged Callback");
+
+    oc_mutex_lock(g_mutexNetCallbackList);
+    CANetworkCallback_t* callback = NULL;
+    LL_FOREACH(g_networkChangeCallbackList, callback)
+    {
+        if (callback && adapterCB == callback->adapter && connCB == callback->conn)
+        {
+            OIC_LOG(DEBUG, TAG, "remove specific callback");
+            LL_DELETE(g_networkChangeCallbackList, callback);
+            oc_mutex_unlock(g_mutexNetCallbackList);
+            OICFree(callback);
+            return CA_STATUS_OK;
+        }
+    }
+    oc_mutex_unlock(g_mutexNetCallbackList);
 
-    OIC_LOG_V(DEBUG, TAG, "%d type adapter, register complete!", cType);
-    OIC_LOG(DEBUG, TAG, "OUT");
+    return CA_STATUS_OK;
 }
 
 #ifdef RA_ADAPTER
@@ -130,35 +220,63 @@ CAResult_t CASetAdapterRAInfo(const CARAInfo_t *caraInfo)
 }
 #endif
 
-static void CAReceivedPacketCallback(const CASecureEndpoint_t *sep,
-                                     const void *data, uint32_t dataLen)
+static CAResult_t CAReceivedPacketCallback(const CASecureEndpoint_t *sep,
+                                           const void *data, uint32_t dataLen)
 {
-    OIC_LOG(DEBUG, TAG, "IN");
-
     if (g_networkPacketReceivedCallback != NULL)
     {
-        g_networkPacketReceivedCallback(sep, data, dataLen);
+        return g_networkPacketReceivedCallback(sep, data, dataLen);
     }
     else
     {
-        OIC_LOG(ERROR, TAG, "network packet received callback is NULL!");
+        OIC_LOG(INFO, TAG, "network packet received callback is NULL!");
+        return CA_STATUS_OK;
     }
-
-    OIC_LOG(DEBUG, TAG, "OUT");
 }
 
-static void CANetworkChangedCallback(const CAEndpoint_t *info, CANetworkStatus_t status)
+static void CAAdapterChangedCallback(CATransportAdapter_t adapter, CANetworkStatus_t status)
 {
-    OIC_LOG(DEBUG, TAG, "IN");
 
+    oc_mutex_lock(g_mutexNetCallbackList);
     // Call the callback.
-    if (g_networkChangeCallback != NULL)
+    CANetworkCallback_t* callback  = NULL;
+    LL_FOREACH(g_networkChangeCallbackList, callback)
     {
-        g_networkChangeCallback(info, status);
+        if (callback && callback->adapter)
+        {
+            OIC_LOG_V(INFO, TAG, "IN application adapter changed callback [%p]", callback);
+            if (CA_INTERFACE_UP == status)
+            {
+                callback->adapter(adapter, true);
+            }
+            else if (CA_INTERFACE_DOWN == status)
+            {
+                callback->adapter(adapter, false);
+            }
+            OIC_LOG_V(INFO, TAG, "OUT application adapter changed callback [%p]", callback);
+        }
     }
+    oc_mutex_unlock(g_mutexNetCallbackList);
+    OIC_LOG_V(DEBUG, TAG, "[%d] adapter status is changed to [%d]", adapter, status);
+}
 
-    OIC_LOG(DEBUG, TAG, "OUT");
+#if defined(TCP_ADAPTER) || defined(EDR_ADAPTER) || defined(LE_ADAPTER)
+static void CAConnectionChangedCallback(const CAEndpoint_t *info, bool isConnected)
+{
+    oc_mutex_lock(g_mutexNetCallbackList);
+    // Call the callback.
+    CANetworkCallback_t* callback = NULL;
+    LL_FOREACH(g_networkChangeCallbackList, callback)
+    {
+        if (callback && callback->conn)
+        {
+            callback->conn(info, isConnected);
+        }
+    }
+    oc_mutex_unlock(g_mutexNetCallbackList);
+    OIC_LOG_V(DEBUG, TAG, "[%s] connection status is changed to [%d]", info->addr, isConnected);
 }
+#endif
 
 static void CAAdapterErrorHandleCallback(const CAEndpoint_t *endpoint,
                                          const void *data, uint32_t dataLen,
@@ -173,55 +291,130 @@ static void CAAdapterErrorHandleCallback(const CAEndpoint_t *endpoint,
     }
 }
 
-void CAInitializeAdapters(ca_thread_pool_t handle)
+static void CADestroyMutex()
+{
+    if (g_mutexNetCallbackList)
+    {
+        oc_mutex_free(g_mutexNetCallbackList);
+        g_mutexNetCallbackList = NULL;
+    }
+}
+
+static CAResult_t CACreateMutex()
+{
+    if (!g_mutexNetCallbackList)
+    {
+        g_mutexNetCallbackList = oc_mutex_new();
+        if (!g_mutexNetCallbackList)
+        {
+            return CA_STATUS_FAILED;
+        }
+    }
+
+    return CA_STATUS_OK;
+}
+
+void CAInitializeAdapters(ca_thread_pool_t handle, CATransportAdapter_t transportType)
 {
-    OIC_LOG(DEBUG, TAG, "initialize adapters..");
+    OIC_LOG_V(DEBUG, TAG, "initialize adapters %d", transportType);
 
-    memset(g_adapterHandler, 0, sizeof(CAConnectivityHandler_t) * CA_TRANSPORT_TYPE_NUM);
+    if (CA_STATUS_OK != CACreateMutex())
+    {
+        OIC_LOG(ERROR, TAG, "Failed to create mutex!");
+    }
+
+    // Initialize ssl adapter.
+#if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
+    if (CA_STATUS_OK != CAinitSslAdapter())
+    {
+        OIC_LOG(ERROR, TAG, "Failed to init SSL adapter");
+    }
+#endif
 
     // Initialize adapters and register callback.
 #ifdef IP_ADAPTER
-    CAInitializeIP(CARegisterCallback, CAReceivedPacketCallback, CANetworkChangedCallback,
-                   CAAdapterErrorHandleCallback, handle);
+    if ((transportType & CA_ADAPTER_IP) || (CA_DEFAULT_ADAPTER == transportType)
+            || (transportType == CA_ALL_ADAPTERS))
+    {
+        CAInitializeIP(CARegisterCallback, CAReceivedPacketCallback, CAAdapterChangedCallback,
+                       CAAdapterErrorHandleCallback, handle);
+    }
 #endif /* IP_ADAPTER */
 
 #ifdef EDR_ADAPTER
-    CAInitializeEDR(CARegisterCallback, CAReceivedPacketCallback, CANetworkChangedCallback,
-                    CAAdapterErrorHandleCallback, handle);
+    if ((transportType & CA_ADAPTER_RFCOMM_BTEDR) || (CA_DEFAULT_ADAPTER == transportType)
+            || (transportType == CA_ALL_ADAPTERS))
+    {
+        CAInitializeEDR(CARegisterCallback, CAReceivedPacketCallback, CAAdapterChangedCallback,
+                        CAConnectionChangedCallback, CAAdapterErrorHandleCallback, handle);
+    }
 #endif /* EDR_ADAPTER */
 
 #ifdef LE_ADAPTER
-    CAInitializeLE(CARegisterCallback, CAReceivedPacketCallback, CANetworkChangedCallback,
-                   CAAdapterErrorHandleCallback, handle);
+    if ((transportType & CA_ADAPTER_GATT_BTLE) || (CA_DEFAULT_ADAPTER == transportType)
+            || (transportType == CA_ALL_ADAPTERS))
+    {
+        CAInitializeLE(CARegisterCallback, CAReceivedPacketCallback, CAAdapterChangedCallback,
+                       CAConnectionChangedCallback, CAAdapterErrorHandleCallback, handle);
+    }
 #endif /* LE_ADAPTER */
 
 #ifdef RA_ADAPTER
-    CAInitializeRA(CARegisterCallback, CAReceivedPacketCallback, CANetworkChangedCallback,
-                   handle);
+    if ((transportType & CA_ADAPTER_REMOTE_ACCESS) || (CA_DEFAULT_ADAPTER == transportType)
+            || (transportType == CA_ALL_ADAPTERS))
+    {
+        CAInitializeRA(CARegisterCallback, CAReceivedPacketCallback, CAAdapterChangedCallback,
+                       handle);
+    }
 #endif /* RA_ADAPTER */
 
 #ifdef TCP_ADAPTER
-    CAInitializeTCP(CARegisterCallback, CAReceivedPacketCallback, CANetworkChangedCallback,
-                    CAAdapterErrorHandleCallback, handle);
+    if ((transportType & CA_ADAPTER_TCP) || (CA_DEFAULT_ADAPTER == transportType)
+            || (transportType == CA_ALL_ADAPTERS))
+    {
+        CAInitializeTCP(CARegisterCallback, CAReceivedPacketCallback, CAAdapterChangedCallback,
+                        CAConnectionChangedCallback, CAAdapterErrorHandleCallback, handle);
+    }
 #endif /* TCP_ADAPTER */
+
+#ifdef NFC_ADAPTER
+    if ((transportType & CA_ADAPTER_NFC) || (CA_DEFAULT_ADAPTER == transportType)
+            || (transportType == CA_ALL_ADAPTERS))
+    {
+        CAInitializeNFC(CARegisterCallback, CAReceivedPacketCallback, CAAdapterChangedCallback,
+                        CAAdapterErrorHandleCallback, handle);
+    }
+#endif /* NFC_ADAPTER */
 }
 
 void CASetPacketReceivedCallback(CANetworkPacketReceivedCallback callback)
 {
-    OIC_LOG(DEBUG, TAG, "IN");
+    OIC_LOG(DEBUG, TAG, "Set Receiver handle callback");
 
     g_networkPacketReceivedCallback = callback;
-
-    OIC_LOG(DEBUG, TAG, "OUT");
 }
 
-void CASetNetworkChangeCallback(CANetworkChangeCallback callback)
+void CASetNetworkMonitorCallbacks(CAAdapterStateChangedCB adapterCB,
+                                  CAConnectionStateChangedCB connCB)
 {
-    OIC_LOG(DEBUG, TAG, "IN");
-
-    g_networkChangeCallback = callback;
+    OIC_LOG(DEBUG, TAG, "Set network monitoring callback");
+    CAResult_t res = AddNetworkStateChangedCallback(adapterCB, connCB);
+    if (CA_STATUS_OK != res)
+    {
+        OIC_LOG(ERROR, TAG, "AddNetworkStateChangedCallback has failed");
+    }
+}
 
-    OIC_LOG(DEBUG, TAG, "OUT");
+CAResult_t CAUnsetNetworkMonitorCallbacks(CAAdapterStateChangedCB adapterCB,
+                                          CAConnectionStateChangedCB connCB)
+{
+    OIC_LOG(DEBUG, TAG, "Unset network monitoring callback");
+    CAResult_t res = RemoveNetworkStateChangedCallback(adapterCB, connCB);
+    if (CA_STATUS_OK != res)
+    {
+        OIC_LOG(ERROR, TAG, "RemoveNetworkStateChangedCallback has failed");
+    }
+    return res;
 }
 
 void CASetErrorHandleCallback(CAErrorHandleCallback errorCallback)
@@ -235,19 +428,19 @@ CAResult_t CAStartAdapter(CATransportAdapter_t transportType)
     OIC_LOG_V(DEBUG, TAG, "Start the adapter of CAConnectivityType[%d]", transportType);
 
     int index = CAGetAdapterIndex(transportType);
-
-    if (index == -1)
+    if (0 > index)
     {
         OIC_LOG(ERROR, TAG, "unknown connectivity type!");
         return CA_STATUS_FAILED;
     }
 
+    CAResult_t res = CA_STATUS_FAILED;
     if (g_adapterHandler[index].startAdapter != NULL)
     {
-        g_adapterHandler[index].startAdapter();
+        res = g_adapterHandler[index].startAdapter();
     }
 
-    return CA_STATUS_OK;
+    return res;
 }
 
 void CAStopAdapter(CATransportAdapter_t transportType)
@@ -255,8 +448,7 @@ void CAStopAdapter(CATransportAdapter_t transportType)
     OIC_LOG_V(DEBUG, TAG, "Stop the adapter of CATransportType[%d]", transportType);
 
     int index = CAGetAdapterIndex(transportType);
-
-    if (index == -1)
+    if (0 > index)
     {
         OIC_LOG(ERROR, TAG, "unknown transport type!");
         return;
@@ -275,12 +467,23 @@ CAResult_t CAGetNetworkInfo(CAEndpoint_t **info, uint32_t *size)
         return CA_STATUS_INVALID_PARAM;
     }
 
-    CAEndpoint_t *tempInfo[CA_TRANSPORT_TYPE_NUM] = { 0 };
-    uint32_t tempSize[CA_TRANSPORT_TYPE_NUM] = { 0 };
+    CAEndpoint_t **tempInfo = (CAEndpoint_t**) OICCalloc(g_numberOfAdapters, sizeof(*tempInfo));
+    if (!tempInfo)
+    {
+        OIC_LOG(ERROR, TAG, "Out of memory!");
+        return CA_MEMORY_ALLOC_FAILED;
+    }
+    uint32_t *tempSize =(uint32_t*) OICCalloc(g_numberOfAdapters, sizeof(*tempSize));
+    if (!tempSize)
+    {
+        OIC_LOG(ERROR, TAG, "Out of memory!");
+        OICFree(tempInfo);
+        return CA_MEMORY_ALLOC_FAILED;
+    }
 
     CAResult_t res = CA_STATUS_FAILED;
-    uint32_t resSize = 0;
-    for (int index = 0; index < CA_TRANSPORT_TYPE_NUM; index++)
+    size_t resSize = 0;
+    for (uint32_t index = 0; index < g_numberOfAdapters; index++)
     {
         if (g_adapterHandler[index].GetnetInfo != NULL)
         {
@@ -294,24 +497,31 @@ CAResult_t CAGetNetworkInfo(CAEndpoint_t **info, uint32_t *size)
                 resSize += tempSize[index];
             }
 
+#ifndef __TIZENRT__
             OIC_LOG_V(DEBUG,
                       TAG,
-                      "%d adapter network info size is %" PRIu32 " res:%d",
+                      "%" PRIu32 " adapter network info size is %" PRIu32 " res:%d",
                       index,
                       tempSize[index],
                       res);
+#endif
         }
     }
 
-    OIC_LOG_V(DEBUG, TAG, "network info total size is %d!", resSize);
+    OIC_LOG_V(DEBUG, TAG, "network info total size is %zu!", resSize);
 
     if (resSize == 0)
     {
+        OICFree(tempInfo);
+        OICFree(tempSize);
         if (res == CA_ADAPTER_NOT_ENABLED || res == CA_NOT_SUPPORTED)
         {
             return res;
         }
-        return CA_STATUS_FAILED;
+        else
+        {
+            return CA_STATUS_FAILED;
+        }
     }
 
     // #3. add data into result
@@ -323,7 +533,7 @@ CAResult_t CAGetNetworkInfo(CAEndpoint_t **info, uint32_t *size)
     *info = resInfo;
     *size = resSize;
 
-    for (int index = 0; index < CA_TRANSPORT_TYPE_NUM; index++)
+    for (uint32_t index = 0; index < g_numberOfAdapters; index++)
     {
         // check information
         if (tempSize[index] == 0)
@@ -341,6 +551,8 @@ CAResult_t CAGetNetworkInfo(CAEndpoint_t **info, uint32_t *size)
         OICFree(tempInfo[index]);
         tempInfo[index] = NULL;
     }
+    OICFree(tempInfo);
+    OICFree(tempSize);
 
     OIC_LOG(DEBUG, TAG, "each network info save success!");
     return CA_STATUS_OK;
@@ -348,60 +560,83 @@ CAResult_t CAGetNetworkInfo(CAEndpoint_t **info, uint32_t *size)
     // memory error label.
 memory_error_exit:
 
-    for (int index = 0; index < CA_TRANSPORT_TYPE_NUM; index++)
+    for (uint32_t index = 0; index < g_numberOfAdapters; index++)
     {
-
         OICFree(tempInfo[index]);
         tempInfo[index] = NULL;
     }
+    OICFree(tempInfo);
+    OICFree(tempSize);
 
     return CA_MEMORY_ALLOC_FAILED;
 }
 
-CAResult_t CASendUnicastData(const CAEndpoint_t *endpoint, const void *data, uint32_t length)
+CAResult_t CASendUnicastData(const CAEndpoint_t *endpoint, const void *data, uint32_t length,
+                             CADataType_t dataType)
 {
-    OIC_LOG(DEBUG, TAG, "IN");
-
     if (endpoint == NULL)
     {
         OIC_LOG(DEBUG, TAG, "Invalid endpoint");
         return CA_STATUS_INVALID_PARAM;
     }
 
-    CATransportAdapter_t type = endpoint->adapter;
 
-    int index = CAGetAdapterIndex(type);
-
-    if (index == -1)
+    u_arraylist_t *list = CAGetSelectedNetworkList();
+    if (!list)
     {
-        OIC_LOG(ERROR, TAG, "unknown transport type!");
-        return CA_STATUS_INVALID_PARAM;
+        OIC_LOG(ERROR, TAG, "No selected network");
+        return CA_SEND_FAILED;
     }
+    CATransportAdapter_t requestedAdapter = endpoint->adapter ? endpoint->adapter : CA_ALL_ADAPTERS;
 
-    int32_t sentDataLen = 0;
-
-    if (g_adapterHandler[index].sendData != NULL)
+    for (uint32_t i = 0; i < u_arraylist_length(list); i++)
     {
-        sentDataLen = g_adapterHandler[index].sendData(endpoint, data, length);
-    }
+        void* ptrType = u_arraylist_get(list, i);
 
-    if (sentDataLen != (int)length)
-    {
-        OIC_LOG(ERROR, TAG, "error in sending data. Error will be reported in adapter");
+        if (NULL == ptrType)
+        {
+            continue;
+        }
+
+        CATransportAdapter_t connType = *(CATransportAdapter_t *)ptrType;
+        if (0 == (connType & requestedAdapter))
+        {
+            continue;
+        }
+
+        int index = CAGetAdapterIndex(connType);
+
+        if (-1 == index)
+        {
+            OIC_LOG_V(ERROR, TAG, "unknown transport type[%d]", connType);
+            return CA_STATUS_INVALID_PARAM;
+        }
+
+        int32_t sentDataLen = 0;
+
+        if (NULL != g_adapterHandler[index].sendData)
+        {
+            OIC_LOG(DEBUG, TAG, "unicast message to adapter");
+            sentDataLen = g_adapterHandler[index].sendData(endpoint, data, length, dataType);
+        }
+
+        if (sentDataLen != (int32_t)length)
+        {
+            OIC_LOG(ERROR, TAG, "error in sending data. Error will be reported in adapter");
 #ifdef SINGLE_THREAD
-        //in case of single thread, no error handler. Report error immediately
-        return CA_SEND_FAILED;
+            //in case of single thread, no error handler. Report error immediately
+            return CA_SEND_FAILED;
 #endif
+        }
+
     }
 
-    OIC_LOG(DEBUG, TAG, "OUT");
     return CA_STATUS_OK;
 }
 
-CAResult_t CASendMulticastData(const CAEndpoint_t *endpoint, const void *data, uint32_t length)
+CAResult_t CASendMulticastData(const CAEndpoint_t *endpoint, const void *data, uint32_t length,
+                               CADataType_t dataType)
 {
-    OIC_LOG(DEBUG, TAG, "IN");
-
     u_arraylist_t *list = CAGetSelectedNetworkList();
     if (!list)
     {
@@ -409,34 +644,33 @@ CAResult_t CASendMulticastData(const CAEndpoint_t *endpoint, const void *data, u
         return CA_SEND_FAILED;
     }
 
-    CATransportFlags_t requestedAdapter = endpoint->adapter ? endpoint->adapter : CA_ALL_ADAPTERS;
-
-    for (uint32_t i = 0; i < u_arraylist_length(list); i++)
+    CATransportAdapter_t requestedAdapter = endpoint->adapter ? endpoint->adapter : CA_ALL_ADAPTERS;
+    size_t selectedLength = u_arraylist_length(list);
+    for (size_t i = 0; i < selectedLength; i++)
     {
         void* ptrType = u_arraylist_get(list, i);
 
-        if(ptrType == NULL)
+        if (NULL == ptrType)
         {
             continue;
         }
 
         CATransportAdapter_t connType = *(CATransportAdapter_t *)ptrType;
-        if ((connType & requestedAdapter) == 0)
+        if (0 == (connType & requestedAdapter))
         {
             continue;
         }
 
         int index = CAGetAdapterIndex(connType);
-
-        if (index == -1)
+        if (0 > index)
         {
-            OIC_LOG(DEBUG, TAG, "unknown connectivity type!");
+            OIC_LOG(ERROR, TAG, "unknown connectivity type!");
             continue;
         }
 
         uint32_t sentDataLen = 0;
 
-        if (g_adapterHandler[index].sendDataToAll != NULL)
+        if (NULL != g_adapterHandler[index].sendDataToAll)
         {
             void *payload = (void *) OICMalloc(length);
             if (!payload)
@@ -445,7 +679,7 @@ CAResult_t CASendMulticastData(const CAEndpoint_t *endpoint, const void *data, u
                 return CA_MEMORY_ALLOC_FAILED;
             }
             memcpy(payload, data, length);
-            sentDataLen = g_adapterHandler[index].sendDataToAll(endpoint, payload, length);
+            sentDataLen = g_adapterHandler[index].sendDataToAll(endpoint, payload, length, dataType);
             OICFree(payload);
         }
 
@@ -459,23 +693,22 @@ CAResult_t CASendMulticastData(const CAEndpoint_t *endpoint, const void *data, u
         }
     }
 
-    OIC_LOG(DEBUG, TAG, "OUT");
-
     return CA_STATUS_OK;
 }
 
 CAResult_t CAStartListeningServerAdapters()
 {
-    OIC_LOG(DEBUG, TAG, "IN");
+    CAResult_t result = CA_STATUS_FAILED;
 
     u_arraylist_t *list = CAGetSelectedNetworkList();
     if (!list)
     {
         OIC_LOG(ERROR, TAG, "No selected network");
-        return CA_STATUS_FAILED;
+        return result;
     }
 
-    for (uint32_t i = 0; i < u_arraylist_length(list); i++)
+    size_t length = u_arraylist_length(list);
+    for (size_t i = 0; i < length; i++)
     {
         void* ptrType = u_arraylist_get(list, i);
 
@@ -487,7 +720,7 @@ CAResult_t CAStartListeningServerAdapters()
         CATransportAdapter_t connType = *(CATransportAdapter_t *)ptrType;
 
         int index = CAGetAdapterIndex(connType);
-        if (index == -1)
+        if (0 > index)
         {
             OIC_LOG(ERROR, TAG, "unknown connectivity type!");
             continue;
@@ -495,27 +728,70 @@ CAResult_t CAStartListeningServerAdapters()
 
         if (g_adapterHandler[index].startListenServer != NULL)
         {
-            g_adapterHandler[index].startListenServer();
+            const CAResult_t tmp =
+                g_adapterHandler[index].startListenServer();
+
+            // Successful listen if at least one adapter started.
+            if (CA_STATUS_OK == tmp)
+            {
+                result = tmp;
+            }
+        }
+    }
+
+    return result;
+}
+
+CAResult_t CAStopListeningServerAdapters()
+{
+    u_arraylist_t *list = CAGetSelectedNetworkList();
+    if (!list)
+    {
+        OIC_LOG(ERROR, TAG, "No selected network");
+        return CA_STATUS_FAILED;
+    }
+
+    size_t length = u_arraylist_length(list);
+    for (size_t i = 0; i < length; i++)
+    {
+        void* ptrType = u_arraylist_get(list, i);
+        if(ptrType == NULL)
+        {
+            continue;
+        }
+
+        CATransportAdapter_t connType = *(CATransportAdapter_t *)ptrType;
+
+        int index = CAGetAdapterIndex(connType);
+        if (0 > index)
+        {
+            OIC_LOG(ERROR, TAG, "unknown connectivity type!");
+            continue;
+        }
+
+        if (g_adapterHandler[index].stopListenServer != NULL)
+        {
+            g_adapterHandler[index].stopListenServer();
         }
     }
 
-    OIC_LOG(DEBUG, TAG, "OUT");
     return CA_STATUS_OK;
 }
 
 CAResult_t CAStartDiscoveryServerAdapters()
 {
-    OIC_LOG(DEBUG, TAG, "IN");
+    CAResult_t result = CA_STATUS_FAILED;
 
     u_arraylist_t *list = CAGetSelectedNetworkList();
 
     if (!list)
     {
         OIC_LOG(ERROR, TAG, "No selected network");
-        return CA_STATUS_FAILED;
+        return result;
     }
 
-    for (uint32_t i = 0; i < u_arraylist_length(list); i++)
+    size_t length = u_arraylist_length(list);
+    for (size_t i = 0; i < length; i++)
     {
         void* ptrType = u_arraylist_get(list, i);
 
@@ -527,8 +803,7 @@ CAResult_t CAStartDiscoveryServerAdapters()
         CATransportAdapter_t connType = *(CATransportAdapter_t *)ptrType;
 
         int index = CAGetAdapterIndex(connType);
-
-        if (index == -1)
+        if (0 > index)
         {
             OIC_LOG(DEBUG, TAG, "unknown connectivity type!");
             continue;
@@ -536,20 +811,25 @@ CAResult_t CAStartDiscoveryServerAdapters()
 
         if (g_adapterHandler[index].startDiscoveryServer != NULL)
         {
-            g_adapterHandler[index].startDiscoveryServer();
+            const CAResult_t tmp =
+                g_adapterHandler[index].startDiscoveryServer();
+
+            // Successful discovery if at least one adapter started.
+            if (CA_STATUS_OK == tmp)
+            {
+                result = tmp;
+            }
         }
     }
 
-    OIC_LOG(DEBUG, TAG, "OUT");
-    return CA_STATUS_OK;
+    return result;
 }
 
 void CATerminateAdapters()
 {
-    OIC_LOG(DEBUG, TAG, "IN");
+    CADestroyMutex();
 
-    uint32_t index;
-    for (index = 0; index < CA_TRANSPORT_TYPE_NUM; index++)
+    for (uint32_t index = 0; index < g_numberOfAdapters; index++)
     {
         if (g_adapterHandler[index].terminate != NULL)
         {
@@ -557,13 +837,18 @@ void CATerminateAdapters()
         }
     }
 
-    OIC_LOG(DEBUG, TAG, "OUT");
+#if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
+    CAdeinitSslAdapter();
+#endif
+
+    OICFree(g_adapterHandler);
+    g_adapterHandler = NULL;
+    g_numberOfAdapters = 0;
 }
 
 #ifdef SINGLE_THREAD
 CAResult_t CAReadData()
 {
-    OIC_LOG(DEBUG, TAG, "IN");
     u_arraylist_t *list = CAGetSelectedNetworkList();
 
     if (!list)
@@ -584,8 +869,7 @@ CAResult_t CAReadData()
         CATransportAdapter_t connType = *(CATransportAdapter_t *) ptrType;
 
         int index = CAGetAdapterIndex(connType);
-
-        if (-1 == index)
+        if (0 > index)
         {
             OIC_LOG(DEBUG, TAG, "unknown connectivity type!");
             continue;
@@ -597,8 +881,37 @@ CAResult_t CAReadData()
         }
     }
 
-    OIC_LOG(DEBUG, TAG, "OUT");
     return CA_STATUS_OK;
 }
 #endif
 
+#ifdef IP_ADAPTER
+CAResult_t CASetMulticastTTL(size_t ttl)
+{
+    return CAIPSetMulticastTTL(ttl);
+}
+
+CAResult_t CAGetMulticastTTL(size_t *ttl)
+{
+    return CAIPGetMulticastTTL(ttl);
+}
+#endif
+
+#ifdef TCP_ADAPTER
+CAResult_t CADisconnectSession(const CAEndpoint_t *endpoint)
+{
+    return CATCPDisconnectSession(endpoint);
+}
+#endif
+
+#ifdef LE_ADAPTER
+void CAStartGattServer()
+{
+       CALEStartGattServer();
+}
+
+void CAStopGattServer()
+{
+       CALEStopGattServer();
+}
+#endif