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 res = CATCPCreateSendMutex();
378 if (CA_STATUS_OK == res)
380 res = CATCPCreateSendCond();
382 if (CA_STATUS_OK != res)
384 OIC_LOG(ERROR, TAG, "failed to create send data mutex/cond");
387 CATCPDestroySendMutex();
388 CATCPDestroySendCond();
392 #ifndef SINGLE_THREAD
393 caglobals.tcp.threadpool = handle;
396 CATCPSetConnectionChangedCallback(CATCPConnectionHandler);
397 CATCPSetPacketReceiveCallback(CATCPPacketReceivedCB);
398 CATCPSetErrorHandler(CATCPErrorHandler);
401 CAsetSslAdapterCallbacks(CATCPPacketReceivedCB, CATCPPacketSendCB, CA_ADAPTER_TCP);
404 CAConnectivityHandler_t tcpHandler = {
405 .startAdapter = CAStartTCP,
406 .startListenServer = CAStartTCPListeningServer,
407 .stopListenServer = CAStopTCPListeningServer,
408 .startDiscoveryServer = CAStartTCPDiscoveryServer,
409 .sendData = CASendTCPUnicastData,
410 .sendDataToAll = CASendTCPMulticastData,
411 .GetnetInfo = CAGetTCPInterfaceInformation,
412 .readData = CAReadTCPData,
413 .stopAdapter = CAStopTCP,
414 .terminate = CATerminateTCP,
415 .cType = CA_ADAPTER_TCP};
417 registerCallback(tcpHandler);
419 OIC_LOG(INFO, TAG, "OUT IntializeTCP is Success");
423 CAResult_t CAStartTCP()
425 OIC_LOG(DEBUG, TAG, "IN");
427 #ifndef SINGLE_THREAD
428 if (CA_STATUS_OK != CATCPInitializeQueueHandles())
430 OIC_LOG(ERROR, TAG, "Failed to Initialize Queue Handle");
432 return CA_STATUS_FAILED;
435 // Start send queue thread
437 if (CA_STATUS_OK != CAQueueingThreadStart(g_sendQueueHandle))
439 if (CA_STATUS_OK != CAQueueingThreadStart(g_sendQueueHandle, "IoT_TCPSendQueue"))
442 OIC_LOG(ERROR, TAG, "Failed to Start Send Data Thread");
443 return CA_STATUS_FAILED;
446 CAResult_t ret = CATCPStartServer();
447 if (CA_STATUS_OK != ret)
449 OIC_LOG_V(DEBUG, TAG, "CATCPStartServer failed[%d]", ret);
454 // Start network monitoring to receive adapter status changes.
455 CAIPStartNetworkMonitor(CATCPAdapterHandler, CA_ADAPTER_TCP);
460 static bool CAClearQueueEndpointDataContext(void *data, uint32_t size, void *ctx)
464 if (NULL == data || NULL == ctx)
469 CATCPData *tcpData = (CATCPData *)data;
470 CAEndpoint_t *endpoint = (CAEndpoint_t *)ctx;
472 if (NULL != tcpData && NULL != tcpData->remoteEndpoint)
474 if (strcmp(tcpData->remoteEndpoint->addr, endpoint->addr) == 0
475 && tcpData->remoteEndpoint->port == endpoint->port)
483 CAResult_t CATCPDisconnectSession(const CAEndpoint_t *endpoint)
485 CAResult_t res = CAQueueingThreadClearContextData(g_sendQueueHandle,
486 CAClearQueueEndpointDataContext,
488 if (CA_STATUS_OK != res)
490 OIC_LOG(ERROR, TAG, "failed to clear context data");
494 res = CAcloseSslConnection(endpoint);
495 if (CA_STATUS_OK != res)
497 OIC_LOG(ERROR, TAG, "failed to close TLS session");
501 res = CASearchAndDeleteTCPSession(endpoint);
502 if (CA_STATUS_OK != res)
504 OIC_LOG(ERROR, TAG, "failed to close TCP session");
510 CAResult_t CAStartTCPListeningServer()
512 #ifndef SINGLE_THREAD
513 if (!caglobals.server)
515 caglobals.server = true; // only needed to run CA tests
518 CAResult_t ret = CATCPStartServer((const ca_thread_pool_t)caglobals.tcp.threadpool);
519 if (CA_STATUS_OK != ret)
521 OIC_LOG_V(ERROR, TAG, "Failed to start listening server![%d]", ret);
529 CAResult_t CAStopTCPListeningServer()
534 CAResult_t CAStartTCPDiscoveryServer()
536 if (!caglobals.client)
538 caglobals.client = true; // only needed to run CA tests
541 CAResult_t ret = CATCPStartServer((const ca_thread_pool_t)caglobals.tcp.threadpool);
542 if (CA_STATUS_OK != ret)
544 OIC_LOG_V(ERROR, TAG, "Failed to start discovery server![%d]", ret);
551 static size_t CAQueueTCPData(bool isMulticast, const CAEndpoint_t *endpoint,
552 const void *data, size_t dataLength)
554 VERIFY_NON_NULL_RET(endpoint, TAG, "endpoint", -1);
555 VERIFY_NON_NULL_RET(data, TAG, "data", -1);
559 OIC_LOG(ERROR, TAG, "Invalid Data Length");
563 VERIFY_NON_NULL_RET(g_sendQueueHandle, TAG, "sendQueueHandle", -1);
565 // Create TCPData to add to queue
566 CATCPData *tcpData = CACreateTCPData(endpoint, data, dataLength, isMulticast);
569 OIC_LOG(ERROR, TAG, "Failed to create ipData!");
572 // Add message to send queue
573 CAQueueingThreadAddData(g_sendQueueHandle, tcpData, sizeof(CATCPData));
578 int32_t CASendTCPUnicastData(const CAEndpoint_t *endpoint,
579 const void *data, uint32_t dataLength,
580 CADataType_t dataType)
582 OIC_LOG(DEBUG, TAG, "IN");
584 #ifndef SINGLE_THREAD
585 return CAQueueTCPData(false, endpoint, data, dataLength);
587 return CATCPSendData(endpoint, data, dataLength);
591 int32_t CASendTCPMulticastData(const CAEndpoint_t *endpoint,
592 const void *data, uint32_t dataLength,
593 CADataType_t dataType)
596 return CAQueueTCPData(true, endpoint, data, dataLength);
599 CAResult_t CAReadTCPData()
601 OIC_LOG(DEBUG, TAG, "IN");
608 CAResult_t CAStopTCP()
610 CAIPStopNetworkMonitor(CA_ADAPTER_TCP);
612 /* Some times send queue thread fails to terminate as it's worker
613 thread gets blocked at TCP session's socket connect operation.
614 So closing sockets which are in connect operation at the time
615 of termination of adapter would save send queue thread from
617 CATCPCloseInProgressConnections();
619 #ifndef SINGLE_THREAD
620 // Stop send queue thread.
621 if (g_sendQueueHandle && g_sendQueueHandle->threadMutex)
623 CAQueueingThreadStop(g_sendQueueHandle);
625 CATCPDeinitializeQueueHandles();
628 // Close TCP servers and established connections.
631 // Re-initializing the Globals to start them again.
632 CAInitializeTCPGlobals();
637 void CATerminateTCP()
639 CATCPSetPacketReceiveCallback(NULL);
644 CATCPDestroySendMutex();
645 CATCPDestroySendCond();
648 void CATCPSendDataThread(void *threadData)
650 CATCPData *tcpData = (CATCPData *) threadData;
653 OIC_LOG(DEBUG, TAG, "Invalid TCP data!");
657 if (caglobals.tcp.terminate)
659 OIC_LOG(DEBUG, TAG, "Adapter is not enabled");
660 CATCPErrorHandler(tcpData->remoteEndpoint, tcpData->data, tcpData->dataLen,
665 if (tcpData->isMulticast)
667 //Processing for sending multicast
668 OIC_LOG(DEBUG, TAG, "Send Multicast Data is called, not supported");
674 if (tcpData->remoteEndpoint && tcpData->remoteEndpoint->flags & CA_SECURE)
676 CAResult_t result = CA_STATUS_OK;
677 OIC_LOG(DEBUG, TAG, "CAencryptSsl called!");
678 result = CAencryptSsl(tcpData->remoteEndpoint, tcpData->data, tcpData->dataLen);
680 if (CA_STATUS_OK != result)
682 OIC_LOG(ERROR, TAG, "CAAdapterNetDtlsEncrypt failed!");
683 CASearchAndDeleteTCPSession(tcpData->remoteEndpoint);
684 CATCPErrorHandler(tcpData->remoteEndpoint, tcpData->data, tcpData->dataLen,
687 OIC_LOG_V(DEBUG, TAG,
688 "CAAdapterNetDtlsEncrypt returned with result[%d]", result);
692 //Processing for sending unicast
693 ssize_t dlen = CATCPSendData(tcpData->remoteEndpoint, tcpData->data, tcpData->dataLen);
696 OIC_LOG(ERROR, TAG, "CATCPSendData failed");
697 CASearchAndDeleteTCPSession(tcpData->remoteEndpoint);
698 CATCPErrorHandler(tcpData->remoteEndpoint, tcpData->data, tcpData->dataLen,
704 CATCPData *CACreateTCPData(const CAEndpoint_t *remoteEndpoint, const void *data,
705 size_t dataLength, bool isMulticast)
707 VERIFY_NON_NULL_RET(remoteEndpoint, TAG, "remoteEndpoint is NULL", NULL);
708 VERIFY_NON_NULL_RET(data, TAG, "data is NULL", NULL);
710 CATCPData *tcpData = (CATCPData *) OICCalloc(1, sizeof(*tcpData));
713 OIC_LOG(ERROR, TAG, "Memory allocation failed!");
717 tcpData->remoteEndpoint = CACloneEndpoint(remoteEndpoint);
718 tcpData->data = (void *) OICMalloc(dataLength);
721 OIC_LOG(ERROR, TAG, "Memory allocation failed!");
722 CAFreeTCPData(tcpData);
726 memcpy(tcpData->data, data, dataLength);
727 tcpData->dataLen = dataLength;
729 tcpData->isMulticast = isMulticast;
734 void CAFreeTCPData(CATCPData *tcpData)
736 VERIFY_NON_NULL_VOID(tcpData, TAG, "tcpData is NULL");
738 CAFreeEndpoint(tcpData->remoteEndpoint);
739 OICFree(tcpData->data);
743 void CADataDestroyer(void *data, uint32_t size)
745 if (size < sizeof(CATCPData))
748 OIC_LOG_V(ERROR, TAG, "Destroy data too small %p %" PRIu32, data, size);
751 CATCPData *TCPData = (CATCPData *) data;
753 CAFreeTCPData(TCPData);
757 size_t CAGetTotalLengthFromPacketHeader(const unsigned char *recvBuffer, size_t size)
759 OIC_LOG(DEBUG, TAG, "IN - CAGetTotalLengthFromHeader");
761 if (NULL == recvBuffer || !size)
763 OIC_LOG(ERROR, TAG, "recvBuffer is NULL");
767 coap_transport_t transport = coap_get_tcp_header_type_from_initbyte(
768 ((unsigned char *)recvBuffer)[0] >> 4);
769 size_t optPaylaodLen = coap_get_length_from_header((unsigned char *)recvBuffer,
771 size_t headerLen = coap_get_tcp_header_length((unsigned char *)recvBuffer);
773 OIC_LOG_V(DEBUG, TAG, "option/paylaod length [%d]", optPaylaodLen);
774 OIC_LOG_V(DEBUG, TAG, "header length [%d]", headerLen);
775 OIC_LOG_V(DEBUG, TAG, "total data length [%d]", headerLen + optPaylaodLen);
777 OIC_LOG(DEBUG, TAG, "OUT - CAGetTotalLengthFromHeader");
778 return headerLen + optPaylaodLen;
781 void CAGetTCPHeaderDetails(unsigned char* recvBuffer, coap_transport_t *transport,
784 if (NULL == recvBuffer)
786 OIC_LOG(ERROR, TAG, "recvBuffer is NULL");
790 if (NULL == transport)
792 OIC_LOG(ERROR, TAG, "transport is NULL");
796 if (NULL == headerlen)
798 OIC_LOG(ERROR, TAG, "headerlen is NULL");
802 *transport = coap_get_tcp_header_type_from_initbyte(
803 ((unsigned char *)recvBuffer)[0] >> 4);
804 *headerlen = coap_get_tcp_header_length_for_transport(*transport);