added filter to handle an IP loopback message in CA directly
authorJaewook Jung <jw0213.jung@samsung.com>
Thu, 6 Oct 2016 10:35:27 +0000 (19:35 +0900)
committerDan Mihai <Daniel.Mihai@microsoft.com>
Wed, 7 Dec 2016 17:12:11 +0000 (17:12 +0000)
If IoTivity stack sends a message to itself, which means the loopback,
it is unnecessary to let them go through the socket layer.
Especially it is a waste when the large payload will be sent by block-wise transfer.
So I made CA layer to handle the loopback message directly.

Change-Id: I2b8e5217575df391dd4ab66d924a3a24c2584915
Signed-off-by: Jaewook Jung <jw0213.jung@samsung.com>
Reviewed-on: https://gerrit.iotivity.org/gerrit/12887
Tested-by: jenkins-iotivity <jenkins-iotivity@opendaylight.org>
Reviewed-by: Phil Coval <philippe.coval@osg.samsung.com>
Reviewed-by: Hyuna Jo <hyuna0213.jo@samsung.com>
Reviewed-by: Jaehong Jo <jaehong.jo@samsung.com>
Reviewed-by: Dan Mihai <Daniel.Mihai@microsoft.com>
resource/csdk/connectivity/inc/cainterfacecontroller.h
resource/csdk/connectivity/inc/caipadapter.h
resource/csdk/connectivity/src/cainterfacecontroller.c
resource/csdk/connectivity/src/camessagehandler.c
resource/csdk/connectivity/src/ip_adapter/caipadapter.c

index 0dbd673..fa15c25 100644 (file)
@@ -161,6 +161,12 @@ CAResult_t CAStopListeningServerAdapters();
 CAResult_t CAStartDiscoveryServerAdapters();
 
 /**
+ * Check whether the endpoint is my own or not.
+ * @return  true or false.
+ */
+bool CAIsLocalEndpoint(const CAEndpoint_t *ep);
+
+/**
  * Terminates the adapters which are initialized during the initialization.
  */
 void CATerminateAdapters();
index 7ca9267..829b043 100644 (file)
@@ -134,6 +134,12 @@ CAResult_t CAReadIPData();
 CAResult_t CAStopIP();
 
 /**
+ * Check whether the endpoint is my own or not.
+ * @return  true or false.
+ */
+bool CAIPIsLocalEndpoint(const CAEndpoint_t *ep);
+
+/**
  * Terminate the IP connectivity adapter.
  * Configuration information will be deleted from further use.
  */
index fbc0364..42ad155 100644 (file)
@@ -752,6 +752,19 @@ CAResult_t CAStartDiscoveryServerAdapters()
     return result;
 }
 
+bool CAIsLocalEndpoint(const CAEndpoint_t *ep)
+{
+#ifdef IP_ADAPTER
+    if (ep->adapter & CA_ADAPTER_IP)
+    {
+        return CAIPIsLocalEndpoint(ep);
+    }
+#endif /* IP_ADAPTER */
+
+    //TODO: implement for the other adapters(EDR/LE/NFC)
+    return false;
+}
+
 void CATerminateAdapters()
 {
     for (uint32_t index = 0; index < g_numberOfAdapters; index++)
index 847b96f..1f3fe86 100644 (file)
@@ -999,6 +999,13 @@ CAResult_t CADetachSendMessage(const CAEndpoint_t *endpoint, const void *sendMsg
     OICFree(data);
 
 #else
+    if (SEND_TYPE_UNICAST == data->type && CAIsLocalEndpoint(data->remoteEndpoint))
+    {
+        OIC_LOG(DEBUG, TAG,
+                "This is a loopback message. Transfer it to the receive queue directly");
+        CAQueueingThreadAddData(&g_receiveThread, data, sizeof(CAData_t));
+        return CA_STATUS_OK;
+    }
 #ifdef WITH_BWT
     if (CAIsSupportedBlockwiseTransfer(endpoint->adapter))
     {
index 6f167c0..ba23056 100644 (file)
@@ -62,6 +62,11 @@ static CAQueueingThread_t *g_sendQueueHandle = NULL;
 #endif
 
 /**
+ * List of the endpoint that has a stack-owned IP address.
+ */
+static u_arraylist_t *g_ownIpEndpointList = NULL;
+
+/**
  * Network Packet Received Callback to CA.
  */
 static CANetworkPacketReceivedCallback g_networkPacketCallback = NULL;
@@ -83,6 +88,8 @@ static ssize_t CAIPPacketSendCB(CAEndpoint_t *endpoint,
                                 const void *data, size_t dataLength);
 #endif
 
+static void CAUpdateStoredIPAddressInfo(CANetworkStatus_t status);
+
 #ifndef SINGLE_THREAD
 
 static CAResult_t CAIPInitializeQueueHandles();
@@ -108,11 +115,20 @@ CAResult_t CAIPInitializeQueueHandles()
         return CA_STATUS_OK;
     }
 
+    g_ownIpEndpointList = u_arraylist_create();
+    if (!g_ownIpEndpointList)
+    {
+        OIC_LOG(ERROR, TAG, "Memory allocation failed! (g_ownIpEndpointList)");
+        return CA_MEMORY_ALLOC_FAILED;
+    }
+
     // Create send message queue
     g_sendQueueHandle = OICMalloc(sizeof(CAQueueingThread_t));
     if (!g_sendQueueHandle)
     {
-        OIC_LOG(ERROR, TAG, "Memory allocation failed!");
+        OIC_LOG(ERROR, TAG, "Memory allocation failed! (g_sendQueueHandle)");
+        u_arraylist_free(&g_ownIpEndpointList);
+        g_ownIpEndpointList = NULL;
         return CA_MEMORY_ALLOC_FAILED;
     }
 
@@ -123,6 +139,8 @@ CAResult_t CAIPInitializeQueueHandles()
         OIC_LOG(ERROR, TAG, "Failed to Initialize send queue thread");
         OICFree(g_sendQueueHandle);
         g_sendQueueHandle = NULL;
+        u_arraylist_free(&g_ownIpEndpointList);
+        g_ownIpEndpointList = NULL;
         return CA_STATUS_FAILED;
     }
 
@@ -134,12 +152,16 @@ void CAIPDeinitializeQueueHandles()
     CAQueueingThreadDestroy(g_sendQueueHandle);
     OICFree(g_sendQueueHandle);
     g_sendQueueHandle = NULL;
+    u_arraylist_free(&g_ownIpEndpointList);
+    g_ownIpEndpointList = NULL;
 }
 
 #endif // SINGLE_THREAD
 
 void CAIPAdapterHandler(CATransportAdapter_t adapter, CANetworkStatus_t status)
 {
+    CAUpdateStoredIPAddressInfo(status);
+
     if (g_networkChangeCallback)
     {
         g_networkChangeCallback(adapter, status);
@@ -150,6 +172,40 @@ void CAIPAdapterHandler(CATransportAdapter_t adapter, CANetworkStatus_t status)
     }
 }
 
+static void CAUpdateStoredIPAddressInfo(CANetworkStatus_t status)
+{
+    if (CA_INTERFACE_UP == status)
+    {
+        OIC_LOG(DEBUG, TAG, "IP adapter status is on. Store the own IP address info");
+
+        CAEndpoint_t *eps = NULL;
+        uint32_t numOfEps = 0;
+
+        CAResult_t res = CAGetIPInterfaceInformation(&eps, &numOfEps);
+        if (CA_STATUS_OK != res)
+        {
+            OIC_LOG(ERROR, TAG, "CAGetIPInterfaceInformation failed");
+            return;
+        }
+
+        for (size_t i = 0; i < numOfEps; i++)
+        {
+            u_arraylist_add(g_ownIpEndpointList, (void *)&eps[i]);
+        }
+    }
+    else // CA_INTERFACE_DOWN
+    {
+        OIC_LOG(DEBUG, TAG, "IP adapter status is off. Remove the own IP address info");
+
+        uint32_t len = u_arraylist_length(g_ownIpEndpointList);
+        for (uint32_t i = len; i > 0; i--)
+        {
+            CAEndpoint_t *ep = u_arraylist_remove(g_ownIpEndpointList, i - 1);
+            OICFree(ep);
+        }
+    }
+}
+
 #ifdef __WITH_DTLS__
 static ssize_t CAIPPacketSendCB(CAEndpoint_t *endpoint, const void *data, size_t dataLength)
 {
@@ -161,7 +217,6 @@ static ssize_t CAIPPacketSendCB(CAEndpoint_t *endpoint, const void *data, size_t
 }
 #endif
 
-
 void CAIPPacketReceivedCB(const CASecureEndpoint_t *sep, const void *data,
                           size_t dataLength)
 {
@@ -176,6 +231,31 @@ void CAIPPacketReceivedCB(const CASecureEndpoint_t *sep, const void *data,
     }
 }
 
+bool CAIPIsLocalEndpoint(const CAEndpoint_t *ep)
+{
+    char addr[MAX_ADDR_STR_SIZE_CA];
+    OICStrcpy(addr, MAX_ADDR_STR_SIZE_CA, ep->addr);
+
+    // drop the zone ID if the address of endpoint is IPv6. ifindex will be checked instead.
+    if ((ep->flags & CA_IPV6) && strchr(addr, '%'))
+    {
+        strtok(addr, "%");
+    }
+
+    size_t len = u_arraylist_length(g_ownIpEndpointList);
+    for (size_t i = 0; i < len; i++)
+    {
+        CAEndpoint_t *ownIpEp = u_arraylist_get(g_ownIpEndpointList, i);
+        if (!strcmp(addr, ownIpEp->addr) && ep->port == ownIpEp->port
+                                         && ep->ifindex == ownIpEp->ifindex)
+        {
+            return true;
+        }
+    }
+
+    return false;
+}
+
 void CAIPErrorHandler(const CAEndpoint_t *endpoint, const void *data,
                       uint32_t dataLength, CAResult_t result)
 {