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;
335 #ifndef DISABLE_TCP_SERVER
336 if (caglobals.server)
338 flags |= caglobals.serverFlags;
342 caglobals.tcp.ipv4tcpenabled = flags & CA_IPV4;
343 caglobals.tcp.ipv6tcpenabled = flags & CA_IPV6;
346 CAResult_t CAInitializeTCP(CARegisterConnectivityCallback registerCallback,
347 CANetworkPacketReceivedCallback networkPacketCallback,
348 CAAdapterChangeCallback netCallback,
349 CAConnectionChangeCallback connCallback,
350 CAErrorHandleCallback errorCallback, ca_thread_pool_t handle)
352 OIC_LOG(DEBUG, TAG, "IN");
353 VERIFY_NON_NULL(registerCallback, TAG, "registerCallback");
354 VERIFY_NON_NULL(networkPacketCallback, TAG, "networkPacketCallback");
355 VERIFY_NON_NULL(netCallback, TAG, "netCallback");
356 #ifndef SINGLE_THREAD
357 VERIFY_NON_NULL(handle, TAG, "thread pool handle");
360 g_networkChangeCallback = netCallback;
361 g_connectionChangeCallback = connCallback;
362 g_networkPacketCallback = networkPacketCallback;
363 g_errorCallback = errorCallback;
365 CAInitializeTCPGlobals();
367 CAResult_t res = CATCPCreateMutex();
368 if (CA_STATUS_OK == res)
370 res = CATCPCreateCond();
372 if (CA_STATUS_OK != res)
374 OIC_LOG(ERROR, TAG, "failed to create mutex/cond");
380 res = CATCPCreateSendMutex();
381 if (CA_STATUS_OK == res)
383 res = CATCPCreateSendCond();
385 if (CA_STATUS_OK != res)
387 OIC_LOG(ERROR, TAG, "failed to create send data mutex/cond");
390 CATCPDestroySendMutex();
391 CATCPDestroySendCond();
395 #ifndef SINGLE_THREAD
396 caglobals.tcp.threadpool = handle;
399 CATCPSetConnectionChangedCallback(CATCPConnectionHandler);
400 CATCPSetPacketReceiveCallback(CATCPPacketReceivedCB);
401 CATCPSetErrorHandler(CATCPErrorHandler);
404 CAsetSslAdapterCallbacks(CATCPPacketReceivedCB, CATCPPacketSendCB, CA_ADAPTER_TCP);
407 CAConnectivityHandler_t tcpHandler = {
408 .startAdapter = CAStartTCP,
409 .startListenServer = CAStartTCPListeningServer,
410 .stopListenServer = CAStopTCPListeningServer,
411 .startDiscoveryServer = CAStartTCPDiscoveryServer,
412 .sendData = CASendTCPUnicastData,
413 .sendDataToAll = CASendTCPMulticastData,
414 .GetnetInfo = CAGetTCPInterfaceInformation,
415 .readData = CAReadTCPData,
416 .stopAdapter = CAStopTCP,
417 .terminate = CATerminateTCP,
418 .cType = CA_ADAPTER_TCP};
420 registerCallback(tcpHandler);
422 OIC_LOG(INFO, TAG, "OUT IntializeTCP is Success");
426 CAResult_t CAStartTCP()
428 OIC_LOG(DEBUG, TAG, "IN");
430 #ifndef SINGLE_THREAD
431 if (CA_STATUS_OK != CATCPInitializeQueueHandles())
433 OIC_LOG(ERROR, TAG, "Failed to Initialize Queue Handle");
435 return CA_STATUS_FAILED;
438 // Start send queue thread
440 if (CA_STATUS_OK != CAQueueingThreadStart(g_sendQueueHandle))
442 if (CA_STATUS_OK != CAQueueingThreadStart(g_sendQueueHandle, "IoT_TCPSendQueue"))
445 OIC_LOG(ERROR, TAG, "Failed to Start Send Data Thread");
446 return CA_STATUS_FAILED;
449 CAResult_t ret = CATCPStartServer();
450 if (CA_STATUS_OK != ret)
452 OIC_LOG_V(DEBUG, TAG, "CATCPStartServer failed[%d]", ret);
457 // Start network monitoring to receive adapter status changes.
458 CAIPStartNetworkMonitor(CATCPAdapterHandler, CA_ADAPTER_TCP);
463 static bool CAClearQueueEndpointDataContext(void *data, uint32_t size, void *ctx)
467 if (NULL == data || NULL == ctx)
472 CATCPData *tcpData = (CATCPData *)data;
473 CAEndpoint_t *endpoint = (CAEndpoint_t *)ctx;
475 if (NULL != tcpData && NULL != tcpData->remoteEndpoint)
477 if (strcmp(tcpData->remoteEndpoint->addr, endpoint->addr) == 0
478 && tcpData->remoteEndpoint->port == endpoint->port)
486 CAResult_t CATCPDisconnectSession(const CAEndpoint_t *endpoint)
488 CAResult_t res = CAQueueingThreadClearContextData(g_sendQueueHandle,
489 CAClearQueueEndpointDataContext,
491 if (CA_STATUS_OK != res)
493 OIC_LOG(ERROR, TAG, "failed to clear context data");
497 res = CAcloseSslConnection(endpoint);
498 if (CA_STATUS_OK != res)
500 OIC_LOG(ERROR, TAG, "failed to close TLS session");
504 res = CASearchAndDeleteTCPSession(endpoint);
505 if (CA_STATUS_OK != res)
507 OIC_LOG(ERROR, TAG, "failed to close TCP session");
513 CAResult_t CAStartTCPListeningServer()
515 #if !defined(SINGLE_THREAD) && !defined(DISABLE_TCP_SERVER)
516 if (!caglobals.server)
518 caglobals.server = true; // only needed to run CA tests
521 CAResult_t ret = CATCPStartServer((const ca_thread_pool_t)caglobals.tcp.threadpool);
522 if (CA_STATUS_OK != ret)
524 OIC_LOG_V(ERROR, TAG, "Failed to start listening server![%d]", ret);
532 CAResult_t CAStopTCPListeningServer()
537 CAResult_t CAStartTCPDiscoveryServer()
539 if (!caglobals.client)
541 caglobals.client = true; // only needed to run CA tests
544 CAResult_t ret = CATCPStartServer((const ca_thread_pool_t)caglobals.tcp.threadpool);
545 if (CA_STATUS_OK != ret)
547 OIC_LOG_V(ERROR, TAG, "Failed to start discovery server![%d]", ret);
554 static size_t CAQueueTCPData(bool isMulticast, const CAEndpoint_t *endpoint,
555 const void *data, size_t dataLength)
557 VERIFY_NON_NULL_RET(endpoint, TAG, "endpoint", -1);
558 VERIFY_NON_NULL_RET(data, TAG, "data", -1);
562 OIC_LOG(ERROR, TAG, "Invalid Data Length");
566 VERIFY_NON_NULL_RET(g_sendQueueHandle, TAG, "sendQueueHandle", -1);
568 // Create TCPData to add to queue
569 CATCPData *tcpData = CACreateTCPData(endpoint, data, dataLength, isMulticast);
572 OIC_LOG(ERROR, TAG, "Failed to create ipData!");
575 // Add message to send queue
576 CAQueueingThreadAddData(g_sendQueueHandle, tcpData, sizeof(CATCPData));
581 int32_t CASendTCPUnicastData(const CAEndpoint_t *endpoint,
582 const void *data, uint32_t dataLength,
583 CADataType_t dataType)
585 OIC_LOG(DEBUG, TAG, "IN");
587 #ifndef SINGLE_THREAD
588 return CAQueueTCPData(false, endpoint, data, dataLength);
590 return CATCPSendData(endpoint, data, dataLength);
594 int32_t CASendTCPMulticastData(const CAEndpoint_t *endpoint,
595 const void *data, uint32_t dataLength,
596 CADataType_t dataType)
603 OIC_LOG(ERROR, TAG, "TCP adapter does not support multicast sending!");
607 CAResult_t CAReadTCPData()
609 OIC_LOG(DEBUG, TAG, "IN");
616 CAResult_t CAStopTCP()
618 CAIPStopNetworkMonitor(CA_ADAPTER_TCP);
620 /* Some times send queue thread fails to terminate as it's worker
621 thread gets blocked at TCP session's socket connect operation.
622 So closing sockets which are in connect operation at the time
623 of termination of adapter would save send queue thread from
625 CATCPCloseInProgressConnections();
627 #ifndef SINGLE_THREAD
628 // Stop send queue thread.
629 if (g_sendQueueHandle && g_sendQueueHandle->threadMutex)
631 CAQueueingThreadStop(g_sendQueueHandle);
633 CATCPDeinitializeQueueHandles();
636 // Close TCP servers and established connections.
639 // Re-initializing the Globals to start them again.
640 CAInitializeTCPGlobals();
645 void CATerminateTCP()
647 CATCPSetPacketReceiveCallback(NULL);
652 CATCPDestroySendMutex();
653 CATCPDestroySendCond();
656 void CATCPSendDataThread(void *threadData)
658 CATCPData *tcpData = (CATCPData *) threadData;
661 OIC_LOG(DEBUG, TAG, "Invalid TCP data!");
665 if (caglobals.tcp.terminate)
667 OIC_LOG(DEBUG, TAG, "Adapter is not enabled");
668 CATCPErrorHandler(tcpData->remoteEndpoint, tcpData->data, tcpData->dataLen,
673 if (tcpData->isMulticast)
675 //Processing for sending multicast
676 OIC_LOG(DEBUG, TAG, "Send Multicast Data is called, not supported");
682 if (tcpData->remoteEndpoint && tcpData->remoteEndpoint->flags & CA_SECURE)
684 CAResult_t result = CA_STATUS_OK;
685 OIC_LOG(DEBUG, TAG, "CAencryptSsl called!");
686 result = CAencryptSsl(tcpData->remoteEndpoint, tcpData->data, tcpData->dataLen);
688 if (CA_STATUS_OK != result)
690 OIC_LOG(ERROR, TAG, "CAAdapterNetDtlsEncrypt failed!");
691 CASearchAndDeleteTCPSession(tcpData->remoteEndpoint);
692 CATCPErrorHandler(tcpData->remoteEndpoint, tcpData->data, tcpData->dataLen,
695 OIC_LOG_V(DEBUG, TAG,
696 "CAAdapterNetDtlsEncrypt returned with result[%d]", result);
700 //Processing for sending unicast
701 ssize_t dlen = CATCPSendData(tcpData->remoteEndpoint, tcpData->data, tcpData->dataLen);
704 OIC_LOG(ERROR, TAG, "CATCPSendData failed");
705 CASearchAndDeleteTCPSession(tcpData->remoteEndpoint);
706 CATCPErrorHandler(tcpData->remoteEndpoint, tcpData->data, tcpData->dataLen,
712 CATCPData *CACreateTCPData(const CAEndpoint_t *remoteEndpoint, const void *data,
713 size_t dataLength, bool isMulticast)
715 VERIFY_NON_NULL_RET(remoteEndpoint, TAG, "remoteEndpoint is NULL", NULL);
716 VERIFY_NON_NULL_RET(data, TAG, "data is NULL", NULL);
718 CATCPData *tcpData = (CATCPData *) OICCalloc(1, sizeof(*tcpData));
721 OIC_LOG(ERROR, TAG, "Memory allocation failed!");
725 tcpData->remoteEndpoint = CACloneEndpoint(remoteEndpoint);
726 tcpData->data = (void *) OICMalloc(dataLength);
729 OIC_LOG(ERROR, TAG, "Memory allocation failed!");
730 CAFreeTCPData(tcpData);
734 memcpy(tcpData->data, data, dataLength);
735 tcpData->dataLen = dataLength;
737 tcpData->isMulticast = isMulticast;
742 void CAFreeTCPData(CATCPData *tcpData)
744 VERIFY_NON_NULL_VOID(tcpData, TAG, "tcpData is NULL");
746 CAFreeEndpoint(tcpData->remoteEndpoint);
747 OICFree(tcpData->data);
751 void CADataDestroyer(void *data, uint32_t size)
753 if (size < sizeof(CATCPData))
756 OIC_LOG_V(ERROR, TAG, "Destroy data too small %p %" PRIu32, data, size);
759 CATCPData *TCPData = (CATCPData *) data;
761 CAFreeTCPData(TCPData);
765 size_t CAGetTotalLengthFromPacketHeader(const unsigned char *recvBuffer, size_t size)
767 OIC_LOG(DEBUG, TAG, "IN - CAGetTotalLengthFromHeader");
769 if (NULL == recvBuffer || !size)
771 OIC_LOG(ERROR, TAG, "recvBuffer is NULL");
775 coap_transport_t transport = coap_get_tcp_header_type_from_initbyte(
776 ((unsigned char *)recvBuffer)[0] >> 4);
777 size_t optPaylaodLen = coap_get_length_from_header((unsigned char *)recvBuffer,
779 size_t headerLen = coap_get_tcp_header_length((unsigned char *)recvBuffer);
781 OIC_LOG_V(DEBUG, TAG, "option/paylaod length [%d]", optPaylaodLen);
782 OIC_LOG_V(DEBUG, TAG, "header length [%d]", headerLen);
783 OIC_LOG_V(DEBUG, TAG, "total data length [%d]", headerLen + optPaylaodLen);
785 OIC_LOG(DEBUG, TAG, "OUT - CAGetTotalLengthFromHeader");
786 return headerLen + optPaylaodLen;
789 void CAGetTCPHeaderDetails(unsigned char* recvBuffer, coap_transport_t *transport,
792 if (NULL == recvBuffer)
794 OIC_LOG(ERROR, TAG, "recvBuffer is NULL");
798 if (NULL == transport)
800 OIC_LOG(ERROR, TAG, "transport is NULL");
804 if (NULL == headerlen)
806 OIC_LOG(ERROR, TAG, "headerlen is NULL");
810 *transport = coap_get_tcp_header_type_from_initbyte(
811 ((unsigned char *)recvBuffer)[0] >> 4);
812 *headerlen = coap_get_tcp_header_length_for_transport(*transport);