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 = CA_STATUS_OK;
472 res = CAcloseSslConnection(endpoint);
473 if (CA_STATUS_OK != res)
475 OIC_LOG(ERROR, TAG, "failed to close TLS session");
476 res = CAQueueingThreadClearContextData(g_sendQueueHandle,
477 CAClearQueueEndpointDataContext,
479 if (CA_STATUS_OK != res)
481 OIC_LOG(ERROR, TAG, "failed to clear context data");
488 res = CASearchAndDeleteTCPSession(endpoint);
489 if (CA_STATUS_OK != res)
491 OIC_LOG(ERROR, TAG, "failed to close TCP session");
494 res = CAQueueingThreadClearContextData(g_sendQueueHandle,
495 CAClearQueueEndpointDataContext,
497 if (CA_STATUS_OK != res)
499 OIC_LOG(ERROR, TAG, "failed to clear context data");
505 CAResult_t CAStartTCPListeningServer()
507 #ifndef SINGLE_THREAD
508 if (!caglobals.server)
510 caglobals.server = true; // only needed to run CA tests
513 CAResult_t ret = CATCPStartServer((const ca_thread_pool_t)caglobals.tcp.threadpool);
514 if (CA_STATUS_OK != ret)
516 OIC_LOG_V(ERROR, TAG, "Failed to start listening server![%d]", ret);
524 CAResult_t CAStopTCPListeningServer()
529 CAResult_t CAStartTCPDiscoveryServer()
531 if (!caglobals.client)
533 caglobals.client = true; // only needed to run CA tests
536 CAResult_t ret = CATCPStartServer((const ca_thread_pool_t)caglobals.tcp.threadpool);
537 if (CA_STATUS_OK != ret)
539 OIC_LOG_V(ERROR, TAG, "Failed to start discovery server![%d]", ret);
546 static size_t CAQueueTCPData(bool isMulticast, const CAEndpoint_t *endpoint,
547 const void *data, size_t dataLength)
549 VERIFY_NON_NULL_RET(endpoint, TAG, "endpoint", -1);
550 VERIFY_NON_NULL_RET(data, TAG, "data", -1);
554 OIC_LOG(ERROR, TAG, "Invalid Data Length");
558 VERIFY_NON_NULL_RET(g_sendQueueHandle, TAG, "sendQueueHandle", -1);
560 // Create TCPData to add to queue
561 CATCPData *tcpData = CACreateTCPData(endpoint, data, dataLength, isMulticast);
564 OIC_LOG(ERROR, TAG, "Failed to create ipData!");
567 // Add message to send queue
568 CAQueueingThreadAddData(g_sendQueueHandle, tcpData, sizeof(CATCPData));
573 int32_t CASendTCPUnicastData(const CAEndpoint_t *endpoint,
574 const void *data, uint32_t dataLength,
575 CADataType_t dataType)
577 OIC_LOG(DEBUG, TAG, "IN");
579 #ifndef SINGLE_THREAD
580 return CAQueueTCPData(false, endpoint, data, dataLength);
582 return CATCPSendData(endpoint, data, dataLength);
586 int32_t CASendTCPMulticastData(const CAEndpoint_t *endpoint,
587 const void *data, uint32_t dataLength,
588 CADataType_t dataType)
591 return CAQueueTCPData(true, endpoint, data, dataLength);
594 CAResult_t CAReadTCPData()
596 OIC_LOG(DEBUG, TAG, "IN");
603 CAResult_t CAStopTCP()
605 CAIPStopNetworkMonitor(CA_ADAPTER_TCP);
607 /* Some times send queue thread fails to terminate as it's worker
608 thread gets blocked at TCP session's socket connect operation.
609 So closing sockets which are in connect operation at the time
610 of termination of adapter would save send queue thread from
612 CATCPCloseInProgressConnections();
614 #ifndef SINGLE_THREAD
615 // Stop send queue thread.
616 if (g_sendQueueHandle && g_sendQueueHandle->threadMutex)
618 CAQueueingThreadStop(g_sendQueueHandle);
620 CATCPDeinitializeQueueHandles();
623 // Close TCP servers and established connections.
626 // Re-initializing the Globals to start them again.
627 CAInitializeTCPGlobals();
632 void CATerminateTCP()
634 CATCPSetPacketReceiveCallback(NULL);
640 void CATCPSendDataThread(void *threadData)
642 CATCPData *tcpData = (CATCPData *) threadData;
645 OIC_LOG(DEBUG, TAG, "Invalid TCP data!");
649 if (caglobals.tcp.terminate)
651 OIC_LOG(DEBUG, TAG, "Adapter is not enabled");
652 CATCPErrorHandler(tcpData->remoteEndpoint, tcpData->data, tcpData->dataLen,
657 if (tcpData->isMulticast)
659 //Processing for sending multicast
660 OIC_LOG(DEBUG, TAG, "Send Multicast Data is called, not supported");
666 if (tcpData->remoteEndpoint && tcpData->remoteEndpoint->flags & CA_SECURE)
668 CAResult_t result = CA_STATUS_OK;
669 OIC_LOG(DEBUG, TAG, "CAencryptSsl called!");
670 result = CAencryptSsl(tcpData->remoteEndpoint, tcpData->data, tcpData->dataLen);
672 if (CA_STATUS_OK != result)
674 OIC_LOG(ERROR, TAG, "CAAdapterNetDtlsEncrypt failed!");
675 CASearchAndDeleteTCPSession(tcpData->remoteEndpoint);
676 CATCPErrorHandler(tcpData->remoteEndpoint, tcpData->data, tcpData->dataLen,
679 OIC_LOG_V(DEBUG, TAG,
680 "CAAdapterNetDtlsEncrypt returned with result[%d]", result);
684 //Processing for sending unicast
685 ssize_t dlen = CATCPSendData(tcpData->remoteEndpoint, tcpData->data, tcpData->dataLen);
688 OIC_LOG(ERROR, TAG, "CATCPSendData failed");
689 CASearchAndDeleteTCPSession(tcpData->remoteEndpoint);
690 CATCPErrorHandler(tcpData->remoteEndpoint, tcpData->data, tcpData->dataLen,
696 CATCPData *CACreateTCPData(const CAEndpoint_t *remoteEndpoint, const void *data,
697 size_t dataLength, bool isMulticast)
699 VERIFY_NON_NULL_RET(remoteEndpoint, TAG, "remoteEndpoint is NULL", NULL);
700 VERIFY_NON_NULL_RET(data, TAG, "data is NULL", NULL);
702 CATCPData *tcpData = (CATCPData *) OICCalloc(1, sizeof(*tcpData));
705 OIC_LOG(ERROR, TAG, "Memory allocation failed!");
709 tcpData->remoteEndpoint = CACloneEndpoint(remoteEndpoint);
710 tcpData->data = (void *) OICMalloc(dataLength);
713 OIC_LOG(ERROR, TAG, "Memory allocation failed!");
714 CAFreeTCPData(tcpData);
718 memcpy(tcpData->data, data, dataLength);
719 tcpData->dataLen = dataLength;
721 tcpData->isMulticast = isMulticast;
726 void CAFreeTCPData(CATCPData *tcpData)
728 VERIFY_NON_NULL_VOID(tcpData, TAG, "tcpData is NULL");
730 CAFreeEndpoint(tcpData->remoteEndpoint);
731 OICFree(tcpData->data);
735 void CADataDestroyer(void *data, uint32_t size)
737 if (size < sizeof(CATCPData))
740 OIC_LOG_V(ERROR, TAG, "Destroy data too small %p %" PRIu32, data, size);
743 CATCPData *TCPData = (CATCPData *) data;
745 CAFreeTCPData(TCPData);
749 size_t CAGetTotalLengthFromPacketHeader(const unsigned char *recvBuffer, size_t size)
751 OIC_LOG(DEBUG, TAG, "IN - CAGetTotalLengthFromHeader");
753 if (NULL == recvBuffer || !size)
755 OIC_LOG(ERROR, TAG, "recvBuffer is NULL");
759 coap_transport_t transport = coap_get_tcp_header_type_from_initbyte(
760 ((unsigned char *)recvBuffer)[0] >> 4);
761 size_t optPaylaodLen = coap_get_length_from_header((unsigned char *)recvBuffer,
763 size_t headerLen = coap_get_tcp_header_length((unsigned char *)recvBuffer);
765 OIC_LOG_V(DEBUG, TAG, "option/paylaod length [%d]", optPaylaodLen);
766 OIC_LOG_V(DEBUG, TAG, "header length [%d]", headerLen);
767 OIC_LOG_V(DEBUG, TAG, "total data length [%d]", headerLen + optPaylaodLen);
769 OIC_LOG(DEBUG, TAG, "OUT - CAGetTotalLengthFromHeader");
770 return headerLen + optPaylaodLen;
773 void CAGetTCPHeaderDetails(unsigned char* recvBuffer, coap_transport_t *transport,
776 if (NULL == recvBuffer)
778 OIC_LOG(ERROR, TAG, "recvBuffer is NULL");
782 if (NULL == transport)
784 OIC_LOG(ERROR, TAG, "transport is NULL");
788 if (NULL == headerlen)
790 OIC_LOG(ERROR, TAG, "headerlen is NULL");
794 *transport = coap_get_tcp_header_type_from_initbyte(
795 ((unsigned char *)recvBuffer)[0] >> 4);
796 *headerlen = coap_get_tcp_header_length_for_transport(*transport);