#define CA_TCP_SELECT_TIMEOUT 10
/**
+ * Mutex to synchronize TCP adapter access.
+ */
+static oc_mutex g_mutexAdapter = NULL;
+
+/**
+ * State to control closing of TCP servers on interface down event.
+ */
+static bool g_skipCloseOnIFDown;
+
+/**
* Queue handle for Send Data.
*/
static CAQueueingThread_t *g_sendQueueHandle = NULL;
static CAResult_t CATCPInitializeQueueHandles();
-static void CATCPDeinitializeQueueHandles();
+static void CATCPDeinitializeQueueHandles(CAQueueingThread_t *queueHandle);
static void CATCPSendDataThread(void *threadData);
return CA_STATUS_OK;
}
-void CATCPDeinitializeQueueHandles()
+void CATCPDeinitializeQueueHandles(CAQueueingThread_t *queueHandle)
{
- CAQueueingThreadDestroy(g_sendQueueHandle);
- OICFree(g_sendQueueHandle);
- g_sendQueueHandle = NULL;
+ CAQueueingThreadDestroy(queueHandle);
+ OICFree(queueHandle);
}
void CATCPConnectionStateCB(const char *ipAddress, CANetworkStatus_t status)
}
else
{
- OIC_LOG_V(DEBUG, TAG, "%u bytes required for complete CoAP",
+ OIC_LOG_V(DEBUG, TAG, "%zd bytes required for complete CoAP",
svritem->totalLen - svritem->len);
}
}
OIC_LOG_BUFFER(DEBUG, TAG, data, dataLength);
ssize_t ret = CATCPSendData(endpoint, data, dataLength);
- OIC_LOG_V(DEBUG, TAG, "Out %s : %d bytes sent", __func__, ret);
+ OIC_LOG_V(DEBUG, TAG, "Out %s : %zd bytes sent", __func__, ret);
return ret;
}
#endif
OIC_LOG_V(ERROR, TAG, "CAQueueingThreadClearData failed[%d]", res);
}
- CATCPStopServer();
+ oc_mutex_lock(g_mutexAdapter);
+ if (!g_skipCloseOnIFDown)
+ {
+ CATCPStopServer();
+ }
+ else
+ {
+ OIC_LOG(INFO, TAG, "Skip closing servers!");
+ }
+ oc_mutex_unlock(g_mutexAdapter);
}
else if (CA_INTERFACE_UP == status)
{
{
flags |= caglobals.clientFlags;
}
+
+#ifndef DISABLE_TCP_SERVER
if (caglobals.server)
{
flags |= caglobals.serverFlags;
}
+#endif
caglobals.tcp.ipv4tcpenabled = flags & CA_IPV4;
caglobals.tcp.ipv6tcpenabled = flags & CA_IPV6;
CAInitializeTCPGlobals();
+ // Create Mutex for synchronize access at adapter level
+ if (!g_mutexAdapter)
+ {
+ g_mutexAdapter = oc_mutex_new();
+ if (!g_mutexAdapter)
+ {
+ OIC_LOG(ERROR, TAG, "Failed to create mutex!");
+ return CA_STATUS_FAILED;
+ }
+ }
+
+ g_skipCloseOnIFDown = false;
+
CAResult_t res = CATCPCreateMutex();
if (CA_STATUS_OK == res)
{
return res;
}
+ res = CATCPCreateSendMutex();
+ if (CA_STATUS_OK == res)
+ {
+ res = CATCPCreateSendCond();
+ }
+ if (CA_STATUS_OK != res)
+ {
+ OIC_LOG(ERROR, TAG, "failed to create send data mutex/cond");
+ CATCPDestroyMutex();
+ CATCPDestroyCond();
+ CATCPDestroySendMutex();
+ CATCPDestroySendCond();
+ return res;
+ }
+
#ifndef SINGLE_THREAD
caglobals.tcp.threadpool = handle;
#endif
static bool CAClearQueueEndpointDataContext(void *data, uint32_t size, void *ctx)
{
+ (void)size;
+
if (NULL == data || NULL == ctx)
{
return false;
CAResult_t CATCPDisconnectSession(const CAEndpoint_t *endpoint)
{
- CAResult_t res = CA_STATUS_OK;
+ CAResult_t res = CAQueueingThreadClearContextData(g_sendQueueHandle,
+ CAClearQueueEndpointDataContext,
+ endpoint);
+ if (CA_STATUS_OK != res)
+ {
+ OIC_LOG(ERROR, TAG, "failed to clear context data");
+ }
+
#ifdef __WITH_TLS__
res = CAcloseSslConnection(endpoint);
if (CA_STATUS_OK != res)
{
OIC_LOG(ERROR, TAG, "failed to close TLS session");
- return res;
}
#endif
+
res = CASearchAndDeleteTCPSession(endpoint);
if (CA_STATUS_OK != res)
{
OIC_LOG(ERROR, TAG, "failed to close TCP session");
}
- res = CAQueueingThreadClearContextData(g_sendQueueHandle,
- CAClearQueueEndpointDataContext,
- endpoint);
+
return res;
}
+void CATCPSkipCloseOnInterfaceDown(bool state)
+{
+ oc_mutex_lock(g_mutexAdapter);
+ g_skipCloseOnIFDown = state;
+ oc_mutex_unlock(g_mutexAdapter);
+}
+
CAResult_t CAStartTCPListeningServer()
{
-#ifndef SINGLE_THREAD
+#if !defined(SINGLE_THREAD) && !defined(DISABLE_TCP_SERVER)
if (!caglobals.server)
{
caglobals.server = true; // only needed to run CA tests
const void *data, uint32_t dataLength,
CADataType_t dataType)
{
+ (void)endpoint;
+ (void)data;
+ (void)dataLength;
(void)dataType;
- return CAQueueTCPData(true, endpoint, data, dataLength);
+
+ OIC_LOG(ERROR, TAG, "TCP adapter does not support multicast sending!");
+ return 0;
}
CAResult_t CAReadTCPData()
{
CAIPStopNetworkMonitor(CA_ADAPTER_TCP);
+ /* Some times send queue thread fails to terminate as it's worker
+ thread gets blocked at TCP session's socket connect operation.
+ So closing sockets which are in connect operation at the time
+ of termination of adapter would save send queue thread from
+ getting blocked. */
+ CATCPCloseInProgressConnections();
+
#ifndef SINGLE_THREAD
- if (g_sendQueueHandle && g_sendQueueHandle->threadMutex)
+ // Stop send queue thread.
+ if (g_sendQueueHandle != NULL)
{
- CAQueueingThreadStop(g_sendQueueHandle);
+ // g_sendQueueHandle is set to NULL to prevent new requests from being enqueued.
+ CAQueueingThread_t *queueHandle = g_sendQueueHandle;
+ g_sendQueueHandle = NULL;
+
+ if (queueHandle->threadMutex)
+ {
+ CAQueueingThreadStop(queueHandle);
+ }
+ CATCPDeinitializeQueueHandles(queueHandle);
}
- CATCPDeinitializeQueueHandles();
#endif
+ // Close TCP servers and established connections.
CATCPStopServer();
- //Re-initializing the Globals to start them again
+ // Re-initializing the Globals to start them again.
CAInitializeTCPGlobals();
return CA_STATUS_OK;
CATCPDestroyMutex();
CATCPDestroyCond();
+
+ CATCPDestroySendMutex();
+ CATCPDestroySendCond();
+
+ g_skipCloseOnIFDown = false;
+
+ // Free adapter mutex
+ if (g_mutexAdapter)
+ {
+ oc_mutex_free(g_mutexAdapter);
+ g_mutexAdapter = NULL;
+ }
}
void CATCPSendDataThread(void *threadData)