1. Updated boost Framework path for ios
[platform/upstream/iotivity.git] / resource / csdk / connectivity / src / tcp_adapter / catcpserver.c
1 /* ****************************************************************
2  *
3  * Copyright 2015 Samsung Electronics All Rights Reserved.
4  *
5  *
6  *
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
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
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.
18  *
19  ******************************************************************/
20
21 #include <sys/types.h>
22 #include <sys/socket.h>
23 #include <sys/select.h>
24 #include <sys/ioctl.h>
25 #include <sys/poll.h>
26 #include <stdio.h>
27 #include <unistd.h>
28 #include <fcntl.h>
29 #include <arpa/inet.h>
30 #include <netinet/in.h>
31 #include <net/if.h>
32 #include <errno.h>
33
34 #ifndef WITH_ARDUINO
35 #include <sys/socket.h>
36 #include <netinet/in.h>
37 #include <netdb.h>
38 #endif
39
40 #include "catcpinterface.h"
41 #include "caipnwmonitor.h"
42 #include <coap/pdu.h>
43 #include "caadapterutils.h"
44 #include "camutex.h"
45 #include "oic_malloc.h"
46
47 #ifdef __WITH_TLS__
48 #include "ca_adapter_net_ssl.h"
49 #endif
50
51 /**
52  * Logging tag for module name.
53  */
54 #define TAG "OIC_CA_TCP_SERVER"
55
56 /**
57  * Maximum CoAP over TCP header length
58  * to know the total data length.
59  */
60 #define COAP_MAX_HEADER_SIZE  6
61
62 /**
63  * TLS header size
64  */
65 #define TLS_HEADER_SIZE 5
66
67 /**
68  * Mutex to synchronize device object list.
69  */
70 static ca_mutex g_mutexObjectList = NULL;
71
72 /**
73  * Conditional mutex to synchronize.
74  */
75 static ca_cond g_condObjectList = NULL;
76
77 /**
78  * Maintains the callback to be notified when data received from remote device.
79  */
80 static CATCPPacketReceivedCallback g_packetReceivedCallback = NULL;
81
82 /**
83  * Error callback to update error in TCP.
84  */
85 static CATCPErrorHandleCallback g_tcpErrorHandler = NULL;
86
87 /**
88  * Connected Callback to pass the connection information to RI.
89  */
90 static CATCPConnectionHandleCallback g_connectionCallback = NULL;
91
92 static CAResult_t CATCPCreateMutex();
93 static void CATCPDestroyMutex();
94 static CAResult_t CATCPCreateCond();
95 static void CATCPDestroyCond();
96 static CASocketFd_t CACreateAcceptSocket(int family, CASocket_t *sock);
97 static void CAAcceptConnection(CATransportFlags_t flag, CASocket_t *sock);
98 static void CAFindReadyMessage();
99 static void CASelectReturned(fd_set *readFds);
100 static void CAReceiveMessage(int fd);
101 static void CAReceiveHandler(void *data);
102 static CAResult_t CATCPCreateSocket(int family, CATCPSessionInfo_t *svritem);
103
104 #define CHECKFD(FD) \
105     if (FD > caglobals.tcp.maxfd) \
106         caglobals.tcp.maxfd = FD;
107
108 #define CLOSE_SOCKET(TYPE) \
109     if (caglobals.tcp.TYPE.fd != OC_INVALID_SOCKET) \
110     { \
111         close(caglobals.tcp.TYPE.fd); \
112         caglobals.tcp.TYPE.fd = OC_INVALID_SOCKET; \
113     }
114
115 #define CA_FD_SET(TYPE, FDS) \
116     if (caglobals.tcp.TYPE.fd != OC_INVALID_SOCKET) \
117     { \
118         FD_SET(caglobals.tcp.TYPE.fd, FDS); \
119     }
120
121 /**
122  * Read length amount of data from socket item->fd
123  * Can read less data length then requested
124  * Actual read length added to item->len variable
125  *
126  * @param[in/out] item - used socket, buffer and to update received message length
127  * @param[in]  length  - length of data required to read
128  * @param[in]  flags   - additional info about socket
129  * @return             - CA_STATUS_OK or appropriate error code
130  */
131 static CAResult_t CARecv(CATCPSessionInfo_t *item, size_t length, int flags)
132 {
133     if (NULL == item)
134     {
135         return CA_STATUS_INVALID_PARAM;
136     }
137
138     //skip read operation if requested zero length
139     if (0 == length)
140     {
141         return CA_STATUS_OK;
142     }
143
144     unsigned char *buffer = item->data + item->len;
145
146     int len = recv(item->fd, buffer, length, flags);
147
148     if (len < 0)
149     {
150         OIC_LOG_V(ERROR, TAG, "recv failed %s", strerror(errno));
151         return CA_RECEIVE_FAILED;
152     }
153     else if (0 == len)
154     {
155         OIC_LOG(INFO, TAG, "Received disconnect from peer. Close connection");
156         item->state = DISCONNECTED;
157         return CA_DESTINATION_DISCONNECTED;
158     }
159
160     OIC_LOG_V(DEBUG, TAG, "recv len = %d", len);
161     OIC_LOG_BUFFER(DEBUG, TAG, buffer, len);
162
163     item->len += len;
164
165     return CA_STATUS_OK;
166 }
167
168 static void CATCPDestroyMutex()
169 {
170     if (g_mutexObjectList)
171     {
172         ca_mutex_free(g_mutexObjectList);
173         g_mutexObjectList = NULL;
174     }
175 }
176
177 static CAResult_t CATCPCreateMutex()
178 {
179     if (!g_mutexObjectList)
180     {
181         g_mutexObjectList = ca_mutex_new();
182         if (!g_mutexObjectList)
183         {
184             OIC_LOG(ERROR, TAG, "Failed to created mutex!");
185             return CA_STATUS_FAILED;
186         }
187     }
188
189     return CA_STATUS_OK;
190 }
191
192 static void CATCPDestroyCond()
193 {
194     if (g_condObjectList)
195     {
196         ca_cond_free(g_condObjectList);
197         g_condObjectList = NULL;
198     }
199 }
200
201 static CAResult_t CATCPCreateCond()
202 {
203     if (!g_condObjectList)
204     {
205         g_condObjectList = ca_cond_new();
206         if (!g_condObjectList)
207         {
208             OIC_LOG(ERROR, TAG, "Failed to created cond!");
209             return CA_STATUS_FAILED;
210         }
211     }
212     return CA_STATUS_OK;
213 }
214
215 static void CAReceiveHandler(void *data)
216 {
217     (void)data;
218     OIC_LOG(DEBUG, TAG, "IN - CAReceiveHandler");
219
220     while (!caglobals.tcp.terminate)
221     {
222         CAFindReadyMessage();
223     }
224
225     ca_mutex_lock(g_mutexObjectList);
226     ca_cond_signal(g_condObjectList);
227     ca_mutex_unlock(g_mutexObjectList);
228
229     OIC_LOG(DEBUG, TAG, "OUT - CAReceiveHandler");
230 }
231
232 static void CAFindReadyMessage()
233 {
234     fd_set readFds;
235     struct timeval timeout = { .tv_sec = caglobals.tcp.selectTimeout };
236
237     FD_ZERO(&readFds);
238     CA_FD_SET(ipv4, &readFds);
239     CA_FD_SET(ipv4s, &readFds);
240     CA_FD_SET(ipv6, &readFds);
241     CA_FD_SET(ipv6s, &readFds);
242
243     if (OC_INVALID_SOCKET != caglobals.tcp.shutdownFds[0])
244     {
245         FD_SET(caglobals.tcp.shutdownFds[0], &readFds);
246     }
247     if (OC_INVALID_SOCKET != caglobals.tcp.connectionFds[0])
248     {
249         FD_SET(caglobals.tcp.connectionFds[0], &readFds);
250     }
251
252     uint32_t length = u_arraylist_length(caglobals.tcp.svrlist);
253     for (size_t i = 0; i < length; i++)
254     {
255         CATCPSessionInfo_t *svritem =
256                 (CATCPSessionInfo_t *) u_arraylist_get(caglobals.tcp.svrlist, i);
257         if (svritem && 0 <= svritem->fd && CONNECTED == svritem->state)
258         {
259             FD_SET(svritem->fd, &readFds);
260         }
261     }
262
263     int ret = select(caglobals.tcp.maxfd + 1, &readFds, NULL, NULL, &timeout);
264
265     if (caglobals.tcp.terminate)
266     {
267         OIC_LOG_V(DEBUG, TAG, "Packet receiver Stop request received.");
268         return;
269     }
270
271     if (0 < ret)
272     {
273         CASelectReturned(&readFds);
274     }
275     else if (0 > ret)
276     {
277         OIC_LOG_V(FATAL, TAG, "select error %s", strerror(errno));
278     }
279 }
280
281 static void CASelectReturned(fd_set *readFds)
282 {
283     VERIFY_NON_NULL_VOID(readFds, TAG, "readFds is NULL");
284
285     if (caglobals.tcp.ipv4.fd != -1 && FD_ISSET(caglobals.tcp.ipv4.fd, readFds))
286     {
287         CAAcceptConnection(CA_IPV4, &caglobals.tcp.ipv4);
288         return;
289     }
290     else if (caglobals.tcp.ipv4s.fd != -1 && FD_ISSET(caglobals.tcp.ipv4s.fd, readFds))
291     {
292         CAAcceptConnection(CA_IPV4 | CA_SECURE, &caglobals.tcp.ipv4s);
293         return;
294     }
295     else if (caglobals.tcp.ipv6.fd != -1 && FD_ISSET(caglobals.tcp.ipv6.fd, readFds))
296     {
297         CAAcceptConnection(CA_IPV6, &caglobals.tcp.ipv6);
298         return;
299     }
300     else if (caglobals.tcp.ipv6s.fd != -1 && FD_ISSET(caglobals.tcp.ipv6s.fd, readFds))
301     {
302         CAAcceptConnection(CA_IPV6 | CA_SECURE, &caglobals.tcp.ipv6s);
303         return;
304     }
305     else if (-1 != caglobals.tcp.connectionFds[0] &&
306             FD_ISSET(caglobals.tcp.connectionFds[0], readFds))
307     {
308         // new connection was created from remote device.
309         // exit the function to update read file descriptor.
310         char buf[MAX_ADDR_STR_SIZE_CA] = {0};
311         ssize_t len = read(caglobals.tcp.connectionFds[0], buf, sizeof (buf));
312         if (-1 == len)
313         {
314             return;
315         }
316         OIC_LOG_V(DEBUG, TAG, "Received new connection event with [%s]", buf);
317         FD_CLR(caglobals.tcp.connectionFds[0], readFds);
318         return;
319     }
320     else
321     {
322         uint32_t length = u_arraylist_length(caglobals.tcp.svrlist);
323         for (size_t i = 0; i < length; i++)
324         {
325             CATCPSessionInfo_t *svritem =
326                     (CATCPSessionInfo_t *) u_arraylist_get(caglobals.tcp.svrlist, i);
327             if (svritem && svritem->fd >= 0)
328             {
329                 if (FD_ISSET(svritem->fd, readFds))
330                 {
331                     CAReceiveMessage(svritem->fd);
332                     if (-1 != svritem->fd)
333                     {
334                         FD_CLR(svritem->fd, readFds);
335                     }
336                 }
337             }
338         }
339     }
340 }
341
342 static void CAAcceptConnection(CATransportFlags_t flag, CASocket_t *sock)
343 {
344     VERIFY_NON_NULL_VOID(sock, TAG, "sock is NULL");
345
346     struct sockaddr_storage clientaddr;
347     socklen_t clientlen = sizeof (struct sockaddr_in);
348     if (flag & CA_IPV6)
349     {
350         clientlen = sizeof(struct sockaddr_in6);
351     }
352
353     CASocketFd_t sockfd = accept(sock->fd, (struct sockaddr *)&clientaddr, &clientlen);
354     if (OC_INVALID_SOCKET != sockfd)
355     {
356         CATCPSessionInfo_t *svritem =
357                 (CATCPSessionInfo_t *) OICCalloc(1, sizeof (*svritem));
358         if (!svritem)
359         {
360             OIC_LOG(ERROR, TAG, "Out of memory");
361             close(sockfd);
362             return;
363         }
364
365         svritem->fd = sockfd;
366         svritem->sep.endpoint.flags = flag;
367         svritem->sep.endpoint.adapter = CA_ADAPTER_TCP;
368         svritem->state = CONNECTED;
369         CAConvertAddrToName((struct sockaddr_storage *)&clientaddr, clientlen,
370                             svritem->sep.endpoint.addr, &svritem->sep.endpoint.port);
371
372         ca_mutex_lock(g_mutexObjectList);
373         bool result = u_arraylist_add(caglobals.tcp.svrlist, svritem);
374         if (!result)
375         {
376             OIC_LOG(ERROR, TAG, "u_arraylist_add failed.");
377             close(sockfd);
378             OICFree(svritem);
379             ca_mutex_unlock(g_mutexObjectList);
380             return;
381         }
382         ca_mutex_unlock(g_mutexObjectList);
383
384         CHECKFD(sockfd);
385
386         // pass the connection information to CA Common Layer.
387         if (g_connectionCallback)
388         {
389             g_connectionCallback(&(svritem->sep.endpoint), true);
390         }
391     }
392 }
393
394 #ifdef __WITH_TLS__
395 static bool CAIsTlsMessage(const unsigned char* data, size_t length)
396 {
397     if (NULL == data || 0 == length)
398     {
399         OIC_LOG_V(ERROR, TAG, "%s: null input param", __func__);
400         return false;
401     }
402
403     unsigned char first_byte = data[0];
404
405     //TLS Plaintext has four types: change_cipher_spec = [14], alert = [15],
406     //handshake = [16], application_data = [17] in HEX
407     const uint8_t tls_head_type[] = {0x14, 0x15, 0x16, 0x17};
408     size_t i = 0;
409
410     for (i = 0; i < sizeof(tls_head_type); i++)
411     {
412         if(tls_head_type[i] == first_byte)
413         {
414             return true;
415         }
416     }
417
418     return false;
419 }
420 #endif
421
422 /**
423  * Clean socket state data
424  *
425  * @param[in/out] item - socket state data
426  */
427 void CACleanData(CATCPSessionInfo_t *svritem)
428 {
429     if (svritem)
430     {
431         OICFree(svritem->data);
432         svritem->data = NULL;
433         svritem->len = 0;
434         svritem->tlsLen = 0;
435         svritem->totalLen = 0;
436         svritem->protocol = UNKNOWN;
437     }
438 }
439
440 /**
441  * Construct CoAP header and payload from buffer
442  *
443  * @param[in] svritem - used socket, buffer, current received message length and protocol
444  * @param[in/out]  data  - data buffer, this value is updated as data is copied to svritem
445  * @param[in/out]  dataLength  - length of data, this value decreased as data is copied to svritem
446  * @return             - CA_STATUS_OK or appropriate error code
447  */
448 CAResult_t CAConstructCoAP(CATCPSessionInfo_t *svritem, unsigned char **data,
449                           size_t *dataLength)
450 {
451     OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
452
453     if (NULL == svritem || NULL == data || NULL == dataLength)
454     {
455         OIC_LOG(ERROR, TAG, "Invalid input parameter(NULL)");
456         return CA_STATUS_INVALID_PARAM;
457     }
458
459     unsigned char *inBuffer = *data;
460     size_t inLen = *dataLength;
461     OIC_LOG_V(DEBUG, TAG, "before-datalength : %u", *dataLength);
462
463     if (NULL == svritem->data && inLen > 0)
464     {
465         // allocate memory for message header (CoAP header size because it is bigger)
466         svritem->data = (unsigned char *) OICCalloc(1, COAP_MAX_HEADER_SIZE);
467         if (NULL == svritem->data)
468         {
469             OIC_LOG(ERROR, TAG, "OICCalloc - out of memory");
470             return CA_MEMORY_ALLOC_FAILED;
471         }
472
473         // copy 1 byte to parse coap header length
474         memcpy(svritem->data, inBuffer, 1);
475         svritem->len = 1;
476         inBuffer++;
477         inLen--;
478     }
479
480     //if not enough data received - read them on next CAFillHeader() call
481     if (0 == inLen)
482     {
483         return CA_STATUS_OK;
484     }
485
486     //if enough data received - parse header
487     svritem->protocol = COAP;
488
489     //seems CoAP data received. read full coap header.
490     coap_transport_t transport = coap_get_tcp_header_type_from_initbyte(svritem->data[0] >> 4);
491     size_t headerLen = coap_get_tcp_header_length_for_transport(transport);
492     size_t copyLen = 0;
493
494     // HEADER
495     if (svritem->len < headerLen)
496     {
497         copyLen = headerLen - svritem->len;
498         if (inLen < copyLen)
499         {
500             copyLen = inLen;
501         }
502
503         //read required bytes to have full CoAP header
504         memcpy(svritem->data + svritem->len, inBuffer, copyLen);
505         svritem->len += copyLen;
506         inBuffer += copyLen;
507         inLen -= copyLen;
508
509         //if not enough data received - read them on next CAFillHeader() call
510         if (svritem->len < headerLen)
511         {
512             *data = inBuffer;
513             *dataLength = inLen;
514             OIC_LOG(DEBUG, TAG, "CoAP header received partially. Wait for rest header data");
515             return CA_STATUS_OK;
516         }
517
518         //calculate CoAP message length
519         svritem->totalLen = CAGetTotalLengthFromHeader(svritem->data);
520
521         // allocate required memory
522         unsigned char *buffer = OICRealloc(svritem->data, svritem->totalLen);
523         if (NULL == buffer)
524         {
525             OIC_LOG(ERROR, TAG, "OICRealloc - out of memory");
526             return CA_MEMORY_ALLOC_FAILED;
527         }
528         svritem->data = buffer;
529     }
530
531     // PAYLOAD
532     if (inLen > 0)
533     {
534         // read required bytes to have full CoAP payload
535         copyLen = svritem->totalLen - svritem->len;
536         if (inLen < copyLen)
537         {
538             copyLen = inLen;
539         }
540
541         //read required bytes to have full CoAP header
542         memcpy(svritem->data + svritem->len, inBuffer, copyLen);
543         svritem->len += copyLen;
544         inBuffer += copyLen;
545         inLen -= copyLen;
546     }
547
548     *data = inBuffer;
549     *dataLength = inLen;
550
551     OIC_LOG_V(DEBUG, TAG, "after-datalength : %u", *dataLength);
552     OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
553     return CA_STATUS_OK;
554 }
555
556 /**
557  * Read message header from socket item->fd
558  *
559  * @param[in/out] item - used socket, buffer, current received message length and protocol
560  * @return             - CA_STATUS_OK or appropriate error code
561  */
562 static CAResult_t CAReadHeader(CATCPSessionInfo_t *svritem)
563 {
564     CAResult_t res = CA_STATUS_OK;
565
566     if (NULL == svritem)
567     {
568         return CA_STATUS_INVALID_PARAM;
569     }
570
571     if (NULL == svritem->data)
572     {
573         // allocate memory for message header (CoAP header size because it is bigger)
574         svritem->data = (unsigned char *) OICCalloc(1, COAP_MAX_HEADER_SIZE);
575         if (NULL == svritem->data)
576         {
577             OIC_LOG(ERROR, TAG, "OICCalloc - out of memory");
578             return CA_MEMORY_ALLOC_FAILED;
579         }
580     }
581
582     //read data (assume TLS header) from remote device.
583     //use TLS_HEADER_SIZE - svritem->len because even header can be read partially
584     res = CARecv(svritem, TLS_HEADER_SIZE - svritem->len, 0);
585
586     //return if any error occurs
587     if (CA_STATUS_OK != res)
588     {
589         return res;
590     }
591
592     //if not enough data received - read them on next CAReceiveMessage() call
593     if (svritem->len < TLS_HEADER_SIZE)
594     {
595         OIC_LOG(DEBUG, TAG, "Header received partially. Wait for rest header data");
596         return CA_STATUS_OK;
597     }
598
599     //if enough data received - parse header
600 #ifdef __WITH_TLS__
601     if (CAIsTlsMessage(svritem->data, svritem->len))
602     {
603         svritem->protocol = TLS;
604
605         //[3][4] bytes in tls header are tls payload length
606         unsigned int message_length = (unsigned int)((svritem->data[3] << 8) | svritem->data[4]);
607         OIC_LOG_V(DEBUG, TAG, "%s: message_length = %d", __func__, message_length);
608
609         svritem->totalLen = message_length + TLS_HEADER_SIZE;
610     }
611     else
612 #endif
613     {
614         svritem->protocol = COAP;
615
616         //seems CoAP data received. read full coap header.
617         coap_transport_t transport = coap_get_tcp_header_type_from_initbyte(svritem->data[0] >> 4);
618
619         size_t headerLen = coap_get_tcp_header_length_for_transport(transport);
620
621         if (svritem->len < headerLen)
622         {
623             //read required bytes to have full CoAP header
624             //it should be 1 byte (COAP_MAX_HEADER_SIZE - TLS_HEADER_SIZE)
625             res = CARecv(svritem, headerLen - svritem->len, 0);
626
627             //return if any error occurs
628             if (CA_STATUS_OK != res)
629             {
630                 return res;
631             }
632
633             //if not enough data received - read them on next CAReceiveMessage() call
634             if (svritem->len < headerLen)
635             {
636                 OIC_LOG(DEBUG, TAG, "CoAP header received partially. Wait for rest header data");
637                 return CA_STATUS_OK;
638             }
639         }
640
641         //calculate CoAP message length
642         svritem->totalLen = CAGetTotalLengthFromHeader(svritem->data);
643     }
644
645     unsigned char *buffer = OICRealloc(svritem->data, svritem->totalLen);
646     if (NULL == buffer)
647     {
648         OIC_LOG(ERROR, TAG, "OICRealloc - out of memory");
649         return CA_MEMORY_ALLOC_FAILED;
650     }
651     svritem->data = buffer;
652
653     return CA_STATUS_OK;
654 }
655
656 /**
657  * Read message payload from socket item->fd
658
659  *
660  * @param[in/out] item - used socket, buffer and to update received message length
661  * @return             - CA_STATUS_OK or appropriate error code
662  */
663 static CAResult_t CAReadPayload(CATCPSessionInfo_t *svritem)
664 {
665     if (NULL == svritem)
666     {
667         return CA_STATUS_INVALID_PARAM;
668     }
669
670     return CARecv(svritem, svritem->totalLen - svritem->len, 0);
671 }
672
673 /**
674  * Pass received data to app layer depending on protocol
675  *
676  * @param[in/out] item - used buffer, received message length and protocol
677  */
678 static void CAExecuteRequest(CATCPSessionInfo_t *svritem)
679 {
680     if (NULL == svritem)
681     {
682         return;
683     }
684
685     switch(svritem->protocol)
686     {
687         case COAP:
688         {
689             if (g_packetReceivedCallback)
690             {
691                 g_packetReceivedCallback(&svritem->sep, svritem->data, svritem->len);
692             }
693         }
694         break;
695         case TLS:
696 #ifdef __WITH_TLS__
697         {
698             int ret = CAdecryptSsl(&svritem->sep, (uint8_t *)svritem->data, svritem->len);
699
700             OIC_LOG_V(DEBUG, TAG, "%s: CAdecryptSsl returned %d", __func__, ret);
701         }
702         break;
703 #endif
704         case UNKNOWN: /* pass through */
705         default:
706             OIC_LOG(ERROR, TAG, "unknown application protocol. Ignore it");
707         break;
708     }
709 }
710
711 static void CAReceiveMessage(int fd)
712 {
713     CAResult_t res = CA_STATUS_OK;
714
715     //get remote device information from file descriptor.
716     size_t index = 0;
717     CATCPSessionInfo_t *svritem = CAGetSessionInfoFromFD(fd, &index);
718     if (!svritem)
719     {
720         OIC_LOG(ERROR, TAG, "there is no connection information in list");
721         return;
722     }
723
724     // read data
725     int len = 0;
726
727     if (svritem->sep.endpoint.flags & CA_SECURE)
728     {
729         svritem->protocol = TLS;
730
731 #ifdef __WITH_TLS__
732         size_t nbRead = 0;
733         size_t tlsLength = 0;
734
735         if (TLS_HEADER_SIZE > svritem->tlsLen)
736         {
737             nbRead = TLS_HEADER_SIZE - svritem->tlsLen;
738         }
739         else
740         {
741             //[3][4] bytes in tls header are tls payload length
742             tlsLength = TLS_HEADER_SIZE +
743                             (size_t)((svritem->tlsdata[3] << 8) | svritem->tlsdata[4]);
744             OIC_LOG_V(DEBUG, TAG, "toal tls length = %u", tlsLength);
745             if (tlsLength > sizeof(svritem->tlsdata))
746             {
747                 OIC_LOG_V(ERROR, TAG, "toal tls length is too big (buffer size : %u)",
748                                     sizeof(svritem->tlsdata));
749                 return;
750             }
751             nbRead = tlsLength - svritem->tlsLen;
752         }
753
754         len = recv(fd, svritem->tlsdata + svritem->tlsLen, nbRead, 0);
755         if (len < 0)
756         {
757             OIC_LOG_V(ERROR, TAG, "recv failed %s", strerror(errno));
758             res = CA_RECEIVE_FAILED;
759         }
760         else if (0 == len)
761         {
762             OIC_LOG(INFO, TAG, "Received disconnect from peer. Close connection");
763             res = CA_DESTINATION_DISCONNECTED;
764         }
765         else
766         {
767             svritem->tlsLen += len;
768             OIC_LOG_V(DEBUG, TAG, "nb_read : %u bytes , recv() : %d bytes, svritem->tlsLen : %u bytes",
769                                 nbRead, len, svritem->tlsLen);
770             if (tlsLength > 0 && tlsLength == svritem->tlsLen)
771             {
772                 //when successfully read data - pass them to callback.
773                 res = CAdecryptSsl(&svritem->sep, (uint8_t *)svritem->tlsdata, svritem->tlsLen);
774                 svritem->tlsLen = 0;
775                 OIC_LOG_V(DEBUG, TAG, "%s: CAdecryptSsl returned %d", __func__, res);
776             }
777         }
778 #endif
779
780     }
781     else
782     {
783         unsigned char buffer[65535] = {0,}; // 65535 is the maximum size of ip packet
784         svritem->protocol = COAP;
785
786         len = recv(fd, buffer, sizeof(buffer), 0);
787         if (len < 0)
788         {
789             OIC_LOG_V(ERROR, TAG, "recv failed %s", strerror(errno));
790             res = CA_RECEIVE_FAILED;
791         }
792         else if (0 == len)
793         {
794             OIC_LOG(INFO, TAG, "Received disconnect from peer. Close connection");
795             res = CA_DESTINATION_DISCONNECTED;
796         }
797         else
798         {
799             OIC_LOG_V(DEBUG, TAG, "recv() : %d bytes", len);
800             //when successfully read data - pass them to callback.
801             if (g_packetReceivedCallback)
802             {
803                 g_packetReceivedCallback(&svritem->sep, buffer, len);
804             }
805         }
806     }
807
808     //disconnect session and clean-up data if any error occurs
809     if (res != CA_STATUS_OK)
810     {
811 #ifdef __WITH_TLS__
812         if (CA_STATUS_OK != CAcloseSslConnection(&svritem->sep.endpoint))
813         {
814             OIC_LOG(ERROR, TAG, "Failed to close TLS session");
815         }
816 #endif
817         CASearchAndDeleteTCPSession(&(svritem->sep.endpoint));
818         return;
819     }
820 }
821
822 static ssize_t CAWakeUpForReadFdsUpdate(const char *host)
823 {
824     if (caglobals.tcp.connectionFds[1] != -1)
825     {
826         ssize_t len = 0;
827         do
828         {
829             len = write(caglobals.tcp.connectionFds[1], host, strlen(host));
830         } while ((len == -1) && (errno == EINTR));
831
832         if ((len == -1) && (errno != EINTR) && (errno != EPIPE))
833         {
834             OIC_LOG_V(DEBUG, TAG, "write failed: %s", strerror(errno));
835         }
836         return len;
837     }
838     return -1;
839 }
840
841 static CAResult_t CATCPConvertNameToAddr(int family, const char *host, uint16_t port,
842                                          struct sockaddr_storage *sockaddr)
843 {
844     struct addrinfo *addrs = NULL;
845     struct addrinfo hints = { .ai_family = family,
846                               .ai_protocol   = IPPROTO_TCP,
847                               .ai_socktype = SOCK_STREAM,
848                               .ai_flags = AI_NUMERICHOST };
849
850     int r = getaddrinfo(host, NULL, &hints, &addrs);
851     if (r)
852     {
853         if (EAI_SYSTEM == r)
854         {
855             OIC_LOG_V(ERROR, TAG, "getaddrinfo failed: errno %s", strerror(errno));
856         }
857         else
858         {
859             OIC_LOG_V(ERROR, TAG, "getaddrinfo failed: %s", gai_strerror(r));
860         }
861         freeaddrinfo(addrs);
862         return CA_STATUS_FAILED;
863     }
864     // assumption: in this case, getaddrinfo will only return one addrinfo
865     // or first is the one we want.
866     if (addrs[0].ai_family == AF_INET6)
867     {
868         memcpy(sockaddr, addrs[0].ai_addr, sizeof (struct sockaddr_in6));
869         ((struct sockaddr_in6 *)sockaddr)->sin6_port = htons(port);
870     }
871     else
872     {
873         memcpy(sockaddr, addrs[0].ai_addr, sizeof (struct sockaddr_in));
874         ((struct sockaddr_in *)sockaddr)->sin_port = htons(port);
875     }
876     freeaddrinfo(addrs);
877     return CA_STATUS_OK;
878 }
879
880 static CAResult_t CATCPCreateSocket(int family, CATCPSessionInfo_t *svritem)
881 {
882     VERIFY_NON_NULL(svritem, TAG, "svritem is NULL");
883
884     OIC_LOG_V(DEBUG, TAG, "try to connect with [%s:%u]",
885               svritem->sep.endpoint.addr, svritem->sep.endpoint.port);
886
887     // #1. create tcp socket.
888     int fd = socket(family, SOCK_STREAM, IPPROTO_TCP);
889     if (-1 == fd)
890     {
891         OIC_LOG_V(ERROR, TAG, "create socket failed: %s", strerror(errno));
892         return CA_SOCKET_OPERATION_FAILED;
893     }
894     svritem->fd = fd;
895
896     // #2. convert address from string to binary.
897     struct sockaddr_storage sa = { .ss_family = family };
898     CAResult_t res = CATCPConvertNameToAddr(family, svritem->sep.endpoint.addr,
899                                             svritem->sep.endpoint.port, &sa);
900     if (CA_STATUS_OK != res)
901     {
902         OIC_LOG(ERROR, TAG, "convert name to sockaddr failed");
903         return CA_SOCKET_OPERATION_FAILED;
904     }
905
906     // #3. set socket length.
907     socklen_t socklen = 0;
908     if (sa.ss_family == AF_INET6)
909     {
910         struct sockaddr_in6 *sock6 = (struct sockaddr_in6 *)&sa;
911         if (!sock6->sin6_scope_id)
912         {
913             sock6->sin6_scope_id = svritem->sep.endpoint.ifindex;
914         }
915         socklen = sizeof(struct sockaddr_in6);
916     }
917     else
918     {
919         socklen = sizeof(struct sockaddr_in);
920     }
921
922     // #4. connect to remote server device.
923     if (connect(fd, (struct sockaddr *)&sa, socklen) < 0)
924     {
925         OIC_LOG_V(ERROR, TAG, "failed to connect socket, %s", strerror(errno));
926         return CA_SOCKET_OPERATION_FAILED;
927     }
928
929     OIC_LOG(DEBUG, TAG, "connect socket success");
930     svritem->state = CONNECTED;
931     CHECKFD(svritem->fd);
932     ssize_t len = CAWakeUpForReadFdsUpdate(svritem->sep.endpoint.addr);
933     if (-1 == len)
934     {
935         OIC_LOG(ERROR, TAG, "wakeup receive thread failed");
936         return CA_SOCKET_OPERATION_FAILED;
937     }
938     return CA_STATUS_OK;
939 }
940
941 static CASocketFd_t CACreateAcceptSocket(int family, CASocket_t *sock)
942 {
943     VERIFY_NON_NULL_RET(sock, TAG, "sock", -1);
944
945     if (OC_INVALID_SOCKET != sock->fd)
946     {
947         OIC_LOG(DEBUG, TAG, "accept socket created already");
948         return sock->fd;
949     }
950
951     socklen_t socklen = 0;
952     struct sockaddr_storage server = { .ss_family = family };
953
954     int fd = socket(family, SOCK_STREAM, IPPROTO_TCP);
955     if (OC_INVALID_SOCKET == fd)
956     {
957         OIC_LOG(ERROR, TAG, "Failed to create socket");
958         goto exit;
959     }
960
961     if (family == AF_INET6)
962     {
963         // the socket is restricted to sending and receiving IPv6 packets only.
964         int on = 1;
965         if (-1 == setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof (on)))
966         {
967             OIC_LOG_V(ERROR, TAG, "IPV6_V6ONLY failed: %s", strerror(errno));
968             goto exit;
969         }
970         ((struct sockaddr_in6 *)&server)->sin6_port = htons(sock->port);
971         socklen = sizeof (struct sockaddr_in6);
972     }
973     else
974     {
975         ((struct sockaddr_in *)&server)->sin_port = htons(sock->port);
976         socklen = sizeof (struct sockaddr_in);
977     }
978
979     int reuse = 1;
980     if (-1 == setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)))
981     {
982         OIC_LOG(ERROR, TAG, "setsockopt SO_REUSEADDR");
983         goto exit;
984     }
985
986     if (-1 == bind(fd, (struct sockaddr *)&server, socklen))
987     {
988         OIC_LOG_V(ERROR, TAG, "bind socket failed: %s", strerror(errno));
989         goto exit;
990     }
991
992     if (listen(fd, caglobals.tcp.listenBacklog) != 0)
993     {
994         OIC_LOG(ERROR, TAG, "listen() error");
995         goto exit;
996     }
997
998     if (!sock->port)  // return the assigned port
999     {
1000         if (-1 == getsockname(fd, (struct sockaddr *)&server, &socklen))
1001         {
1002             OIC_LOG_V(ERROR, TAG, "getsockname failed: %s", strerror(errno));
1003             goto exit;
1004         }
1005         sock->port = ntohs(family == AF_INET6 ?
1006                       ((struct sockaddr_in6 *)&server)->sin6_port :
1007                       ((struct sockaddr_in *)&server)->sin_port);
1008     }
1009
1010     return fd;
1011
1012 exit:
1013     if (fd >= 0)
1014     {
1015         close(fd);
1016     }
1017     return OC_INVALID_SOCKET;
1018 }
1019
1020 static void CAInitializePipe(int *fds)
1021 {
1022     int ret = pipe(fds);
1023     if (-1 != ret)
1024     {
1025         ret = fcntl(fds[0], F_GETFD);
1026         if (-1 != ret)
1027         {
1028             ret = fcntl(fds[0], F_SETFD, ret|FD_CLOEXEC);
1029         }
1030         if (-1 != ret)
1031         {
1032             ret = fcntl(fds[1], F_GETFD);
1033         }
1034         if (-1 != ret)
1035         {
1036             ret = fcntl(fds[1], F_SETFD, ret|FD_CLOEXEC);
1037         }
1038         if (-1 == ret)
1039         {
1040             close(fds[1]);
1041             close(fds[0]);
1042
1043             fds[0] = -1;
1044             fds[1] = -1;
1045
1046             OIC_LOG_V(ERROR, TAG, "pipe failed: %s", strerror(errno));
1047         }
1048     }
1049 }
1050
1051 #define NEWSOCKET(FAMILY, NAME) \
1052     caglobals.tcp.NAME.fd = CACreateAcceptSocket(FAMILY, &caglobals.tcp.NAME); \
1053     if (caglobals.tcp.NAME.fd == -1) \
1054     { \
1055         caglobals.tcp.NAME.port = 0; \
1056         caglobals.tcp.NAME.fd = CACreateAcceptSocket(FAMILY, &caglobals.tcp.NAME); \
1057     } \
1058     CHECKFD(caglobals.tcp.NAME.fd);
1059
1060 CAResult_t CATCPStartServer(const ca_thread_pool_t threadPool)
1061 {
1062     if (caglobals.tcp.started)
1063     {
1064         OIC_LOG(DEBUG, TAG, "Adapter is started already");
1065         return CA_STATUS_OK;
1066     }
1067
1068     if (!caglobals.tcp.ipv4tcpenabled)
1069     {
1070         caglobals.tcp.ipv4tcpenabled = true;    // only needed to run CA tests
1071     }
1072     if (!caglobals.tcp.ipv6tcpenabled)
1073     {
1074         caglobals.tcp.ipv6tcpenabled = true;    // only needed to run CA tests
1075     }
1076
1077     CAResult_t res = CATCPCreateMutex();
1078     if (CA_STATUS_OK == res)
1079     {
1080         res = CATCPCreateCond();
1081     }
1082     if (CA_STATUS_OK != res)
1083     {
1084         OIC_LOG(ERROR, TAG, "failed to create mutex/cond");
1085         return res;
1086     }
1087
1088     ca_mutex_lock(g_mutexObjectList);
1089     if (!caglobals.tcp.svrlist)
1090     {
1091         caglobals.tcp.svrlist = u_arraylist_create();
1092     }
1093     ca_mutex_unlock(g_mutexObjectList);
1094
1095     if (caglobals.server)
1096     {
1097         NEWSOCKET(AF_INET, ipv4);
1098         NEWSOCKET(AF_INET, ipv4s);
1099         NEWSOCKET(AF_INET6, ipv6);
1100         NEWSOCKET(AF_INET6, ipv6s);
1101         OIC_LOG_V(DEBUG, TAG, "IPv4 socket fd=%d, port=%d",
1102                   caglobals.tcp.ipv4.fd, caglobals.tcp.ipv4.port);
1103         OIC_LOG_V(DEBUG, TAG, "IPv4 secure socket fd=%d, port=%d",
1104                   caglobals.tcp.ipv4s.fd, caglobals.tcp.ipv4s.port);
1105         OIC_LOG_V(DEBUG, TAG, "IPv6 socket fd=%d, port=%d",
1106                   caglobals.tcp.ipv6.fd, caglobals.tcp.ipv6.port);
1107         OIC_LOG_V(DEBUG, TAG, "IPv6 secure socket fd=%d, port=%d",
1108                   caglobals.tcp.ipv6s.fd, caglobals.tcp.ipv6s.port);
1109     }
1110
1111     // create pipe for fast shutdown
1112     CAInitializePipe(caglobals.tcp.shutdownFds);
1113     CHECKFD(caglobals.tcp.shutdownFds[0]);
1114     CHECKFD(caglobals.tcp.shutdownFds[1]);
1115
1116     // create pipe for connection event
1117     CAInitializePipe(caglobals.tcp.connectionFds);
1118     CHECKFD(caglobals.tcp.connectionFds[0]);
1119     CHECKFD(caglobals.tcp.connectionFds[1]);
1120
1121     caglobals.tcp.terminate = false;
1122     res = ca_thread_pool_add_task(threadPool, CAReceiveHandler, NULL);
1123     if (CA_STATUS_OK != res)
1124     {
1125         OIC_LOG(ERROR, TAG, "thread_pool_add_task failed");
1126         return res;
1127     }
1128     OIC_LOG(DEBUG, TAG, "CAReceiveHandler thread started successfully.");
1129
1130     caglobals.tcp.started = true;
1131     return CA_STATUS_OK;
1132 }
1133
1134 void CATCPStopServer()
1135 {
1136     if (caglobals.tcp.terminate)
1137     {
1138         OIC_LOG(DEBUG, TAG, "Adapter is not enabled");
1139         return;
1140     }
1141
1142     // mutex lock
1143     ca_mutex_lock(g_mutexObjectList);
1144
1145     // set terminate flag.
1146     caglobals.tcp.terminate = true;
1147
1148     if (caglobals.tcp.shutdownFds[1] != -1)
1149     {
1150         close(caglobals.tcp.shutdownFds[1]);
1151         caglobals.tcp.shutdownFds[1] = OC_INVALID_SOCKET;
1152         // receive thread will stop immediately
1153     }
1154     if (caglobals.tcp.connectionFds[1] != -1)
1155     {
1156         close(caglobals.tcp.connectionFds[1]);
1157         caglobals.tcp.connectionFds[1] = OC_INVALID_SOCKET;
1158     }
1159
1160     // close accept socket.
1161     CLOSE_SOCKET(ipv4);
1162     CLOSE_SOCKET(ipv4s);
1163     CLOSE_SOCKET(ipv6);
1164     CLOSE_SOCKET(ipv6s);
1165
1166     if (caglobals.tcp.started)
1167     {
1168         ca_cond_wait(g_condObjectList, g_mutexObjectList);
1169     }
1170     caglobals.tcp.started = false;
1171
1172     // mutex unlock
1173     ca_mutex_unlock(g_mutexObjectList);
1174
1175     CATCPDisconnectAll();
1176     CATCPDestroyMutex();
1177     CATCPDestroyCond();
1178
1179     OIC_LOG(DEBUG, TAG, "Adapter terminated successfully");
1180 }
1181
1182 void CATCPSetPacketReceiveCallback(CATCPPacketReceivedCallback callback)
1183 {
1184     g_packetReceivedCallback = callback;
1185 }
1186
1187 void CATCPSetConnectionChangedCallback(CATCPConnectionHandleCallback connHandler)
1188 {
1189     g_connectionCallback = connHandler;
1190 }
1191
1192 size_t CACheckPayloadLengthFromHeader(const void *data, size_t dlen)
1193 {
1194     VERIFY_NON_NULL_RET(data, TAG, "data", -1);
1195
1196     coap_transport_t transport = coap_get_tcp_header_type_from_initbyte(
1197             ((unsigned char *)data)[0] >> 4);
1198
1199     coap_pdu_t *pdu = coap_new_pdu2(transport, dlen);
1200     if (!pdu)
1201     {
1202         OIC_LOG(ERROR, TAG, "outpdu is null");
1203         return 0;
1204     }
1205
1206     int ret = coap_pdu_parse2((unsigned char *) data, dlen, pdu, transport);
1207     if (0 >= ret)
1208     {
1209         OIC_LOG(ERROR, TAG, "pdu parse failed");
1210         coap_delete_pdu(pdu);
1211         return 0;
1212     }
1213
1214     size_t payloadLen = 0;
1215     size_t headerSize = coap_get_tcp_header_length_for_transport(transport);
1216     OIC_LOG_V(DEBUG, TAG, "headerSize : %zu, pdu length : %d",
1217               headerSize, pdu->length);
1218     if (pdu->length > headerSize)
1219     {
1220         payloadLen = (unsigned char *) pdu->hdr + pdu->length - pdu->data;
1221     }
1222
1223     OICFree(pdu);
1224
1225     return payloadLen;
1226 }
1227
1228 static ssize_t sendData(const CAEndpoint_t *endpoint, const void *data,
1229                         size_t dlen, const char *fam)
1230 {
1231     OIC_LOG_V(INFO, TAG, "The length of data that needs to be sent is %zu bytes", dlen);
1232
1233     // #1. find a session info from list.
1234     CASocketFd_t sockFd = CAGetSocketFDFromEndpoint(endpoint);
1235     if (OC_INVALID_SOCKET == sockFd)
1236     {
1237         // if there is no connection info, connect to remote device.
1238         sockFd = CAConnectTCPSession(endpoint);
1239         if (OC_INVALID_SOCKET == sockFd)
1240         {
1241             OIC_LOG(ERROR, TAG, "Failed to create tcp session object");
1242             return -1;
1243         }
1244     }
1245
1246     // #2. send data to remote device.
1247     ssize_t remainLen = dlen;
1248     do
1249     {
1250         ssize_t len = send(sockFd, data, remainLen, 0);
1251         if (-1 == len)
1252         {
1253             if (EWOULDBLOCK != errno)
1254             {
1255                 OIC_LOG_V(ERROR, TAG, "unicast ipv4tcp sendTo failed: %s", strerror(errno));
1256                 return len;
1257             }
1258             continue;
1259         }
1260         data += len;
1261         remainLen -= len;
1262     } while (remainLen > 0);
1263
1264 #ifndef TB_LOG
1265     (void)fam;
1266 #endif
1267     OIC_LOG_V(INFO, TAG, "unicast %stcp sendTo is successful: %zu bytes", fam, dlen);
1268     return dlen;
1269 }
1270
1271 ssize_t CATCPSendData(CAEndpoint_t *endpoint, const void *data, size_t datalen)
1272 {
1273     VERIFY_NON_NULL_RET(endpoint, TAG, "endpoint is NULL", -1);
1274     VERIFY_NON_NULL_RET(data, TAG, "data is NULL", -1);
1275
1276     if (caglobals.tcp.ipv6tcpenabled && (endpoint->flags & CA_IPV6))
1277     {
1278         return sendData(endpoint, data, datalen, "ipv6");
1279     }
1280     if (caglobals.tcp.ipv4tcpenabled && (endpoint->flags & CA_IPV4))
1281     {
1282         return sendData(endpoint, data, datalen, "ipv4");
1283     }
1284
1285     OIC_LOG(ERROR, TAG, "Not supported transport flags");
1286     return -1;
1287 }
1288
1289 CAResult_t CAGetTCPInterfaceInformation(CAEndpoint_t **info, uint32_t *size)
1290 {
1291     VERIFY_NON_NULL(info, TAG, "info is NULL");
1292     VERIFY_NON_NULL(size, TAG, "size is NULL");
1293
1294     return CA_NOT_SUPPORTED;
1295 }
1296
1297 CASocketFd_t CAConnectTCPSession(const CAEndpoint_t *endpoint)
1298 {
1299     VERIFY_NON_NULL_RET(endpoint, TAG, "endpoint is NULL", OC_INVALID_SOCKET);
1300
1301     // #1. create TCP server object
1302     CATCPSessionInfo_t *svritem = (CATCPSessionInfo_t *) OICCalloc(1, sizeof (*svritem));
1303     if (!svritem)
1304     {
1305         OIC_LOG(ERROR, TAG, "Out of memory");
1306         return OC_INVALID_SOCKET;
1307     }
1308     memcpy(svritem->sep.endpoint.addr, endpoint->addr, sizeof(svritem->sep.endpoint.addr));
1309     svritem->sep.endpoint.adapter = endpoint->adapter;
1310     svritem->sep.endpoint.port = endpoint->port;
1311     svritem->sep.endpoint.flags = endpoint->flags;
1312     svritem->sep.endpoint.ifindex = endpoint->ifindex;
1313     svritem->state = CONNECTING;
1314
1315     // #2. add TCP connection info to list
1316     ca_mutex_lock(g_mutexObjectList);
1317     if (caglobals.tcp.svrlist)
1318     {
1319         bool res = u_arraylist_add(caglobals.tcp.svrlist, svritem);
1320         if (!res)
1321         {
1322             OIC_LOG(ERROR, TAG, "u_arraylist_add failed.");
1323             close(svritem->fd);
1324             OICFree(svritem);
1325             ca_mutex_unlock(g_mutexObjectList);
1326             return OC_INVALID_SOCKET;
1327         }
1328     }
1329     ca_mutex_unlock(g_mutexObjectList);
1330
1331     // #3. create the socket and connect to TCP server
1332     int family = (svritem->sep.endpoint.flags & CA_IPV6) ? AF_INET6 : AF_INET;
1333     if (CA_STATUS_OK != CATCPCreateSocket(family, svritem))
1334     {
1335         return OC_INVALID_SOCKET;
1336     }
1337
1338     // #4. pass the connection information to CA Common Layer.
1339     if (g_connectionCallback)
1340     {
1341         g_connectionCallback(&(svritem->sep.endpoint), true);
1342     }
1343
1344     return svritem->fd;
1345 }
1346
1347 CAResult_t CADisconnectTCPSession(size_t index)
1348 {
1349     CATCPSessionInfo_t *removedData = u_arraylist_remove(caglobals.tcp.svrlist, index);
1350     if (!removedData)
1351     {
1352         OIC_LOG(DEBUG, TAG, "there is no data to be removed");
1353         return CA_STATUS_OK;
1354     }
1355
1356     // close the socket and remove session info in list.
1357     if (removedData->fd >= 0)
1358     {
1359         shutdown(removedData->fd, SHUT_RDWR);
1360         close(removedData->fd);
1361         removedData->fd = -1;
1362         removedData->state = (CONNECTED == removedData->state) ?
1363                                     DISCONNECTED : removedData->state;
1364
1365         // pass the connection information to CA Common Layer.
1366         if (g_connectionCallback && DISCONNECTED == removedData->state)
1367         {
1368             g_connectionCallback(&(removedData->sep.endpoint), false);
1369         }
1370     }
1371     OICFree(removedData->data);
1372     removedData->data = NULL;
1373
1374     OICFree(removedData);
1375     removedData = NULL;
1376
1377     OIC_LOG(DEBUG, TAG, "data is removed from session list");
1378     return CA_STATUS_OK;
1379 }
1380
1381 void CATCPDisconnectAll()
1382 {
1383     ca_mutex_lock(g_mutexObjectList);
1384
1385     uint32_t length = u_arraylist_length(caglobals.tcp.svrlist);
1386     for (ssize_t index = length; index > 0; index--)
1387     {
1388         // disconnect session from remote device.
1389         CADisconnectTCPSession(index - 1);
1390     }
1391
1392     u_arraylist_destroy(caglobals.tcp.svrlist);
1393     caglobals.tcp.svrlist = NULL;
1394
1395     ca_mutex_unlock(g_mutexObjectList);
1396
1397 #ifdef __WITH_TLS__
1398     CAcloseSslConnectionAll();
1399 #endif
1400
1401 }
1402
1403 CATCPSessionInfo_t *CAGetTCPSessionInfoFromEndpoint(const CAEndpoint_t *endpoint, size_t *index)
1404 {
1405     VERIFY_NON_NULL_RET(endpoint, TAG, "endpoint is NULL", NULL);
1406     VERIFY_NON_NULL_RET(index, TAG, "index is NULL", NULL);
1407
1408     OIC_LOG_V(DEBUG, TAG, "Looking for [%s:%d]", endpoint->addr, endpoint->port);
1409
1410     // get connection info from list
1411     uint32_t length = u_arraylist_length(caglobals.tcp.svrlist);
1412     for (size_t i = 0; i < length; i++)
1413     {
1414         CATCPSessionInfo_t *svritem = (CATCPSessionInfo_t *) u_arraylist_get(
1415                 caglobals.tcp.svrlist, i);
1416         if (!svritem)
1417         {
1418             continue;
1419         }
1420
1421         if (!strncmp(svritem->sep.endpoint.addr, endpoint->addr,
1422                      sizeof(svritem->sep.endpoint.addr))
1423                 && (svritem->sep.endpoint.port == endpoint->port)
1424                 && (svritem->sep.endpoint.flags & endpoint->flags))
1425         {
1426             OIC_LOG(DEBUG, TAG, "Found in session list");
1427             *index = i;
1428             return svritem;
1429         }
1430     }
1431
1432     OIC_LOG(DEBUG, TAG, "Session not found");
1433     return NULL;
1434 }
1435
1436 CASocketFd_t CAGetSocketFDFromEndpoint(const CAEndpoint_t *endpoint)
1437 {
1438     VERIFY_NON_NULL_RET(endpoint, TAG, "endpoint is NULL", OC_INVALID_SOCKET);
1439
1440     OIC_LOG_V(DEBUG, TAG, "Looking for [%s:%d]", endpoint->addr, endpoint->port);
1441
1442     // get connection info from list.
1443     ca_mutex_lock(g_mutexObjectList);
1444     uint32_t length = u_arraylist_length(caglobals.tcp.svrlist);
1445     for (size_t i = 0; i < length; i++)
1446     {
1447         CATCPSessionInfo_t *svritem = (CATCPSessionInfo_t *) u_arraylist_get(
1448                 caglobals.tcp.svrlist, i);
1449         if (!svritem)
1450         {
1451             continue;
1452         }
1453
1454         if (!strncmp(svritem->sep.endpoint.addr, endpoint->addr,
1455                      sizeof(svritem->sep.endpoint.addr))
1456                 && (svritem->sep.endpoint.port == endpoint->port)
1457                 && (svritem->sep.endpoint.flags & endpoint->flags))
1458         {
1459             ca_mutex_unlock(g_mutexObjectList);
1460             OIC_LOG(DEBUG, TAG, "Found in session list");
1461             return svritem->fd;
1462         }
1463     }
1464
1465     ca_mutex_unlock(g_mutexObjectList);
1466     OIC_LOG(DEBUG, TAG, "Session not found");
1467     return OC_INVALID_SOCKET;
1468 }
1469
1470 CATCPSessionInfo_t *CAGetSessionInfoFromFD(int fd, size_t *index)
1471 {
1472     ca_mutex_lock(g_mutexObjectList);
1473
1474     // check from the last item.
1475     CATCPSessionInfo_t *svritem = NULL;
1476     uint32_t length = u_arraylist_length(caglobals.tcp.svrlist);
1477     for (size_t i = 0; i < length; i++)
1478     {
1479         svritem = (CATCPSessionInfo_t *) u_arraylist_get(caglobals.tcp.svrlist, i);
1480
1481         if (svritem && svritem->fd == fd)
1482         {
1483             *index = i;
1484             ca_mutex_unlock(g_mutexObjectList);
1485             return svritem;
1486         }
1487     }
1488
1489     ca_mutex_unlock(g_mutexObjectList);
1490
1491     return NULL;
1492 }
1493
1494 CAResult_t CASearchAndDeleteTCPSession(const CAEndpoint_t *endpoint)
1495 {
1496     ca_mutex_lock(g_mutexObjectList);
1497
1498     CAResult_t result = CA_STATUS_OK;
1499     size_t index = 0;
1500     CATCPSessionInfo_t *svritem = CAGetTCPSessionInfoFromEndpoint(endpoint, &index);
1501     if (svritem)
1502     {
1503         result = CADisconnectTCPSession(index);
1504         if (CA_STATUS_OK != result)
1505         {
1506             OIC_LOG_V(ERROR, TAG, "CADisconnectTCPSession failed, result[%d]", result);
1507         }
1508     }
1509
1510     ca_mutex_unlock(g_mutexObjectList);
1511     return result;
1512 }
1513
1514 size_t CAGetTotalLengthFromHeader(const unsigned char *recvBuffer)
1515 {
1516     OIC_LOG(DEBUG, TAG, "IN - CAGetTotalLengthFromHeader");
1517
1518     coap_transport_t transport = coap_get_tcp_header_type_from_initbyte(
1519             ((unsigned char *)recvBuffer)[0] >> 4);
1520     size_t optPaylaodLen = coap_get_length_from_header((unsigned char *)recvBuffer,
1521                                                         transport);
1522     size_t headerLen = coap_get_tcp_header_length((unsigned char *)recvBuffer);
1523
1524     OIC_LOG_V(DEBUG, TAG, "option/paylaod length [%zu]", optPaylaodLen);
1525     OIC_LOG_V(DEBUG, TAG, "header length [%zu]", headerLen);
1526     OIC_LOG_V(DEBUG, TAG, "total data length [%zu]", headerLen + optPaylaodLen);
1527
1528     OIC_LOG(DEBUG, TAG, "OUT - CAGetTotalLengthFromHeader");
1529     return headerLen + optPaylaodLen;
1530 }
1531
1532 void CATCPSetErrorHandler(CATCPErrorHandleCallback errorHandleCallback)
1533 {
1534     g_tcpErrorHandler = errorHandleCallback;
1535 }
1536