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