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 * Mutex to synchronize TCP adapter access.
69 static oc_mutex g_mutexAdapter = NULL;
72 * State to control closing of TCP servers on interface down event.
74 static bool g_skipCloseOnIFDown;
77 * Queue handle for Send Data.
79 static CAQueueingThread_t *g_sendQueueHandle = NULL;
82 * Network Packet Received Callback to CA.
84 static CANetworkPacketReceivedCallback g_networkPacketCallback = NULL;
87 * Adapter Changed Callback to CA.
89 static CAAdapterChangeCallback g_networkChangeCallback = NULL;
92 * Connection Changed Callback to CA.
94 static CAConnectionChangeCallback g_connectionChangeCallback = NULL;
97 * error Callback to CA adapter.
99 static CAErrorHandleCallback g_errorCallback = NULL;
102 * KeepAlive Connected or Disconnected Callback to CA adapter.
104 static CAKeepAliveConnectionCallback g_connKeepAliveCallback = NULL;
106 static CAResult_t CATCPPacketReceivedCB(const CASecureEndpoint_t *sep,
107 const void *data, uint32_t dataLength);
109 static void CATCPErrorHandler(const CAEndpoint_t *endpoint, const void *data,
110 size_t dataLength, CAResult_t result);
112 static CAResult_t CATCPInitializeQueueHandles();
114 static void CATCPDeinitializeQueueHandles();
116 static void CATCPSendDataThread(void *threadData);
118 static CATCPData *CACreateTCPData(const CAEndpoint_t *remoteEndpoint,
119 const void *data, size_t dataLength,
121 void CAFreeTCPData(CATCPData *ipData);
123 static void CADataDestroyer(void *data, uint32_t size);
125 CAResult_t CATCPInitializeQueueHandles()
127 // Check if the message queue is already initialized
128 if (g_sendQueueHandle)
130 OIC_LOG(DEBUG, TAG, "send queue handle is already initialized!");
134 // Create send message queue
135 g_sendQueueHandle = OICMalloc(sizeof(CAQueueingThread_t));
136 if (!g_sendQueueHandle)
138 OIC_LOG(ERROR, TAG, "Memory allocation failed!");
139 return CA_MEMORY_ALLOC_FAILED;
142 if (CA_STATUS_OK != CAQueueingThreadInitialize(g_sendQueueHandle,
143 (const ca_thread_pool_t)caglobals.tcp.threadpool,
144 CATCPSendDataThread, CADataDestroyer))
146 OIC_LOG(ERROR, TAG, "Failed to Initialize send queue thread");
147 OICFree(g_sendQueueHandle);
148 g_sendQueueHandle = NULL;
149 return CA_STATUS_FAILED;
155 void CATCPDeinitializeQueueHandles()
157 CAQueueingThreadDestroy(g_sendQueueHandle);
158 OICFree(g_sendQueueHandle);
159 g_sendQueueHandle = NULL;
162 void CATCPConnectionStateCB(const char *ipAddress, CANetworkStatus_t status)
168 CAResult_t CATCPPacketReceivedCB(const CASecureEndpoint_t *sep, const void *data,
171 VERIFY_NON_NULL(sep, TAG, "sep is NULL");
172 VERIFY_NON_NULL(data, TAG, "data is NULL");
174 OIC_LOG_V(DEBUG, TAG, "Address: %s, port:%d", sep->endpoint.addr, sep->endpoint.port);
176 CAResult_t res = CA_STATUS_OK;
178 if (g_networkPacketCallback)
180 res = g_networkPacketCallback(sep, data, dataLength);
181 if (CA_STATUS_OK != res)
183 OIC_LOG(ERROR, TAG, "Error parsing CoAP data");
187 unsigned char *buffer = (unsigned char*)data;
188 size_t bufferLen = dataLength;
191 //get remote device information from file descriptor.
192 CATCPSessionInfo_t *svritem = CAGetTCPSessionInfoFromEndpoint(&sep->endpoint, &index);
195 OIC_LOG(ERROR, TAG, "there is no connection information in list");
196 return CA_STATUS_INVALID_PARAM;
198 if (UNKNOWN == svritem->protocol)
200 OIC_LOG(ERROR, TAG, "invalid protocol type");
201 return CA_STATUS_INVALID_PARAM;
204 //totalLen filled only when header fully read and parsed
205 while (0 != bufferLen)
207 res = CAConstructCoAP(svritem, &buffer, &bufferLen);
208 if (CA_STATUS_OK != res)
210 OIC_LOG_V(ERROR, TAG, "CAConstructCoAP return error : %d", res);
214 //when successfully read all required data - pass them to upper layer.
215 if (svritem->len == svritem->totalLen)
217 if (g_networkPacketCallback)
219 res = g_networkPacketCallback(sep, svritem->data, svritem->totalLen);
220 if (CA_STATUS_OK != res)
222 OIC_LOG(ERROR, TAG, "Error parsing CoAP data");
226 CACleanData(svritem);
230 OIC_LOG_V(DEBUG, TAG, "%zd bytes required for complete CoAP",
231 svritem->totalLen - svritem->len);
239 static ssize_t CATCPPacketSendCB(CAEndpoint_t *endpoint, const void *data, size_t dataLength)
241 OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
242 VERIFY_NON_NULL_RET(endpoint, TAG, "endpoint is NULL", -1);
243 VERIFY_NON_NULL_RET(data, TAG, "data is NULL", -1);
245 OIC_LOG_V(DEBUG, TAG, "Address: %s, port:%d", endpoint->addr, endpoint->port);
246 OIC_LOG_BUFFER(DEBUG, TAG, data, dataLength);
248 ssize_t ret = CATCPSendData(endpoint, data, dataLength);
249 OIC_LOG_V(DEBUG, TAG, "Out %s : %zd bytes sent", __func__, ret);
254 static void CATCPErrorHandler(const CAEndpoint_t *endpoint, const void *data,
255 size_t dataLength, CAResult_t result)
257 VERIFY_NON_NULL_VOID(endpoint, TAG, "endpoint is NULL");
258 VERIFY_NON_NULL_VOID(data, TAG, "data is NULL");
262 g_errorCallback(endpoint, data, dataLength, result);
266 static void CATCPConnectionHandler(const CAEndpoint_t *endpoint, bool isConnected, bool isClient)
268 // Pass the changed connection status to RI Layer for keepalive.
269 if (g_connKeepAliveCallback)
271 g_connKeepAliveCallback(endpoint, isConnected, isClient);
274 // Pass the changed connection status to CAUtil.
275 if (g_connectionChangeCallback)
277 g_connectionChangeCallback(endpoint, isConnected);
281 void CATCPSetKeepAliveCallbacks(CAKeepAliveConnectionCallback ConnHandler)
283 g_connKeepAliveCallback = ConnHandler;
286 void CATCPAdapterHandler(CATransportAdapter_t adapter, CANetworkStatus_t status)
288 if (g_networkChangeCallback)
290 g_networkChangeCallback(adapter, status);
293 if (CA_INTERFACE_DOWN == status)
295 OIC_LOG(INFO, TAG, "Network status is down, close all session");
297 CAResult_t res = CAQueueingThreadClearData(g_sendQueueHandle);
298 if (res != CA_STATUS_OK)
300 OIC_LOG_V(ERROR, TAG, "CAQueueingThreadClearData failed[%d]", res);
303 oc_mutex_lock(g_mutexAdapter);
304 if (!g_skipCloseOnIFDown)
310 OIC_LOG(INFO, TAG, "Skip closing servers!");
312 oc_mutex_unlock(g_mutexAdapter);
314 else if (CA_INTERFACE_UP == status)
316 OIC_LOG(INFO, TAG, "Network status is up, create new socket for listening");
318 CAResult_t ret = CA_STATUS_FAILED;
319 #ifndef SINGLE_THREAD
320 ret = CATCPStartServer((const ca_thread_pool_t)caglobals.tcp.threadpool);
322 ret = CATCPStartServer();
324 if (CA_STATUS_OK != ret)
326 OIC_LOG_V(ERROR, TAG, "CATCPStartServer failed[%d]", ret);
331 static void CAInitializeTCPGlobals()
333 caglobals.tcp.ipv4.fd = -1;
334 caglobals.tcp.ipv4s.fd = -1;
335 caglobals.tcp.ipv6.fd = -1;
336 caglobals.tcp.ipv6s.fd = -1;
338 // Set the port number received from application.
339 caglobals.tcp.ipv4.port = caglobals.ports.tcp.u4;
340 caglobals.tcp.ipv4s.port = caglobals.ports.tcp.u4s;
341 caglobals.tcp.ipv6.port = caglobals.ports.tcp.u6;
342 caglobals.tcp.ipv6s.port = caglobals.ports.tcp.u6s;
344 caglobals.tcp.selectTimeout = CA_TCP_SELECT_TIMEOUT;
345 caglobals.tcp.listenBacklog = CA_TCP_LISTEN_BACKLOG;
346 caglobals.tcp.svrlist = NULL;
348 CATransportFlags_t flags = 0;
349 if (caglobals.client)
351 flags |= caglobals.clientFlags;
354 #ifndef DISABLE_TCP_SERVER
355 if (caglobals.server)
357 flags |= caglobals.serverFlags;
361 caglobals.tcp.ipv4tcpenabled = flags & CA_IPV4;
362 caglobals.tcp.ipv6tcpenabled = flags & CA_IPV6;
365 CAResult_t CAInitializeTCP(CARegisterConnectivityCallback registerCallback,
366 CANetworkPacketReceivedCallback networkPacketCallback,
367 CAAdapterChangeCallback netCallback,
368 CAConnectionChangeCallback connCallback,
369 CAErrorHandleCallback errorCallback, ca_thread_pool_t handle)
371 OIC_LOG(DEBUG, TAG, "IN");
372 VERIFY_NON_NULL(registerCallback, TAG, "registerCallback");
373 VERIFY_NON_NULL(networkPacketCallback, TAG, "networkPacketCallback");
374 VERIFY_NON_NULL(netCallback, TAG, "netCallback");
375 #ifndef SINGLE_THREAD
376 VERIFY_NON_NULL(handle, TAG, "thread pool handle");
379 g_networkChangeCallback = netCallback;
380 g_connectionChangeCallback = connCallback;
381 g_networkPacketCallback = networkPacketCallback;
382 g_errorCallback = errorCallback;
384 CAInitializeTCPGlobals();
386 // Create Mutex for synchronize access at adapter level
389 g_mutexAdapter = oc_mutex_new();
392 OIC_LOG(ERROR, TAG, "Failed to create mutex!");
393 return CA_STATUS_FAILED;
397 g_skipCloseOnIFDown = false;
399 CAResult_t res = CATCPCreateMutex();
400 if (CA_STATUS_OK == res)
402 res = CATCPCreateCond();
404 if (CA_STATUS_OK != res)
406 OIC_LOG(ERROR, TAG, "failed to create mutex/cond");
412 res = CATCPCreateSendMutex();
413 if (CA_STATUS_OK == res)
415 res = CATCPCreateSendCond();
417 if (CA_STATUS_OK != res)
419 OIC_LOG(ERROR, TAG, "failed to create send data mutex/cond");
422 CATCPDestroySendMutex();
423 CATCPDestroySendCond();
427 #ifndef SINGLE_THREAD
428 caglobals.tcp.threadpool = handle;
431 CATCPSetConnectionChangedCallback(CATCPConnectionHandler);
432 CATCPSetPacketReceiveCallback(CATCPPacketReceivedCB);
433 CATCPSetErrorHandler(CATCPErrorHandler);
436 CAsetSslAdapterCallbacks(CATCPPacketReceivedCB, CATCPPacketSendCB, CA_ADAPTER_TCP);
439 CAConnectivityHandler_t tcpHandler = {
440 .startAdapter = CAStartTCP,
441 .startListenServer = CAStartTCPListeningServer,
442 .stopListenServer = CAStopTCPListeningServer,
443 .startDiscoveryServer = CAStartTCPDiscoveryServer,
444 .sendData = CASendTCPUnicastData,
445 .sendDataToAll = CASendTCPMulticastData,
446 .GetnetInfo = CAGetTCPInterfaceInformation,
447 .readData = CAReadTCPData,
448 .stopAdapter = CAStopTCP,
449 .terminate = CATerminateTCP,
450 .cType = CA_ADAPTER_TCP};
452 registerCallback(tcpHandler);
454 OIC_LOG(INFO, TAG, "OUT IntializeTCP is Success");
458 CAResult_t CAStartTCP()
460 OIC_LOG(DEBUG, TAG, "IN");
462 #ifndef SINGLE_THREAD
463 if (CA_STATUS_OK != CATCPInitializeQueueHandles())
465 OIC_LOG(ERROR, TAG, "Failed to Initialize Queue Handle");
467 return CA_STATUS_FAILED;
470 // Start send queue thread
472 if (CA_STATUS_OK != CAQueueingThreadStart(g_sendQueueHandle))
474 if (CA_STATUS_OK != CAQueueingThreadStart(g_sendQueueHandle, "IoT_TCPSendQueue"))
477 OIC_LOG(ERROR, TAG, "Failed to Start Send Data Thread");
478 return CA_STATUS_FAILED;
481 CAResult_t ret = CATCPStartServer();
482 if (CA_STATUS_OK != ret)
484 OIC_LOG_V(DEBUG, TAG, "CATCPStartServer failed[%d]", ret);
489 // Start network monitoring to receive adapter status changes.
490 CAIPStartNetworkMonitor(CATCPAdapterHandler, CA_ADAPTER_TCP);
495 static bool CAClearQueueEndpointDataContext(void *data, uint32_t size, void *ctx)
499 if (NULL == data || NULL == ctx)
504 CATCPData *tcpData = (CATCPData *)data;
505 CAEndpoint_t *endpoint = (CAEndpoint_t *)ctx;
507 if (NULL != tcpData && NULL != tcpData->remoteEndpoint)
509 if (strcmp(tcpData->remoteEndpoint->addr, endpoint->addr) == 0
510 && tcpData->remoteEndpoint->port == endpoint->port)
518 CAResult_t CATCPDisconnectSession(const CAEndpoint_t *endpoint)
520 CAResult_t res = CAQueueingThreadClearContextData(g_sendQueueHandle,
521 CAClearQueueEndpointDataContext,
523 if (CA_STATUS_OK != res)
525 OIC_LOG(ERROR, TAG, "failed to clear context data");
529 res = CAcloseSslConnection(endpoint);
530 if (CA_STATUS_OK != res)
532 OIC_LOG(ERROR, TAG, "failed to close TLS session");
536 res = CASearchAndDeleteTCPSession(endpoint);
537 if (CA_STATUS_OK != res)
539 OIC_LOG(ERROR, TAG, "failed to close TCP session");
545 void CATCPSkipCloseOnInterfaceDown(bool state)
547 oc_mutex_lock(g_mutexAdapter);
548 g_skipCloseOnIFDown = state;
549 oc_mutex_unlock(g_mutexAdapter);
552 CAResult_t CAStartTCPListeningServer()
554 #if !defined(SINGLE_THREAD) && !defined(DISABLE_TCP_SERVER)
555 if (!caglobals.server)
557 caglobals.server = true; // only needed to run CA tests
560 CAResult_t ret = CATCPStartServer((const ca_thread_pool_t)caglobals.tcp.threadpool);
561 if (CA_STATUS_OK != ret)
563 OIC_LOG_V(ERROR, TAG, "Failed to start listening server![%d]", ret);
571 CAResult_t CAStopTCPListeningServer()
576 CAResult_t CAStartTCPDiscoveryServer()
578 if (!caglobals.client)
580 caglobals.client = true; // only needed to run CA tests
583 CAResult_t ret = CATCPStartServer((const ca_thread_pool_t)caglobals.tcp.threadpool);
584 if (CA_STATUS_OK != ret)
586 OIC_LOG_V(ERROR, TAG, "Failed to start discovery server![%d]", ret);
593 static size_t CAQueueTCPData(bool isMulticast, const CAEndpoint_t *endpoint,
594 const void *data, size_t dataLength)
596 VERIFY_NON_NULL_RET(endpoint, TAG, "endpoint", -1);
597 VERIFY_NON_NULL_RET(data, TAG, "data", -1);
601 OIC_LOG(ERROR, TAG, "Invalid Data Length");
605 VERIFY_NON_NULL_RET(g_sendQueueHandle, TAG, "sendQueueHandle", -1);
607 // Create TCPData to add to queue
608 CATCPData *tcpData = CACreateTCPData(endpoint, data, dataLength, isMulticast);
611 OIC_LOG(ERROR, TAG, "Failed to create ipData!");
614 // Add message to send queue
615 CAQueueingThreadAddData(g_sendQueueHandle, tcpData, sizeof(CATCPData));
620 int32_t CASendTCPUnicastData(const CAEndpoint_t *endpoint,
621 const void *data, uint32_t dataLength,
622 CADataType_t dataType)
624 OIC_LOG(DEBUG, TAG, "IN");
626 #ifndef SINGLE_THREAD
627 return CAQueueTCPData(false, endpoint, data, dataLength);
629 return CATCPSendData(endpoint, data, dataLength);
633 int32_t CASendTCPMulticastData(const CAEndpoint_t *endpoint,
634 const void *data, uint32_t dataLength,
635 CADataType_t dataType)
642 OIC_LOG(ERROR, TAG, "TCP adapter does not support multicast sending!");
646 CAResult_t CAReadTCPData()
648 OIC_LOG(DEBUG, TAG, "IN");
655 CAResult_t CAStopTCP()
657 CAIPStopNetworkMonitor(CA_ADAPTER_TCP);
659 /* Some times send queue thread fails to terminate as it's worker
660 thread gets blocked at TCP session's socket connect operation.
661 So closing sockets which are in connect operation at the time
662 of termination of adapter would save send queue thread from
664 CATCPCloseInProgressConnections();
666 #ifndef SINGLE_THREAD
667 // Stop send queue thread.
668 if (g_sendQueueHandle && g_sendQueueHandle->threadMutex)
670 CAQueueingThreadStop(g_sendQueueHandle);
672 CATCPDeinitializeQueueHandles();
675 // Close TCP servers and established connections.
678 // Re-initializing the Globals to start them again.
679 CAInitializeTCPGlobals();
684 void CATerminateTCP()
686 CATCPSetPacketReceiveCallback(NULL);
691 CATCPDestroySendMutex();
692 CATCPDestroySendCond();
694 g_skipCloseOnIFDown = false;
696 // Free adapter mutex
699 oc_mutex_free(g_mutexAdapter);
700 g_mutexAdapter = NULL;
704 void CATCPSendDataThread(void *threadData)
706 CATCPData *tcpData = (CATCPData *) threadData;
709 OIC_LOG(DEBUG, TAG, "Invalid TCP data!");
713 if (caglobals.tcp.terminate)
715 OIC_LOG(DEBUG, TAG, "Adapter is not enabled");
716 CATCPErrorHandler(tcpData->remoteEndpoint, tcpData->data, tcpData->dataLen,
721 if (tcpData->isMulticast)
723 //Processing for sending multicast
724 OIC_LOG(DEBUG, TAG, "Send Multicast Data is called, not supported");
730 if (tcpData->remoteEndpoint && tcpData->remoteEndpoint->flags & CA_SECURE)
732 CAResult_t result = CA_STATUS_OK;
733 OIC_LOG(DEBUG, TAG, "CAencryptSsl called!");
734 result = CAencryptSsl(tcpData->remoteEndpoint, tcpData->data, tcpData->dataLen);
736 if (CA_STATUS_OK != result)
738 OIC_LOG(ERROR, TAG, "CAAdapterNetDtlsEncrypt failed!");
739 CASearchAndDeleteTCPSession(tcpData->remoteEndpoint);
740 CATCPErrorHandler(tcpData->remoteEndpoint, tcpData->data, tcpData->dataLen,
743 OIC_LOG_V(DEBUG, TAG,
744 "CAAdapterNetDtlsEncrypt returned with result[%d]", result);
748 //Processing for sending unicast
749 ssize_t dlen = CATCPSendData(tcpData->remoteEndpoint, tcpData->data, tcpData->dataLen);
752 OIC_LOG(ERROR, TAG, "CATCPSendData failed");
753 CASearchAndDeleteTCPSession(tcpData->remoteEndpoint);
754 CATCPErrorHandler(tcpData->remoteEndpoint, tcpData->data, tcpData->dataLen,
760 CATCPData *CACreateTCPData(const CAEndpoint_t *remoteEndpoint, const void *data,
761 size_t dataLength, bool isMulticast)
763 VERIFY_NON_NULL_RET(remoteEndpoint, TAG, "remoteEndpoint is NULL", NULL);
764 VERIFY_NON_NULL_RET(data, TAG, "data is NULL", NULL);
766 CATCPData *tcpData = (CATCPData *) OICCalloc(1, sizeof(*tcpData));
769 OIC_LOG(ERROR, TAG, "Memory allocation failed!");
773 tcpData->remoteEndpoint = CACloneEndpoint(remoteEndpoint);
774 tcpData->data = (void *) OICMalloc(dataLength);
777 OIC_LOG(ERROR, TAG, "Memory allocation failed!");
778 CAFreeTCPData(tcpData);
782 memcpy(tcpData->data, data, dataLength);
783 tcpData->dataLen = dataLength;
785 tcpData->isMulticast = isMulticast;
790 void CAFreeTCPData(CATCPData *tcpData)
792 VERIFY_NON_NULL_VOID(tcpData, TAG, "tcpData is NULL");
794 CAFreeEndpoint(tcpData->remoteEndpoint);
795 OICFree(tcpData->data);
799 void CADataDestroyer(void *data, uint32_t size)
801 if (size < sizeof(CATCPData))
804 OIC_LOG_V(ERROR, TAG, "Destroy data too small %p %" PRIu32, data, size);
807 CATCPData *TCPData = (CATCPData *) data;
809 CAFreeTCPData(TCPData);
813 size_t CAGetTotalLengthFromPacketHeader(const unsigned char *recvBuffer, size_t size)
815 OIC_LOG(DEBUG, TAG, "IN - CAGetTotalLengthFromHeader");
817 if (NULL == recvBuffer || !size)
819 OIC_LOG(ERROR, TAG, "recvBuffer is NULL");
823 coap_transport_t transport = coap_get_tcp_header_type_from_initbyte(
824 ((unsigned char *)recvBuffer)[0] >> 4);
825 size_t optPaylaodLen = coap_get_length_from_header((unsigned char *)recvBuffer,
827 size_t headerLen = coap_get_tcp_header_length((unsigned char *)recvBuffer);
829 OIC_LOG_V(DEBUG, TAG, "option/paylaod length [%d]", optPaylaodLen);
830 OIC_LOG_V(DEBUG, TAG, "header length [%d]", headerLen);
831 OIC_LOG_V(DEBUG, TAG, "total data length [%d]", headerLen + optPaylaodLen);
833 OIC_LOG(DEBUG, TAG, "OUT - CAGetTotalLengthFromHeader");
834 return headerLen + optPaylaodLen;
837 void CAGetTCPHeaderDetails(unsigned char* recvBuffer, coap_transport_t *transport,
840 if (NULL == recvBuffer)
842 OIC_LOG(ERROR, TAG, "recvBuffer is NULL");
846 if (NULL == transport)
848 OIC_LOG(ERROR, TAG, "transport is NULL");
852 if (NULL == headerlen)
854 OIC_LOG(ERROR, TAG, "headerlen is NULL");
858 *transport = coap_get_tcp_header_type_from_initbyte(
859 ((unsigned char *)recvBuffer)[0] >> 4);
860 *headerlen = coap_get_tcp_header_length_for_transport(*transport);