Update snapshot(2018-02-07)
[platform/upstream/iotivity.git] / resource / csdk / connectivity / src / tcp_adapter / catcpserver.c
index 661612e..f40c533 100644 (file)
@@ -77,6 +77,8 @@
 
 #define COAP_TCP_MAX_BUFFER_CHUNK_SIZE 65530 //64kb - 6 (coap+tcp max header size)
 
+#define MILLISECONDS_PER_SECOND   (1000)
+
 /**
  * Thread pool.
  */
@@ -93,6 +95,16 @@ static oc_mutex g_mutexObjectList = NULL;
 static oc_cond g_condObjectList = NULL;
 
 /**
+ * Mutex to synchronize send.
+ */
+static oc_mutex g_mutexSend = NULL;
+
+/**
+ * Conditional mutex to synchronize send.
+ */
+static oc_cond g_condSend = NULL;
+
+/**
  * Maintains the callback to be notified when data received from remote device.
  */
 static CATCPPacketReceivedCallback g_packetReceivedCallback = NULL;
@@ -150,7 +162,7 @@ CAResult_t CATCPCreateMutex()
         g_mutexObjectList = oc_mutex_new();
         if (!g_mutexObjectList)
         {
-            OIC_LOG(ERROR, TAG, "Failed to created mutex!");
+            OIC_LOG(ERROR, TAG, "Failed to create mutex!");
             return CA_STATUS_FAILED;
         }
     }
@@ -174,7 +186,54 @@ CAResult_t CATCPCreateCond()
         g_condObjectList = oc_cond_new();
         if (!g_condObjectList)
         {
-            OIC_LOG(ERROR, TAG, "Failed to created cond!");
+            OIC_LOG(ERROR, TAG, "Failed to create cond!");
+            return CA_STATUS_FAILED;
+        }
+    }
+    return CA_STATUS_OK;
+}
+
+void CATCPDestroySendMutex()
+{
+    if (g_mutexSend)
+    {
+        oc_mutex_free(g_mutexSend);
+        g_mutexSend = NULL;
+    }
+}
+
+CAResult_t CATCPCreateSendMutex()
+{
+    if (!g_mutexSend)
+    {
+        g_mutexSend = oc_mutex_new();
+        if (!g_mutexSend)
+        {
+            OIC_LOG(ERROR, TAG, "Failed to create send mutex!");
+            return CA_STATUS_FAILED;
+        }
+    }
+
+    return CA_STATUS_OK;
+}
+
+void CATCPDestroySendCond()
+{
+    if (g_condSend)
+    {
+        oc_cond_free(g_condSend);
+        g_condSend = NULL;
+    }
+}
+
+CAResult_t CATCPCreateSendCond()
+{
+    if (!g_condSend)
+    {
+        g_condSend = oc_cond_new();
+        if (!g_condSend)
+        {
+            OIC_LOG(ERROR, TAG, "Failed to create send cond!");
             return CA_STATUS_FAILED;
         }
     }
@@ -1075,6 +1134,10 @@ void CATCPStopServer()
     // set terminate flag.
     caglobals.tcp.terminate = true;
 
+    oc_mutex_lock(g_mutexSend);
+    oc_cond_signal(g_condSend);
+    oc_mutex_unlock(g_mutexSend);
+
 #ifdef __TIZENRT__
     if (caglobals.tcp.started)
     {
@@ -1189,7 +1252,7 @@ static ssize_t sendData(const CAEndpoint_t *endpoint, const void *data,
 
     // #2. send data to remote device.
     ssize_t remainLen = dlen;
-    size_t sendCounter = 0;
+    unsigned int sendRetryTime = 1;
     do
     {
 #ifdef MSG_NOSIGNAL
@@ -1206,14 +1269,30 @@ static ssize_t sendData(const CAEndpoint_t *endpoint, const void *data,
                                    len, false, strerror(errno));
                 return len;
             }
-            sendCounter++;
-            OIC_LOG_V(WARNING, TAG, "send blocked. trying %zu attempt from 25", sendCounter);
-            if(sendCounter >= 25)
+
+            // re-trying send after 10, 20, 40, 80, 160 and 320 milliseconds
+            if (sendRetryTime > 32)
             {
                 return len;
             }
+
+            unsigned int waitTime = sendRetryTime * 10 * MILLISECONDS_PER_SECOND;
+            OIC_LOG_V(WARNING, TAG, "send blocked. trying send after %u microseconds", waitTime);
+
+            oc_mutex_lock(g_mutexSend);
+            oc_cond_wait_for(g_condSend, g_mutexSend, waitTime);
+            oc_mutex_unlock(g_mutexSend);
+
+            if (caglobals.tcp.terminate)
+            {
+                return len;
+            }
+
+            sendRetryTime = (sendRetryTime << 1);
+
             continue;
         }
+        sendRetryTime = 1;
         data += len;
         remainLen -= len;
     } while (remainLen > 0);