1 /* ****************************************************************
3 * Copyright 2015 Samsung Electronics All Rights Reserved.
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
19 ******************************************************************/
26 #ifndef __STDC_FORMAT_MACROS
27 #define __STDC_FORMAT_MACROS
31 #include "cainterface.h"
32 #include "caipnwmonitor.h"
33 #include "catcpadapter.h"
34 #include "catcpinterface.h"
35 #include "caqueueingthread.h"
36 #include "caadapterutils.h"
38 #include "uarraylist.h"
39 #include "caremotehandler.h"
41 #include "oic_malloc.h"
43 #include "ca_adapter_net_ssl.h"
47 * Logging tag for module name.
49 #define TAG "OIC_CA_TCP_ADAP"
52 * Holds internal thread TCP data information.
56 CAEndpoint_t *remoteEndpoint;
62 #define CA_TCP_LISTEN_BACKLOG 3
64 #define CA_TCP_SELECT_TIMEOUT 10
67 * Queue handle for Send Data.
69 static CAQueueingThread_t *g_sendQueueHandle = NULL;
72 * Network Packet Received Callback to CA.
74 static CANetworkPacketReceivedCallback g_networkPacketCallback = NULL;
77 * Adapter Changed Callback to CA.
79 static CAAdapterChangeCallback g_networkChangeCallback = NULL;
82 * Connection Changed Callback to CA.
84 static CAConnectionChangeCallback g_connectionChangeCallback = NULL;
87 * error Callback to CA adapter.
89 static CAErrorHandleCallback g_errorCallback = NULL;
92 * KeepAlive Connected or Disconnected Callback to CA adapter.
94 static CAKeepAliveConnectionCallback g_connKeepAliveCallback = NULL;
96 static CAResult_t CATCPPacketReceivedCB(const CASecureEndpoint_t *sep,
97 const void *data, uint32_t dataLength);
99 static void CATCPErrorHandler(const CAEndpoint_t *endpoint, const void *data,
100 size_t dataLength, CAResult_t result);
102 static CAResult_t CATCPInitializeQueueHandles();
104 static void CATCPDeinitializeQueueHandles();
106 static void CATCPSendDataThread(void *threadData);
108 static CATCPData *CACreateTCPData(const CAEndpoint_t *remoteEndpoint,
109 const void *data, size_t dataLength,
111 void CAFreeTCPData(CATCPData *ipData);
113 static void CADataDestroyer(void *data, uint32_t size);
115 CAResult_t CATCPInitializeQueueHandles()
117 // Check if the message queue is already initialized
118 if (g_sendQueueHandle)
120 OIC_LOG(DEBUG, TAG, "send queue handle is already initialized!");
124 // Create send message queue
125 g_sendQueueHandle = OICMalloc(sizeof(CAQueueingThread_t));
126 if (!g_sendQueueHandle)
128 OIC_LOG(ERROR, TAG, "Memory allocation failed!");
129 return CA_MEMORY_ALLOC_FAILED;
132 if (CA_STATUS_OK != CAQueueingThreadInitialize(g_sendQueueHandle,
133 (const ca_thread_pool_t)caglobals.tcp.threadpool,
134 CATCPSendDataThread, CADataDestroyer))
136 OIC_LOG(ERROR, TAG, "Failed to Initialize send queue thread");
137 OICFree(g_sendQueueHandle);
138 g_sendQueueHandle = NULL;
139 return CA_STATUS_FAILED;
145 void CATCPDeinitializeQueueHandles()
147 CAQueueingThreadDestroy(g_sendQueueHandle);
148 OICFree(g_sendQueueHandle);
149 g_sendQueueHandle = NULL;
152 void CATCPConnectionStateCB(const char *ipAddress, CANetworkStatus_t status)
158 CAResult_t CATCPPacketReceivedCB(const CASecureEndpoint_t *sep, const void *data,
161 VERIFY_NON_NULL(sep, TAG, "sep is NULL");
162 VERIFY_NON_NULL(data, TAG, "data is NULL");
164 OIC_LOG_V(DEBUG, TAG, "Address: %s, port:%d", sep->endpoint.addr, sep->endpoint.port);
166 CAResult_t res = CA_STATUS_OK;
168 if (g_networkPacketCallback)
170 res = g_networkPacketCallback(sep, data, dataLength);
171 if (CA_STATUS_OK != res)
173 OIC_LOG(ERROR, TAG, "Error parsing CoAP data");
177 unsigned char *buffer = (unsigned char*)data;
178 size_t bufferLen = dataLength;
181 //get remote device information from file descriptor.
182 CATCPSessionInfo_t *svritem = CAGetTCPSessionInfoFromEndpoint(&sep->endpoint, &index);
185 OIC_LOG(ERROR, TAG, "there is no connection information in list");
186 return CA_STATUS_INVALID_PARAM;
188 if (UNKNOWN == svritem->protocol)
190 OIC_LOG(ERROR, TAG, "invalid protocol type");
191 return CA_STATUS_INVALID_PARAM;
194 //totalLen filled only when header fully read and parsed
195 while (0 != bufferLen)
197 res = CAConstructCoAP(svritem, &buffer, &bufferLen);
198 if (CA_STATUS_OK != res)
200 OIC_LOG_V(ERROR, TAG, "CAConstructCoAP return error : %d", res);
204 //when successfully read all required data - pass them to upper layer.
205 if (svritem->len == svritem->totalLen)
207 if (g_networkPacketCallback)
209 res = g_networkPacketCallback(sep, svritem->data, svritem->totalLen);
210 if (CA_STATUS_OK != res)
212 OIC_LOG(ERROR, TAG, "Error parsing CoAP data");
216 CACleanData(svritem);
220 OIC_LOG_V(DEBUG, TAG, "%u bytes required for complete CoAP",
221 svritem->totalLen - svritem->len);
229 static ssize_t CATCPPacketSendCB(CAEndpoint_t *endpoint, const void *data, size_t dataLength)
231 OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
232 VERIFY_NON_NULL_RET(endpoint, TAG, "endpoint is NULL", -1);
233 VERIFY_NON_NULL_RET(data, TAG, "data is NULL", -1);
235 OIC_LOG_V(DEBUG, TAG, "Address: %s, port:%d", endpoint->addr, endpoint->port);
236 OIC_LOG_BUFFER(DEBUG, TAG, data, dataLength);
238 ssize_t ret = CATCPSendData(endpoint, data, dataLength);
239 OIC_LOG_V(DEBUG, TAG, "Out %s : %d bytes sent", __func__, ret);
244 static void CATCPErrorHandler(const CAEndpoint_t *endpoint, const void *data,
245 size_t dataLength, CAResult_t result)
247 VERIFY_NON_NULL_VOID(endpoint, TAG, "endpoint is NULL");
248 VERIFY_NON_NULL_VOID(data, TAG, "data is NULL");
252 g_errorCallback(endpoint, data, dataLength, result);
256 static void CATCPConnectionHandler(const CAEndpoint_t *endpoint, bool isConnected, bool isClient)
258 // Pass the changed connection status to RI Layer for keepalive.
259 if (g_connKeepAliveCallback)
261 g_connKeepAliveCallback(endpoint, isConnected, isClient);
264 // Pass the changed connection status to CAUtil.
265 if (g_connectionChangeCallback)
267 g_connectionChangeCallback(endpoint, isConnected);
271 void CATCPSetKeepAliveCallbacks(CAKeepAliveConnectionCallback ConnHandler)
273 g_connKeepAliveCallback = ConnHandler;
276 void CATCPAdapterHandler(CATransportAdapter_t adapter, CANetworkStatus_t status)
278 if (g_networkChangeCallback)
280 g_networkChangeCallback(adapter, status);
283 if (CA_INTERFACE_DOWN == status)
285 OIC_LOG(INFO, TAG, "Network status is down, close all session");
287 CAResult_t res = CAQueueingThreadClearData(g_sendQueueHandle);
288 if (res != CA_STATUS_OK)
290 OIC_LOG_V(ERROR, TAG, "CAQueueingThreadClearData failed[%d]", res);
295 else if (CA_INTERFACE_UP == status)
297 OIC_LOG(INFO, TAG, "Network status is up, create new socket for listening");
299 CAResult_t ret = CA_STATUS_FAILED;
300 #ifndef SINGLE_THREAD
301 ret = CATCPStartServer((const ca_thread_pool_t)caglobals.tcp.threadpool);
303 ret = CATCPStartServer();
305 if (CA_STATUS_OK != ret)
307 OIC_LOG_V(ERROR, TAG, "CATCPStartServer failed[%d]", ret);
312 static void CAInitializeTCPGlobals()
314 caglobals.tcp.ipv4.fd = -1;
315 caglobals.tcp.ipv4s.fd = -1;
316 caglobals.tcp.ipv6.fd = -1;
317 caglobals.tcp.ipv6s.fd = -1;
319 // Set the port number received from application.
320 caglobals.tcp.ipv4.port = caglobals.ports.tcp.u4;
321 caglobals.tcp.ipv4s.port = caglobals.ports.tcp.u4s;
322 caglobals.tcp.ipv6.port = caglobals.ports.tcp.u6;
323 caglobals.tcp.ipv6s.port = caglobals.ports.tcp.u6s;
325 caglobals.tcp.selectTimeout = CA_TCP_SELECT_TIMEOUT;
326 caglobals.tcp.listenBacklog = CA_TCP_LISTEN_BACKLOG;
327 caglobals.tcp.svrlist = NULL;
329 CATransportFlags_t flags = 0;
330 if (caglobals.client)
332 flags |= caglobals.clientFlags;
334 if (caglobals.server)
336 flags |= caglobals.serverFlags;
339 caglobals.tcp.ipv4tcpenabled = flags & CA_IPV4;
340 caglobals.tcp.ipv6tcpenabled = flags & CA_IPV6;
343 CAResult_t CAInitializeTCP(CARegisterConnectivityCallback registerCallback,
344 CANetworkPacketReceivedCallback networkPacketCallback,
345 CAAdapterChangeCallback netCallback,
346 CAConnectionChangeCallback connCallback,
347 CAErrorHandleCallback errorCallback, ca_thread_pool_t handle)
349 OIC_LOG(DEBUG, TAG, "IN");
350 VERIFY_NON_NULL(registerCallback, TAG, "registerCallback");
351 VERIFY_NON_NULL(networkPacketCallback, TAG, "networkPacketCallback");
352 VERIFY_NON_NULL(netCallback, TAG, "netCallback");
353 #ifndef SINGLE_THREAD
354 VERIFY_NON_NULL(handle, TAG, "thread pool handle");
357 g_networkChangeCallback = netCallback;
358 g_connectionChangeCallback = connCallback;
359 g_networkPacketCallback = networkPacketCallback;
360 g_errorCallback = errorCallback;
362 CAInitializeTCPGlobals();
364 CAResult_t res = CATCPCreateMutex();
365 if (CA_STATUS_OK == res)
367 res = CATCPCreateCond();
369 if (CA_STATUS_OK != res)
371 OIC_LOG(ERROR, TAG, "failed to create mutex/cond");
377 #ifndef SINGLE_THREAD
378 caglobals.tcp.threadpool = handle;
381 CATCPSetConnectionChangedCallback(CATCPConnectionHandler);
382 CATCPSetPacketReceiveCallback(CATCPPacketReceivedCB);
383 CATCPSetErrorHandler(CATCPErrorHandler);
386 CAsetSslAdapterCallbacks(CATCPPacketReceivedCB, CATCPPacketSendCB, CA_ADAPTER_TCP);
389 CAConnectivityHandler_t tcpHandler = {
390 .startAdapter = CAStartTCP,
391 .startListenServer = CAStartTCPListeningServer,
392 .stopListenServer = CAStopTCPListeningServer,
393 .startDiscoveryServer = CAStartTCPDiscoveryServer,
394 .sendData = CASendTCPUnicastData,
395 .sendDataToAll = CASendTCPMulticastData,
396 .GetnetInfo = CAGetTCPInterfaceInformation,
397 .readData = CAReadTCPData,
398 .stopAdapter = CAStopTCP,
399 .terminate = CATerminateTCP,
400 .cType = CA_ADAPTER_TCP};
402 registerCallback(tcpHandler);
404 OIC_LOG(INFO, TAG, "OUT IntializeTCP is Success");
408 CAResult_t CAStartTCP()
410 OIC_LOG(DEBUG, TAG, "IN");
412 #ifndef SINGLE_THREAD
413 if (CA_STATUS_OK != CATCPInitializeQueueHandles())
415 OIC_LOG(ERROR, TAG, "Failed to Initialize Queue Handle");
417 return CA_STATUS_FAILED;
420 // Start send queue thread
422 if (CA_STATUS_OK != CAQueueingThreadStart(g_sendQueueHandle))
424 if (CA_STATUS_OK != CAQueueingThreadStart(g_sendQueueHandle, "IoT_TCPSendQueue"))
427 OIC_LOG(ERROR, TAG, "Failed to Start Send Data Thread");
428 return CA_STATUS_FAILED;
431 CAResult_t ret = CATCPStartServer();
432 if (CA_STATUS_OK != ret)
434 OIC_LOG_V(DEBUG, TAG, "CATCPStartServer failed[%d]", ret);
439 // Start network monitoring to receive adapter status changes.
440 CAIPStartNetworkMonitor(CATCPAdapterHandler, CA_ADAPTER_TCP);
445 static bool CAClearQueueEndpointDataContext(void *data, uint32_t size, void *ctx)
449 if (NULL == data || NULL == ctx)
454 CATCPData *tcpData = (CATCPData *)data;
455 CAEndpoint_t *endpoint = (CAEndpoint_t *)ctx;
457 if (NULL != tcpData && NULL != tcpData->remoteEndpoint)
459 if (strcmp(tcpData->remoteEndpoint->addr, endpoint->addr) == 0
460 && tcpData->remoteEndpoint->port == endpoint->port)
468 CAResult_t CATCPDisconnectSession(const CAEndpoint_t *endpoint)
470 CAResult_t res = CAQueueingThreadClearContextData(g_sendQueueHandle,
471 CAClearQueueEndpointDataContext,
473 if (CA_STATUS_OK != res)
475 OIC_LOG(ERROR, TAG, "failed to clear context data");
479 res = CAcloseSslConnection(endpoint);
480 if (CA_STATUS_OK != res)
482 OIC_LOG(ERROR, TAG, "failed to close TLS session");
487 res = CASearchAndDeleteTCPSession(endpoint);
488 if (CA_STATUS_OK != res)
490 OIC_LOG(ERROR, TAG, "failed to close TCP session");
496 CAResult_t CAStartTCPListeningServer()
498 #ifndef SINGLE_THREAD
499 if (!caglobals.server)
501 caglobals.server = true; // only needed to run CA tests
504 CAResult_t ret = CATCPStartServer((const ca_thread_pool_t)caglobals.tcp.threadpool);
505 if (CA_STATUS_OK != ret)
507 OIC_LOG_V(ERROR, TAG, "Failed to start listening server![%d]", ret);
515 CAResult_t CAStopTCPListeningServer()
520 CAResult_t CAStartTCPDiscoveryServer()
522 if (!caglobals.client)
524 caglobals.client = true; // only needed to run CA tests
527 CAResult_t ret = CATCPStartServer((const ca_thread_pool_t)caglobals.tcp.threadpool);
528 if (CA_STATUS_OK != ret)
530 OIC_LOG_V(ERROR, TAG, "Failed to start discovery server![%d]", ret);
537 static size_t CAQueueTCPData(bool isMulticast, const CAEndpoint_t *endpoint,
538 const void *data, size_t dataLength)
540 VERIFY_NON_NULL_RET(endpoint, TAG, "endpoint", -1);
541 VERIFY_NON_NULL_RET(data, TAG, "data", -1);
545 OIC_LOG(ERROR, TAG, "Invalid Data Length");
549 VERIFY_NON_NULL_RET(g_sendQueueHandle, TAG, "sendQueueHandle", -1);
551 // Create TCPData to add to queue
552 CATCPData *tcpData = CACreateTCPData(endpoint, data, dataLength, isMulticast);
555 OIC_LOG(ERROR, TAG, "Failed to create ipData!");
558 // Add message to send queue
559 CAQueueingThreadAddData(g_sendQueueHandle, tcpData, sizeof(CATCPData));
564 int32_t CASendTCPUnicastData(const CAEndpoint_t *endpoint,
565 const void *data, uint32_t dataLength,
566 CADataType_t dataType)
568 OIC_LOG(DEBUG, TAG, "IN");
570 #ifndef SINGLE_THREAD
571 return CAQueueTCPData(false, endpoint, data, dataLength);
573 return CATCPSendData(endpoint, data, dataLength);
577 int32_t CASendTCPMulticastData(const CAEndpoint_t *endpoint,
578 const void *data, uint32_t dataLength,
579 CADataType_t dataType)
582 return CAQueueTCPData(true, endpoint, data, dataLength);
585 CAResult_t CAReadTCPData()
587 OIC_LOG(DEBUG, TAG, "IN");
594 CAResult_t CAStopTCP()
596 CAIPStopNetworkMonitor(CA_ADAPTER_TCP);
598 /* Some times send queue thread fails to terminate as it's worker
599 thread gets blocked at TCP session's socket connect operation.
600 So closing sockets which are in connect operation at the time
601 of termination of adapter would save send queue thread from
603 CATCPCloseInProgressConnections();
605 #ifndef SINGLE_THREAD
606 // Stop send queue thread.
607 if (g_sendQueueHandle && g_sendQueueHandle->threadMutex)
609 CAQueueingThreadStop(g_sendQueueHandle);
611 CATCPDeinitializeQueueHandles();
614 // Close TCP servers and established connections.
617 // Re-initializing the Globals to start them again.
618 CAInitializeTCPGlobals();
623 void CATerminateTCP()
625 CATCPSetPacketReceiveCallback(NULL);
631 void CATCPSendDataThread(void *threadData)
633 CATCPData *tcpData = (CATCPData *) threadData;
636 OIC_LOG(DEBUG, TAG, "Invalid TCP data!");
640 if (caglobals.tcp.terminate)
642 OIC_LOG(DEBUG, TAG, "Adapter is not enabled");
643 CATCPErrorHandler(tcpData->remoteEndpoint, tcpData->data, tcpData->dataLen,
648 if (tcpData->isMulticast)
650 //Processing for sending multicast
651 OIC_LOG(DEBUG, TAG, "Send Multicast Data is called, not supported");
657 if (tcpData->remoteEndpoint && tcpData->remoteEndpoint->flags & CA_SECURE)
659 CAResult_t result = CA_STATUS_OK;
660 OIC_LOG(DEBUG, TAG, "CAencryptSsl called!");
661 result = CAencryptSsl(tcpData->remoteEndpoint, tcpData->data, tcpData->dataLen);
663 if (CA_STATUS_OK != result)
665 OIC_LOG(ERROR, TAG, "CAAdapterNetDtlsEncrypt failed!");
666 CASearchAndDeleteTCPSession(tcpData->remoteEndpoint);
667 CATCPErrorHandler(tcpData->remoteEndpoint, tcpData->data, tcpData->dataLen,
670 OIC_LOG_V(DEBUG, TAG,
671 "CAAdapterNetDtlsEncrypt returned with result[%d]", result);
675 //Processing for sending unicast
676 ssize_t dlen = CATCPSendData(tcpData->remoteEndpoint, tcpData->data, tcpData->dataLen);
679 OIC_LOG(ERROR, TAG, "CATCPSendData failed");
680 CASearchAndDeleteTCPSession(tcpData->remoteEndpoint);
681 CATCPErrorHandler(tcpData->remoteEndpoint, tcpData->data, tcpData->dataLen,
687 CATCPData *CACreateTCPData(const CAEndpoint_t *remoteEndpoint, const void *data,
688 size_t dataLength, bool isMulticast)
690 VERIFY_NON_NULL_RET(remoteEndpoint, TAG, "remoteEndpoint is NULL", NULL);
691 VERIFY_NON_NULL_RET(data, TAG, "data is NULL", NULL);
693 CATCPData *tcpData = (CATCPData *) OICCalloc(1, sizeof(*tcpData));
696 OIC_LOG(ERROR, TAG, "Memory allocation failed!");
700 tcpData->remoteEndpoint = CACloneEndpoint(remoteEndpoint);
701 tcpData->data = (void *) OICMalloc(dataLength);
704 OIC_LOG(ERROR, TAG, "Memory allocation failed!");
705 CAFreeTCPData(tcpData);
709 memcpy(tcpData->data, data, dataLength);
710 tcpData->dataLen = dataLength;
712 tcpData->isMulticast = isMulticast;
717 void CAFreeTCPData(CATCPData *tcpData)
719 VERIFY_NON_NULL_VOID(tcpData, TAG, "tcpData is NULL");
721 CAFreeEndpoint(tcpData->remoteEndpoint);
722 OICFree(tcpData->data);
726 void CADataDestroyer(void *data, uint32_t size)
728 if (size < sizeof(CATCPData))
731 OIC_LOG_V(ERROR, TAG, "Destroy data too small %p %" PRIu32, data, size);
734 CATCPData *TCPData = (CATCPData *) data;
736 CAFreeTCPData(TCPData);
740 size_t CAGetTotalLengthFromPacketHeader(const unsigned char *recvBuffer, size_t size)
742 OIC_LOG(DEBUG, TAG, "IN - CAGetTotalLengthFromHeader");
744 if (NULL == recvBuffer || !size)
746 OIC_LOG(ERROR, TAG, "recvBuffer is NULL");
750 coap_transport_t transport = coap_get_tcp_header_type_from_initbyte(
751 ((unsigned char *)recvBuffer)[0] >> 4);
752 size_t optPaylaodLen = coap_get_length_from_header((unsigned char *)recvBuffer,
754 size_t headerLen = coap_get_tcp_header_length((unsigned char *)recvBuffer);
756 OIC_LOG_V(DEBUG, TAG, "option/paylaod length [%d]", optPaylaodLen);
757 OIC_LOG_V(DEBUG, TAG, "header length [%d]", headerLen);
758 OIC_LOG_V(DEBUG, TAG, "total data length [%d]", headerLen + optPaylaodLen);
760 OIC_LOG(DEBUG, TAG, "OUT - CAGetTotalLengthFromHeader");
761 return headerLen + optPaylaodLen;
764 void CAGetTCPHeaderDetails(unsigned char* recvBuffer, coap_transport_t *transport,
767 if (NULL == recvBuffer)
769 OIC_LOG(ERROR, TAG, "recvBuffer is NULL");
773 if (NULL == transport)
775 OIC_LOG(ERROR, TAG, "transport is NULL");
779 if (NULL == headerlen)
781 OIC_LOG(ERROR, TAG, "headerlen is NULL");
785 *transport = coap_get_tcp_header_type_from_initbyte(
786 ((unsigned char *)recvBuffer)[0] >> 4);
787 *headerlen = coap_get_tcp_header_length_for_transport(*transport);