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