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