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");
486 res = CASearchAndDeleteTCPSession(endpoint);
487 if (CA_STATUS_OK != res)
489 OIC_LOG(ERROR, TAG, "failed to close TCP session");
495 CAResult_t CAStartTCPListeningServer()
497 #ifndef SINGLE_THREAD
498 if (!caglobals.server)
500 caglobals.server = true; // only needed to run CA tests
503 CAResult_t ret = CATCPStartServer((const ca_thread_pool_t)caglobals.tcp.threadpool);
504 if (CA_STATUS_OK != ret)
506 OIC_LOG_V(ERROR, TAG, "Failed to start listening server![%d]", ret);
514 CAResult_t CAStopTCPListeningServer()
519 CAResult_t CAStartTCPDiscoveryServer()
521 if (!caglobals.client)
523 caglobals.client = true; // only needed to run CA tests
526 CAResult_t ret = CATCPStartServer((const ca_thread_pool_t)caglobals.tcp.threadpool);
527 if (CA_STATUS_OK != ret)
529 OIC_LOG_V(ERROR, TAG, "Failed to start discovery server![%d]", ret);
536 static size_t CAQueueTCPData(bool isMulticast, const CAEndpoint_t *endpoint,
537 const void *data, size_t dataLength)
539 VERIFY_NON_NULL_RET(endpoint, TAG, "endpoint", -1);
540 VERIFY_NON_NULL_RET(data, TAG, "data", -1);
544 OIC_LOG(ERROR, TAG, "Invalid Data Length");
548 VERIFY_NON_NULL_RET(g_sendQueueHandle, TAG, "sendQueueHandle", -1);
550 // Create TCPData to add to queue
551 CATCPData *tcpData = CACreateTCPData(endpoint, data, dataLength, isMulticast);
554 OIC_LOG(ERROR, TAG, "Failed to create ipData!");
557 // Add message to send queue
558 CAQueueingThreadAddData(g_sendQueueHandle, tcpData, sizeof(CATCPData));
563 int32_t CASendTCPUnicastData(const CAEndpoint_t *endpoint,
564 const void *data, uint32_t dataLength,
565 CADataType_t dataType)
567 OIC_LOG(DEBUG, TAG, "IN");
569 #ifndef SINGLE_THREAD
570 return CAQueueTCPData(false, endpoint, data, dataLength);
572 return CATCPSendData(endpoint, data, dataLength);
576 int32_t CASendTCPMulticastData(const CAEndpoint_t *endpoint,
577 const void *data, uint32_t dataLength,
578 CADataType_t dataType)
581 return CAQueueTCPData(true, endpoint, data, dataLength);
584 CAResult_t CAReadTCPData()
586 OIC_LOG(DEBUG, TAG, "IN");
593 CAResult_t CAStopTCP()
595 CAIPStopNetworkMonitor(CA_ADAPTER_TCP);
597 /* Some times send queue thread fails to terminate as it's worker
598 thread gets blocked at TCP session's socket connect operation.
599 So closing sockets which are in connect operation at the time
600 of termination of adapter would save send queue thread from
602 CATCPCloseInProgressConnections();
604 #ifndef SINGLE_THREAD
605 // Stop send queue thread.
606 if (g_sendQueueHandle && g_sendQueueHandle->threadMutex)
608 CAQueueingThreadStop(g_sendQueueHandle);
610 CATCPDeinitializeQueueHandles();
613 // Close TCP servers and established connections.
616 // Re-initializing the Globals to start them again.
617 CAInitializeTCPGlobals();
622 void CATerminateTCP()
624 CATCPSetPacketReceiveCallback(NULL);
630 void CATCPSendDataThread(void *threadData)
632 CATCPData *tcpData = (CATCPData *) threadData;
635 OIC_LOG(DEBUG, TAG, "Invalid TCP data!");
639 if (caglobals.tcp.terminate)
641 OIC_LOG(DEBUG, TAG, "Adapter is not enabled");
642 CATCPErrorHandler(tcpData->remoteEndpoint, tcpData->data, tcpData->dataLen,
647 if (tcpData->isMulticast)
649 //Processing for sending multicast
650 OIC_LOG(DEBUG, TAG, "Send Multicast Data is called, not supported");
656 if (tcpData->remoteEndpoint && tcpData->remoteEndpoint->flags & CA_SECURE)
658 CAResult_t result = CA_STATUS_OK;
659 OIC_LOG(DEBUG, TAG, "CAencryptSsl called!");
660 result = CAencryptSsl(tcpData->remoteEndpoint, tcpData->data, tcpData->dataLen);
662 if (CA_STATUS_OK != result)
664 OIC_LOG(ERROR, TAG, "CAAdapterNetDtlsEncrypt failed!");
665 CASearchAndDeleteTCPSession(tcpData->remoteEndpoint);
666 CATCPErrorHandler(tcpData->remoteEndpoint, tcpData->data, tcpData->dataLen,
669 OIC_LOG_V(DEBUG, TAG,
670 "CAAdapterNetDtlsEncrypt returned with result[%d]", result);
674 //Processing for sending unicast
675 ssize_t dlen = CATCPSendData(tcpData->remoteEndpoint, tcpData->data, tcpData->dataLen);
678 OIC_LOG(ERROR, TAG, "CATCPSendData failed");
679 CASearchAndDeleteTCPSession(tcpData->remoteEndpoint);
680 CATCPErrorHandler(tcpData->remoteEndpoint, tcpData->data, tcpData->dataLen,
686 CATCPData *CACreateTCPData(const CAEndpoint_t *remoteEndpoint, const void *data,
687 size_t dataLength, bool isMulticast)
689 VERIFY_NON_NULL_RET(remoteEndpoint, TAG, "remoteEndpoint is NULL", NULL);
690 VERIFY_NON_NULL_RET(data, TAG, "data is NULL", NULL);
692 CATCPData *tcpData = (CATCPData *) OICCalloc(1, sizeof(*tcpData));
695 OIC_LOG(ERROR, TAG, "Memory allocation failed!");
699 tcpData->remoteEndpoint = CACloneEndpoint(remoteEndpoint);
700 tcpData->data = (void *) OICMalloc(dataLength);
703 OIC_LOG(ERROR, TAG, "Memory allocation failed!");
704 CAFreeTCPData(tcpData);
708 memcpy(tcpData->data, data, dataLength);
709 tcpData->dataLen = dataLength;
711 tcpData->isMulticast = isMulticast;
716 void CAFreeTCPData(CATCPData *tcpData)
718 VERIFY_NON_NULL_VOID(tcpData, TAG, "tcpData is NULL");
720 CAFreeEndpoint(tcpData->remoteEndpoint);
721 OICFree(tcpData->data);
725 void CADataDestroyer(void *data, uint32_t size)
727 if (size < sizeof(CATCPData))
730 OIC_LOG_V(ERROR, TAG, "Destroy data too small %p %" PRIu32, data, size);
733 CATCPData *TCPData = (CATCPData *) data;
735 CAFreeTCPData(TCPData);
739 size_t CAGetTotalLengthFromPacketHeader(const unsigned char *recvBuffer, size_t size)
741 OIC_LOG(DEBUG, TAG, "IN - CAGetTotalLengthFromHeader");
743 if (NULL == recvBuffer || !size)
745 OIC_LOG(ERROR, TAG, "recvBuffer is NULL");
749 coap_transport_t transport = coap_get_tcp_header_type_from_initbyte(
750 ((unsigned char *)recvBuffer)[0] >> 4);
751 size_t optPaylaodLen = coap_get_length_from_header((unsigned char *)recvBuffer,
753 size_t headerLen = coap_get_tcp_header_length((unsigned char *)recvBuffer);
755 OIC_LOG_V(DEBUG, TAG, "option/paylaod length [%d]", optPaylaodLen);
756 OIC_LOG_V(DEBUG, TAG, "header length [%d]", headerLen);
757 OIC_LOG_V(DEBUG, TAG, "total data length [%d]", headerLen + optPaylaodLen);
759 OIC_LOG(DEBUG, TAG, "OUT - CAGetTotalLengthFromHeader");
760 return headerLen + optPaylaodLen;
763 void CAGetTCPHeaderDetails(unsigned char* recvBuffer, coap_transport_t *transport,
766 if (NULL == recvBuffer)
768 OIC_LOG(ERROR, TAG, "recvBuffer is NULL");
772 if (NULL == transport)
774 OIC_LOG(ERROR, TAG, "transport is NULL");
778 if (NULL == headerlen)
780 OIC_LOG(ERROR, TAG, "headerlen is NULL");
784 *transport = coap_get_tcp_header_type_from_initbyte(
785 ((unsigned char *)recvBuffer)[0] >> 4);
786 *headerlen = coap_get_tcp_header_length_for_transport(*transport);