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