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