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)
447 if (NULL == data || NULL == ctx)
452 CATCPData *tcpData = (CATCPData *)data;
453 CAEndpoint_t *endpoint = (CAEndpoint_t *)ctx;
455 if (NULL != tcpData && NULL != tcpData->remoteEndpoint)
457 if (strcmp(tcpData->remoteEndpoint->addr, endpoint->addr) == 0
458 && tcpData->remoteEndpoint->port == endpoint->port)
466 CAResult_t CATCPDisconnectSession(const CAEndpoint_t *endpoint)
468 CAResult_t res = CA_STATUS_OK;
470 res = CAcloseSslConnection(endpoint);
471 if (CA_STATUS_OK != res)
473 OIC_LOG(ERROR, TAG, "failed to close TLS session");
474 res = CAQueueingThreadClearContextData(g_sendQueueHandle,
475 CAClearQueueEndpointDataContext,
477 if (CA_STATUS_OK != res)
479 OIC_LOG(ERROR, TAG, "failed to clear context data");
486 res = CASearchAndDeleteTCPSession(endpoint);
487 if (CA_STATUS_OK != res)
489 OIC_LOG(ERROR, TAG, "failed to close TCP session");
492 res = CAQueueingThreadClearContextData(g_sendQueueHandle,
493 CAClearQueueEndpointDataContext,
495 if (CA_STATUS_OK != res)
497 OIC_LOG(ERROR, TAG, "failed to clear context data");
503 CAResult_t CAStartTCPListeningServer()
505 #ifndef SINGLE_THREAD
506 if (!caglobals.server)
508 caglobals.server = true; // only needed to run CA tests
511 CAResult_t ret = CATCPStartServer((const ca_thread_pool_t)caglobals.tcp.threadpool);
512 if (CA_STATUS_OK != ret)
514 OIC_LOG_V(ERROR, TAG, "Failed to start listening server![%d]", ret);
522 CAResult_t CAStopTCPListeningServer()
527 CAResult_t CAStartTCPDiscoveryServer()
529 if (!caglobals.client)
531 caglobals.client = true; // only needed to run CA tests
534 CAResult_t ret = CATCPStartServer((const ca_thread_pool_t)caglobals.tcp.threadpool);
535 if (CA_STATUS_OK != ret)
537 OIC_LOG_V(ERROR, TAG, "Failed to start discovery server![%d]", ret);
544 static size_t CAQueueTCPData(bool isMulticast, const CAEndpoint_t *endpoint,
545 const void *data, size_t dataLength)
547 VERIFY_NON_NULL_RET(endpoint, TAG, "endpoint", -1);
548 VERIFY_NON_NULL_RET(data, TAG, "data", -1);
552 OIC_LOG(ERROR, TAG, "Invalid Data Length");
556 VERIFY_NON_NULL_RET(g_sendQueueHandle, TAG, "sendQueueHandle", -1);
558 // Create TCPData to add to queue
559 CATCPData *tcpData = CACreateTCPData(endpoint, data, dataLength, isMulticast);
562 OIC_LOG(ERROR, TAG, "Failed to create ipData!");
565 // Add message to send queue
566 CAQueueingThreadAddData(g_sendQueueHandle, tcpData, sizeof(CATCPData));
571 int32_t CASendTCPUnicastData(const CAEndpoint_t *endpoint,
572 const void *data, uint32_t dataLength,
573 CADataType_t dataType)
575 OIC_LOG(DEBUG, TAG, "IN");
577 #ifndef SINGLE_THREAD
578 return CAQueueTCPData(false, endpoint, data, dataLength);
580 return CATCPSendData(endpoint, data, dataLength);
584 int32_t CASendTCPMulticastData(const CAEndpoint_t *endpoint,
585 const void *data, uint32_t dataLength,
586 CADataType_t dataType)
589 return CAQueueTCPData(true, endpoint, data, dataLength);
592 CAResult_t CAReadTCPData()
594 OIC_LOG(DEBUG, TAG, "IN");
601 CAResult_t CAStopTCP()
603 CAIPStopNetworkMonitor(CA_ADAPTER_TCP);
605 #ifndef SINGLE_THREAD
606 if (g_sendQueueHandle && g_sendQueueHandle->threadMutex)
608 CAQueueingThreadStop(g_sendQueueHandle);
610 CATCPDeinitializeQueueHandles();
615 //Re-initializing the Globals to start them again
616 CAInitializeTCPGlobals();
621 void CATerminateTCP()
623 CATCPSetPacketReceiveCallback(NULL);
629 void CATCPSendDataThread(void *threadData)
631 CATCPData *tcpData = (CATCPData *) threadData;
634 OIC_LOG(DEBUG, TAG, "Invalid TCP data!");
638 if (caglobals.tcp.terminate)
640 OIC_LOG(DEBUG, TAG, "Adapter is not enabled");
641 CATCPErrorHandler(tcpData->remoteEndpoint, tcpData->data, tcpData->dataLen,
646 if (tcpData->isMulticast)
648 //Processing for sending multicast
649 OIC_LOG(DEBUG, TAG, "Send Multicast Data is called, not supported");
655 if (tcpData->remoteEndpoint && tcpData->remoteEndpoint->flags & CA_SECURE)
657 CAResult_t result = CA_STATUS_OK;
658 OIC_LOG(DEBUG, TAG, "CAencryptSsl called!");
659 result = CAencryptSsl(tcpData->remoteEndpoint, tcpData->data, tcpData->dataLen);
661 if (CA_STATUS_OK != result)
663 OIC_LOG(ERROR, TAG, "CAAdapterNetDtlsEncrypt failed!");
664 CASearchAndDeleteTCPSession(tcpData->remoteEndpoint);
665 CATCPErrorHandler(tcpData->remoteEndpoint, tcpData->data, tcpData->dataLen,
668 OIC_LOG_V(DEBUG, TAG,
669 "CAAdapterNetDtlsEncrypt returned with result[%d]", result);
673 //Processing for sending unicast
674 ssize_t dlen = CATCPSendData(tcpData->remoteEndpoint, tcpData->data, tcpData->dataLen);
677 OIC_LOG(ERROR, TAG, "CATCPSendData failed");
678 CASearchAndDeleteTCPSession(tcpData->remoteEndpoint);
679 CATCPErrorHandler(tcpData->remoteEndpoint, tcpData->data, tcpData->dataLen,
685 CATCPData *CACreateTCPData(const CAEndpoint_t *remoteEndpoint, const void *data,
686 size_t dataLength, bool isMulticast)
688 VERIFY_NON_NULL_RET(remoteEndpoint, TAG, "remoteEndpoint is NULL", NULL);
689 VERIFY_NON_NULL_RET(data, TAG, "data is NULL", NULL);
691 CATCPData *tcpData = (CATCPData *) OICCalloc(1, sizeof(*tcpData));
694 OIC_LOG(ERROR, TAG, "Memory allocation failed!");
698 tcpData->remoteEndpoint = CACloneEndpoint(remoteEndpoint);
699 tcpData->data = (void *) OICMalloc(dataLength);
702 OIC_LOG(ERROR, TAG, "Memory allocation failed!");
703 CAFreeTCPData(tcpData);
707 memcpy(tcpData->data, data, dataLength);
708 tcpData->dataLen = dataLength;
710 tcpData->isMulticast = isMulticast;
715 void CAFreeTCPData(CATCPData *tcpData)
717 VERIFY_NON_NULL_VOID(tcpData, TAG, "tcpData is NULL");
719 CAFreeEndpoint(tcpData->remoteEndpoint);
720 OICFree(tcpData->data);
724 void CADataDestroyer(void *data, uint32_t size)
726 if (size < sizeof(CATCPData))
729 OIC_LOG_V(ERROR, TAG, "Destroy data too small %p %" PRIu32, data, size);
732 CATCPData *TCPData = (CATCPData *) data;
734 CAFreeTCPData(TCPData);
738 size_t CAGetTotalLengthFromPacketHeader(const unsigned char *recvBuffer, size_t size)
740 OIC_LOG(DEBUG, TAG, "IN - CAGetTotalLengthFromHeader");
742 if (NULL == recvBuffer || !size)
744 OIC_LOG(ERROR, TAG, "recvBuffer is NULL");
748 coap_transport_t transport = coap_get_tcp_header_type_from_initbyte(
749 ((unsigned char *)recvBuffer)[0] >> 4);
750 size_t optPaylaodLen = coap_get_length_from_header((unsigned char *)recvBuffer,
752 size_t headerLen = coap_get_tcp_header_length((unsigned char *)recvBuffer);
754 OIC_LOG_V(DEBUG, TAG, "option/paylaod length [%d]", optPaylaodLen);
755 OIC_LOG_V(DEBUG, TAG, "header length [%d]", headerLen);
756 OIC_LOG_V(DEBUG, TAG, "total data length [%d]", headerLen + optPaylaodLen);
758 OIC_LOG(DEBUG, TAG, "OUT - CAGetTotalLengthFromHeader");
759 return headerLen + optPaylaodLen;
762 void CAGetTCPHeaderDetails(unsigned char* recvBuffer, coap_transport_t *transport,
765 if (NULL == recvBuffer)
767 OIC_LOG(ERROR, TAG, "recvBuffer is NULL");
771 if (NULL == transport)
773 OIC_LOG(ERROR, TAG, "transport is NULL");
777 if (NULL == headerlen)
779 OIC_LOG(ERROR, TAG, "headerlen is NULL");
783 *transport = coap_get_tcp_header_type_from_initbyte(
784 ((unsigned char *)recvBuffer)[0] >> 4);
785 *headerlen = coap_get_tcp_header_length_for_transport(*transport);