Merge "Merge remote-tracking branch 'origin/master' into notification-service" into...
[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 #define REALLOC(buffer, length) \
108 { \
109     unsigned char *tmpBuf = OICRealloc(buffer, length); \
110     if (!tmpBuf) \
111     { \
112         OIC_LOG(ERROR, TAG, "out of memory"); \
113         goto error; \
114     } \
115     buffer = tmpBuf; \
116 }
117
118 /**
119  * Read length amount of data from socket fd
120  * Made a few recv calls if required
121  *
122  * @param[in]  fd     - socket
123  * @param[out] item   - used to update received message length
124  * @param[out] data   - buffer to store data
125  * @param[in]  length - length of data required to read
126  * @param[in]  flags  - additional info about socket
127  */
128 #define RECV(fd, item, data, length, flags) \
129 { \
130     int remain_len = length; \
131     int len = 0; \
132     while (remain_len > 0) \
133     { \
134         len = recv(fd, data + item->len, remain_len, flags); \
135         OIC_LOG_V(DEBUG, TAG, "recv len = %d", len); \
136         OIC_LOG_BUFFER(DEBUG, TAG, data + item->len, len); \
137         if (2 == len && 0 == data[item->len] && 0 == data[item->len + 1]) \
138         { \
139             OIC_LOG(DEBUG, TAG, "received RESET message. Skip it"); \
140             continue; \
141         } \
142         if (len < 0) \
143         { \
144             OIC_LOG_V(ERROR, TAG, "recv failed %s", strerror(errno)); \
145             goto error; \
146         } \
147         else if (0 == len) \
148         { \
149             OIC_LOG(INFO, TAG, "Received disconnect from peer. Close connection"); \
150             goto error; \
151         } \
152         item->len += len; \
153         remain_len -= len; \
154     } \
155 }
156
157 static void CATCPDestroyMutex()
158 {
159     if (g_mutexObjectList)
160     {
161         ca_mutex_free(g_mutexObjectList);
162         g_mutexObjectList = NULL;
163     }
164 }
165
166 static CAResult_t CATCPCreateMutex()
167 {
168     if (!g_mutexObjectList)
169     {
170         g_mutexObjectList = ca_mutex_new();
171         if (!g_mutexObjectList)
172         {
173             OIC_LOG(ERROR, TAG, "Failed to created mutex!");
174             return CA_STATUS_FAILED;
175         }
176     }
177
178     return CA_STATUS_OK;
179 }
180
181 static void CATCPDestroyCond()
182 {
183     if (g_condObjectList)
184     {
185         ca_cond_free(g_condObjectList);
186         g_condObjectList = NULL;
187     }
188 }
189
190 static CAResult_t CATCPCreateCond()
191 {
192     if (!g_condObjectList)
193     {
194         g_condObjectList = ca_cond_new();
195         if (!g_condObjectList)
196         {
197             OIC_LOG(ERROR, TAG, "Failed to created cond!");
198             return CA_STATUS_FAILED;
199         }
200     }
201     return CA_STATUS_OK;
202 }
203
204 static void CAReceiveHandler(void *data)
205 {
206     (void)data;
207     OIC_LOG(DEBUG, TAG, "IN - CAReceiveHandler");
208
209     while (!caglobals.tcp.terminate)
210     {
211         CAFindReadyMessage();
212     }
213
214     ca_mutex_lock(g_mutexObjectList);
215     ca_cond_signal(g_condObjectList);
216     ca_mutex_unlock(g_mutexObjectList);
217
218     OIC_LOG(DEBUG, TAG, "OUT - CAReceiveHandler");
219 }
220
221 static void CAFindReadyMessage()
222 {
223     fd_set readFds;
224     struct timeval timeout = { .tv_sec = caglobals.tcp.selectTimeout };
225
226     FD_ZERO(&readFds);
227
228     if (-1 != caglobals.tcp.ipv4.fd)
229     {
230         FD_SET(caglobals.tcp.ipv4.fd, &readFds);
231     }
232     if (-1 != caglobals.tcp.ipv6.fd)
233     {
234         FD_SET(caglobals.tcp.ipv6.fd, &readFds);
235     }
236     if (-1 != caglobals.tcp.shutdownFds[0])
237     {
238         FD_SET(caglobals.tcp.shutdownFds[0], &readFds);
239     }
240     if (-1 != caglobals.tcp.connectionFds[0])
241     {
242         FD_SET(caglobals.tcp.connectionFds[0], &readFds);
243     }
244
245     uint32_t length = u_arraylist_length(caglobals.tcp.svrlist);
246     for (size_t i = 0; i < length; i++)
247     {
248         CATCPSessionInfo_t *svritem =
249                 (CATCPSessionInfo_t *) u_arraylist_get(caglobals.tcp.svrlist, i);
250         if (svritem && 0 <= svritem->fd)
251         {
252             FD_SET(svritem->fd, &readFds);
253         }
254     }
255
256     int ret = select(caglobals.tcp.maxfd + 1, &readFds, NULL, NULL, &timeout);
257
258     if (caglobals.tcp.terminate)
259     {
260         OIC_LOG_V(DEBUG, TAG, "Packet receiver Stop request received.");
261         return;
262     }
263     if (0 >= ret)
264     {
265         if (0 > ret)
266         {
267             OIC_LOG_V(FATAL, TAG, "select error %s", strerror(errno));
268         }
269         return;
270     }
271
272     CASelectReturned(&readFds);
273 }
274
275 static void CASelectReturned(fd_set *readFds)
276 {
277     VERIFY_NON_NULL_VOID(readFds, TAG, "readFds is NULL");
278
279     if (caglobals.tcp.ipv4.fd != -1 && FD_ISSET(caglobals.tcp.ipv4.fd, readFds))
280     {
281         CAAcceptConnection(CA_IPV4, &caglobals.tcp.ipv4);
282         return;
283     }
284     else if (caglobals.tcp.ipv6.fd != -1 && FD_ISSET(caglobals.tcp.ipv6.fd, readFds))
285     {
286         CAAcceptConnection(CA_IPV6, &caglobals.tcp.ipv6);
287         return;
288     }
289     else if (-1 != caglobals.tcp.connectionFds[0] &&
290             FD_ISSET(caglobals.tcp.connectionFds[0], readFds))
291     {
292         // new connection was created from remote device.
293         // exit the function to update read file descriptor.
294         char buf[MAX_ADDR_STR_SIZE_CA] = {0};
295         ssize_t len = read(caglobals.tcp.connectionFds[0], buf, sizeof (buf));
296         if (-1 == len)
297         {
298             return;
299         }
300         OIC_LOG_V(DEBUG, TAG, "Received new connection event with [%s]", buf);
301         FD_CLR(caglobals.tcp.connectionFds[0], readFds);
302         return;
303     }
304     else if (-1 != caglobals.tcp.connectionFds[0] &&
305             FD_ISSET(caglobals.tcp.connectionFds[0], readFds))
306     {
307         // new connection was created from remote device.
308         // exit the function to update read file descriptor.
309         char buf[MAX_ADDR_STR_SIZE_CA] = {0};
310         ssize_t len = read(caglobals.tcp.connectionFds[0], buf, sizeof (buf));
311         if (-1 == len)
312         {
313             return;
314         }
315         OIC_LOG_V(DEBUG, TAG, "Received new connection event with [%s]", buf);
316         FD_CLR(caglobals.tcp.connectionFds[0], readFds);
317         return;
318     }
319     else
320     {
321         uint32_t length = u_arraylist_length(caglobals.tcp.svrlist);
322         for (size_t i = 0; i < length; i++)
323         {
324             CATCPSessionInfo_t *svritem =
325                     (CATCPSessionInfo_t *) u_arraylist_get(caglobals.tcp.svrlist, i);
326             if (svritem && svritem->fd >= 0)
327             {
328                 if (FD_ISSET(svritem->fd, readFds))
329                 {
330                     CAReceiveMessage(svritem->fd);
331                     FD_CLR(svritem->fd, readFds);
332                 }
333             }
334         }
335     }
336 }
337
338 static void CAAcceptConnection(CATransportFlags_t flag, CASocket_t *sock)
339 {
340     VERIFY_NON_NULL_VOID(sock, TAG, "sock is NULL");
341
342     struct sockaddr_storage clientaddr;
343     socklen_t clientlen = sizeof (struct sockaddr_in);
344     if (flag & CA_IPV6)
345     {
346         clientlen = sizeof(struct sockaddr_in6);
347     }
348
349     int sockfd = accept(sock->fd, (struct sockaddr *)&clientaddr, &clientlen);
350     if (-1 != sockfd)
351     {
352         CATCPSessionInfo_t *svritem =
353                 (CATCPSessionInfo_t *) OICCalloc(1, sizeof (*svritem));
354         if (!svritem)
355         {
356             OIC_LOG(ERROR, TAG, "Out of memory");
357             close(sockfd);
358             return;
359         }
360
361         svritem->fd = sockfd;
362         svritem->sep.endpoint.flags = flag;
363         CAConvertAddrToName((struct sockaddr_storage *)&clientaddr, clientlen,
364                             svritem->sep.endpoint.addr, &svritem->sep.endpoint.port);
365
366         ca_mutex_lock(g_mutexObjectList);
367         bool result = u_arraylist_add(caglobals.tcp.svrlist, svritem);
368         if (!result)
369         {
370             OIC_LOG(ERROR, TAG, "u_arraylist_add failed.");
371             close(sockfd);
372             OICFree(svritem);
373             ca_mutex_unlock(g_mutexObjectList);
374             return;
375         }
376         ca_mutex_unlock(g_mutexObjectList);
377
378         CHECKFD(sockfd);
379     }
380 }
381
382 #ifdef __WITH_TLS__
383 static bool CAIsTlsMessage(const CATCPSessionInfo_t * recvinfo)
384 {
385     if (recvinfo->data == NULL || recvinfo->len == 0)
386     {
387         OIC_LOG_V(ERROR, TAG, "%s: null input param", __func__);
388         return false;
389     }
390
391     unsigned char first_byte = recvinfo->data[0];
392
393     //TLS Plaintext has four types: change_cipher_spec = [14], alert = [15],
394     //handshake = [16], application_data = [17] in HEX
395     const uint8_t tls_head_type[] = {0x14, 0x15, 0x16, 0x17};
396     size_t i = 0;
397
398     for (i = 0; i < sizeof(tls_head_type); i++)
399     {
400         if(tls_head_type[i] == first_byte)
401         {
402             return true;
403         }
404     }
405
406     return false;
407 }
408 #endif
409
410 static void CAReceiveMessage(int fd)
411 {
412     // #1. get remote device information from file descriptor.
413     size_t index = 0;
414     CATCPSessionInfo_t *svritem = CAGetSessionInfoFromFD(fd, &index);
415     if (!svritem)
416     {
417         OIC_LOG(ERROR, TAG, "there is no connection information in list");
418         return;
419     }
420
421     // #2. allocate memory for message header (CoAP header size because it is bigger)
422     svritem->data = (unsigned char *) OICCalloc(1, COAP_MAX_HEADER_SIZE);
423     if (!svritem->data)
424     {
425         OIC_LOG(ERROR, TAG, "out of memory");
426         goto error;
427     }
428
429     // #3. read data (assume TLS header) from remote device.
430     RECV(fd, svritem, svritem->data, TLS_HEADER_SIZE, 0);
431
432 #ifdef __WITH_TLS__
433     if (CAIsTlsMessage(svritem))
434     {
435         // #4.1 get tls body length from tls header. [3][4] bytes are length of tls body in header
436         unsigned int message_length = (unsigned int)((svritem->data[3] << 8) | svritem->data[4]);
437         OIC_LOG_V(DEBUG, TAG, "%s: message_length = %d", __func__, message_length);
438
439         REALLOC(svritem->data, message_length + TLS_HEADER_SIZE);
440
441         RECV(fd, svritem, svritem->data, message_length, 0);
442
443         int ret = CAdecryptTls(&svritem->sep, (uint8_t *)svritem->data, svritem->len);
444
445         OIC_LOG_V(DEBUG, TAG, "%s: CAdecryptTls returned %d", __func__, ret);
446         goto success;
447     }
448     else
449 #endif
450     {
451         // #4.2 Seems CoAP data received. read full coap header.
452         coap_transport_type transport = coap_get_tcp_header_type_from_initbyte(svritem->data[0] >> 4);
453
454         size_t headerLen = coap_get_tcp_header_length_for_transport(transport);
455
456         if (svritem->len < headerLen)
457         {
458             // read required bytes to have full CoAP header
459             // usually it is 1 bytes (COAP_MAX_HEADER_SIZE - TLS_HEADER_SIZE)
460             RECV(fd, svritem, svritem->data, headerLen - svritem->len, 0);
461         }
462
463         // #4.3 Calculate CoAP message length and read it
464         size_t total_length = CAGetTotalLengthFromHeader(svritem->data);
465         REALLOC(svritem->data, total_length);
466
467         RECV(fd, svritem, svritem->data, total_length - svritem->len, 0);
468
469         // #4.4. pass the received data information to upper layer.
470         if (g_packetReceivedCallback)
471         {
472             svritem->sep.endpoint.adapter = CA_ADAPTER_TCP;
473             g_packetReceivedCallback(&svritem->sep, svritem->data, svritem->len);
474         }
475         goto success;
476     }
477
478     error:
479     CADisconnectTCPSession(svritem, index);
480
481     success:
482     // initialize data info to receive next message.
483     OICFree(svritem->data);
484     svritem->data = NULL;
485     svritem->len = 0;
486
487     return;
488 }
489
490 static void CAWakeUpForReadFdsUpdate(const char *host)
491 {
492     if (caglobals.tcp.connectionFds[1] != -1)
493     {
494         ssize_t len = 0;
495         do
496         {
497             len = write(caglobals.tcp.connectionFds[1], host, strlen(host));
498         } while ((len == -1) && (errno == EINTR));
499
500         if ((len == -1) && (errno != EINTR) && (errno != EPIPE))
501         {
502             OIC_LOG_V(DEBUG, TAG, "write failed: %s", strerror(errno));
503         }
504     }
505 }
506
507 static CAResult_t CATCPConvertNameToAddr(int family, const char *host, uint16_t port,
508                                          struct sockaddr_storage *sockaddr)
509 {
510     struct addrinfo *addrs = NULL;
511     struct addrinfo hints = { .ai_family = family,
512                               .ai_protocol   = IPPROTO_TCP,
513                               .ai_socktype = SOCK_STREAM,
514                               .ai_flags = AI_NUMERICHOST };
515
516     int r = getaddrinfo(host, NULL, &hints, &addrs);
517     if (r)
518     {
519         if (EAI_SYSTEM == r)
520         {
521             OIC_LOG_V(ERROR, TAG, "getaddrinfo failed: errno %s", strerror(errno));
522         }
523         else
524         {
525             OIC_LOG_V(ERROR, TAG, "getaddrinfo failed: %s", gai_strerror(r));
526         }
527         freeaddrinfo(addrs);
528         return CA_STATUS_FAILED;
529     }
530     // assumption: in this case, getaddrinfo will only return one addrinfo
531     // or first is the one we want.
532     if (addrs[0].ai_family == AF_INET6)
533     {
534         memcpy(sockaddr, addrs[0].ai_addr, sizeof (struct sockaddr_in6));
535         ((struct sockaddr_in6 *)sockaddr)->sin6_port = htons(port);
536     }
537     else
538     {
539         memcpy(sockaddr, addrs[0].ai_addr, sizeof (struct sockaddr_in));
540         ((struct sockaddr_in *)sockaddr)->sin_port = htons(port);
541     }
542     freeaddrinfo(addrs);
543     return CA_STATUS_OK;
544 }
545
546 static int CATCPCreateSocket(int family, CATCPSessionInfo_t *svritem)
547 {
548     // #1. create tcp socket.
549     int fd = socket(family, SOCK_STREAM, IPPROTO_TCP);
550     if (-1 == fd)
551     {
552         OIC_LOG_V(ERROR, TAG, "create socket failed: %s", strerror(errno));
553         return -1;
554     }
555
556     // #2. convert address from string to binary.
557     struct sockaddr_storage sa = { .ss_family = family };
558     CAResult_t res = CATCPConvertNameToAddr(family, svritem->sep.endpoint.addr,
559                                             svritem->sep.endpoint.port, &sa);
560     if (CA_STATUS_OK != res)
561     {
562         close(fd);
563         return -1;
564     }
565
566     // #3. set socket length.
567     socklen_t socklen = 0;
568     if (sa.ss_family == AF_INET6)
569     {
570         struct sockaddr_in6 *sock6 = (struct sockaddr_in6 *)&sa;
571         if (!sock6->sin6_scope_id)
572         {
573             sock6->sin6_scope_id = svritem->sep.endpoint.ifindex;
574         }
575         socklen = sizeof(struct sockaddr_in6);
576     }
577     else
578     {
579         socklen = sizeof(struct sockaddr_in);
580     }
581
582     // #4. connect to remote server device.
583     if (connect(fd, (struct sockaddr *)&sa, socklen) < 0)
584     {
585         OIC_LOG_V(ERROR, TAG, "failed to connect socket, %s", strerror(errno));
586         close(fd);
587         return -1;
588     }
589
590     OIC_LOG(DEBUG, TAG, "connect socket success");
591     CAWakeUpForReadFdsUpdate(svritem->sep.endpoint.addr);
592     return fd;
593 }
594
595 static int CACreateAcceptSocket(int family, CASocket_t *sock)
596 {
597     VERIFY_NON_NULL_RET(sock, TAG, "sock", -1);
598
599     if (sock->fd != -1)
600     {
601         OIC_LOG(DEBUG, TAG, "accept socket created already");
602         return sock->fd;
603     }
604
605     socklen_t socklen = 0;
606     struct sockaddr_storage server = { .ss_family = family };
607
608     int fd = socket(family, SOCK_STREAM, IPPROTO_TCP);
609     if (fd < 0)
610     {
611         OIC_LOG(ERROR, TAG, "Failed to create socket");
612         goto exit;
613     }
614
615     if (family == AF_INET6)
616     {
617         // the socket is re‐stricted to sending and receiving IPv6 packets only.
618         int on = 1;
619         if (-1 == setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof (on)))
620         {
621             OIC_LOG_V(ERROR, TAG, "IPV6_V6ONLY failed: %s", strerror(errno));
622             goto exit;
623         }
624         ((struct sockaddr_in6 *)&server)->sin6_port = htons(sock->port);
625         socklen = sizeof (struct sockaddr_in6);
626     }
627     else
628     {
629         ((struct sockaddr_in *)&server)->sin_port = htons(sock->port);
630         socklen = sizeof (struct sockaddr_in);
631     }
632
633     int reuse = 1;
634     if (-1 == setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)))
635     {
636         OIC_LOG(ERROR, TAG, "setsockopt SO_REUSEADDR");
637         goto exit;
638     }
639
640     if (-1 == bind(fd, (struct sockaddr *)&server, socklen))
641     {
642         OIC_LOG_V(ERROR, TAG, "bind socket failed: %s", strerror(errno));
643         goto exit;
644     }
645
646     if (listen(fd, caglobals.tcp.listenBacklog) != 0)
647     {
648         OIC_LOG(ERROR, TAG, "listen() error");
649         goto exit;
650     }
651
652     if (!sock->port)  // return the assigned port
653     {
654         if (-1 == getsockname(fd, (struct sockaddr *)&server, &socklen))
655         {
656             OIC_LOG_V(ERROR, TAG, "getsockname failed: %s", strerror(errno));
657             goto exit;
658         }
659         sock->port = ntohs(family == AF_INET6 ?
660                       ((struct sockaddr_in6 *)&server)->sin6_port :
661                       ((struct sockaddr_in *)&server)->sin_port);
662     }
663
664     return fd;
665
666 exit:
667     if (fd >= 0)
668     {
669         close(fd);
670     }
671     return -1;
672 }
673
674 static void CAInitializePipe(int *fds)
675 {
676     int ret = pipe(fds);
677     if (-1 != ret)
678     {
679         ret = fcntl(fds[0], F_GETFD);
680         if (-1 != ret)
681         {
682             ret = fcntl(fds[0], F_SETFD, ret|FD_CLOEXEC);
683         }
684         if (-1 != ret)
685         {
686             ret = fcntl(fds[1], F_GETFD);
687         }
688         if (-1 != ret)
689         {
690             ret = fcntl(fds[1], F_SETFD, ret|FD_CLOEXEC);
691         }
692         if (-1 == ret)
693         {
694             close(fds[1]);
695             close(fds[0]);
696
697             fds[0] = -1;
698             fds[1] = -1;
699
700             OIC_LOG_V(ERROR, TAG, "pipe failed: %s", strerror(errno));
701         }
702     }
703 }
704
705 #define NEWSOCKET(FAMILY, NAME) \
706     caglobals.tcp.NAME.fd = CACreateAcceptSocket(FAMILY, &caglobals.tcp.NAME); \
707     if (caglobals.tcp.NAME.fd == -1) \
708     { \
709         caglobals.tcp.NAME.port = 0; \
710         caglobals.tcp.NAME.fd = CACreateAcceptSocket(FAMILY, &caglobals.tcp.NAME); \
711     } \
712     CHECKFD(caglobals.tcp.NAME.fd);
713
714 CAResult_t CATCPStartServer(const ca_thread_pool_t threadPool)
715 {
716     if (caglobals.tcp.started)
717     {
718         return CA_STATUS_OK;
719     }
720
721     if (!caglobals.tcp.ipv4tcpenabled)
722     {
723         caglobals.tcp.ipv4tcpenabled = true;    // only needed to run CA tests
724     }
725     if (!caglobals.tcp.ipv6tcpenabled)
726     {
727         caglobals.tcp.ipv6tcpenabled = true;    // only needed to run CA tests
728     }
729
730     CAResult_t res = CATCPCreateMutex();
731     if (CA_STATUS_OK == res)
732     {
733         res = CATCPCreateCond();
734     }
735     if (CA_STATUS_OK != res)
736     {
737         OIC_LOG(ERROR, TAG, "failed to create mutex/cond");
738         return res;
739     }
740
741     ca_mutex_lock(g_mutexObjectList);
742     if (!caglobals.tcp.svrlist)
743     {
744         caglobals.tcp.svrlist = u_arraylist_create();
745     }
746     ca_mutex_unlock(g_mutexObjectList);
747
748     if (caglobals.server)
749     {
750         NEWSOCKET(AF_INET, ipv4);
751         NEWSOCKET(AF_INET6, ipv6);
752         OIC_LOG_V(DEBUG, TAG, "IPv4 socket fd=%d, port=%d",
753                   caglobals.tcp.ipv4.fd, caglobals.tcp.ipv4.port);
754         OIC_LOG_V(DEBUG, TAG, "IPv6 socket fd=%d, port=%d",
755                   caglobals.tcp.ipv6.fd, caglobals.tcp.ipv6.port);
756     }
757
758     // create pipe for fast shutdown
759     CAInitializePipe(caglobals.tcp.shutdownFds);
760     CHECKFD(caglobals.tcp.shutdownFds[0]);
761     CHECKFD(caglobals.tcp.shutdownFds[1]);
762
763     // create pipe for connection event
764     CAInitializePipe(caglobals.tcp.connectionFds);
765     CHECKFD(caglobals.tcp.connectionFds[0]);
766     CHECKFD(caglobals.tcp.connectionFds[1]);
767
768     caglobals.tcp.terminate = false;
769     res = ca_thread_pool_add_task(threadPool, CAReceiveHandler, NULL);
770     if (CA_STATUS_OK != res)
771     {
772         OIC_LOG(ERROR, TAG, "thread_pool_add_task failed");
773         return res;
774     }
775     OIC_LOG(DEBUG, TAG, "CAReceiveHandler thread started successfully.");
776
777     caglobals.tcp.started = true;
778     return CA_STATUS_OK;
779 }
780
781 void CATCPStopServer()
782 {
783     // mutex lock
784     ca_mutex_lock(g_mutexObjectList);
785
786     // set terminate flag
787     caglobals.tcp.terminate = true;
788
789     if (caglobals.tcp.shutdownFds[1] != -1)
790     {
791         close(caglobals.tcp.shutdownFds[1]);
792         // receive thread will stop immediately
793     }
794
795     if (caglobals.tcp.connectionFds[1] != -1)
796     {
797         close(caglobals.tcp.connectionFds[1]);
798     }
799
800     if (caglobals.tcp.started)
801     {
802         ca_cond_wait(g_condObjectList, g_mutexObjectList);
803     }
804     caglobals.tcp.started = false;
805
806     // mutex unlock
807     ca_mutex_unlock(g_mutexObjectList);
808
809     if (-1 != caglobals.tcp.ipv4.fd)
810     {
811         close(caglobals.tcp.ipv4.fd);
812         caglobals.tcp.ipv4.fd = -1;
813     }
814
815     if (-1 != caglobals.tcp.ipv6.fd)
816     {
817         close(caglobals.tcp.ipv6.fd);
818         caglobals.tcp.ipv6.fd = -1;
819     }
820
821     CATCPDisconnectAll();
822     CATCPDestroyMutex();
823     CATCPDestroyCond();
824 }
825
826 void CATCPSetPacketReceiveCallback(CATCPPacketReceivedCallback callback)
827 {
828     g_packetReceivedCallback = callback;
829 }
830
831 void CATCPSetConnectionChangedCallback(CATCPConnectionHandleCallback connHandler)
832 {
833     g_connectionCallback = connHandler;
834 }
835
836 static void sendData(const CAEndpoint_t *endpoint, const void *data,
837                      size_t dlen, const char *fam)
838 {
839     // #1. get TCP Server object from list
840     size_t index = 0;
841     CATCPSessionInfo_t *svritem = CAGetTCPSessionInfoFromEndpoint(endpoint, &index);
842     if (!svritem)
843     {
844         // if there is no connection info, connect to TCP Server
845         svritem = CAConnectTCPSession(endpoint);
846         if (!svritem)
847         {
848             OIC_LOG(ERROR, TAG, "Failed to create TCP server object");
849             if (g_tcpErrorHandler)
850             {
851                 g_tcpErrorHandler(endpoint, data, dlen, CA_SEND_FAILED);
852             }
853             return;
854         }
855     }
856
857     // #2. check connection state
858     if (svritem->fd < 0)
859     {
860         // if file descriptor value is wrong, remove TCP Server info from list
861         OIC_LOG(ERROR, TAG, "Failed to connect to TCP server");
862         CADisconnectTCPSession(svritem, index);
863         if (g_tcpErrorHandler)
864         {
865             g_tcpErrorHandler(endpoint, data, dlen, CA_SEND_FAILED);
866         }
867         return;
868     }
869
870     // #4. send data to TCP Server
871     ssize_t remainLen = dlen;
872     do
873     {
874         ssize_t len = send(svritem->fd, data, remainLen, 0);
875         if (-1 == len)
876         {
877             if (EWOULDBLOCK != errno)
878             {
879                 OIC_LOG_V(ERROR, TAG, "unicast ipv4tcp sendTo failed: %s", strerror(errno));
880                 if (g_tcpErrorHandler)
881                 {
882                     g_tcpErrorHandler(endpoint, data, dlen, CA_SEND_FAILED);
883                 }
884                 return;
885             }
886             continue;
887         }
888         data += len;
889         remainLen -= len;
890     } while (remainLen > 0);
891
892     OIC_LOG_V(INFO, TAG, "unicast %stcp sendTo is successful: %zu bytes", fam, dlen);
893 }
894
895 void CATCPSendData(CAEndpoint_t *endpoint, const void *data, uint32_t datalen,
896                    bool isMulticast)
897 {
898     VERIFY_NON_NULL_VOID(endpoint, TAG, "endpoint is NULL");
899     VERIFY_NON_NULL_VOID(data, TAG, "data is NULL");
900
901     if (!isMulticast)
902     {
903         if (caglobals.tcp.ipv6tcpenabled && (endpoint->flags & CA_IPV6))
904         {
905             sendData(endpoint, data, datalen, "ipv6");
906         }
907         if (caglobals.tcp.ipv4tcpenabled && (endpoint->flags & CA_IPV4))
908         {
909             sendData(endpoint, data, datalen, "ipv4");
910         }
911     }
912 }
913
914 CAResult_t CAGetTCPInterfaceInformation(CAEndpoint_t **info, uint32_t *size)
915 {
916     VERIFY_NON_NULL(info, TAG, "info is NULL");
917     VERIFY_NON_NULL(size, TAG, "size is NULL");
918
919     return CA_NOT_SUPPORTED;
920 }
921
922 CATCPSessionInfo_t *CAConnectTCPSession(const CAEndpoint_t *endpoint)
923 {
924     VERIFY_NON_NULL_RET(endpoint, TAG, "endpoint is NULL", NULL);
925
926     // #1. create TCP server object
927     CATCPSessionInfo_t *svritem = (CATCPSessionInfo_t *) OICCalloc(1, sizeof (*svritem));
928     if (!svritem)
929     {
930         OIC_LOG(ERROR, TAG, "Out of memory");
931         return NULL;
932     }
933     memcpy(svritem->sep.endpoint.addr, endpoint->addr, sizeof(svritem->sep.endpoint.addr));
934     svritem->sep.endpoint.adapter = endpoint->adapter;
935     svritem->sep.endpoint.port = endpoint->port;
936     svritem->sep.endpoint.flags = endpoint->flags;
937     svritem->sep.endpoint.ifindex = endpoint->ifindex;
938
939     // #2. create the socket and connect to TCP server
940     int family = (svritem->sep.endpoint.flags & CA_IPV6) ? AF_INET6 : AF_INET;
941     int fd = CATCPCreateSocket(family, svritem);
942     if (-1 == fd)
943     {
944         OICFree(svritem);
945         return NULL;
946     }
947
948     // #3. add TCP connection info to list
949     svritem->fd = fd;
950     ca_mutex_lock(g_mutexObjectList);
951     if (caglobals.tcp.svrlist)
952     {
953         bool res = u_arraylist_add(caglobals.tcp.svrlist, svritem);
954         if (!res)
955         {
956             OIC_LOG(ERROR, TAG, "u_arraylist_add failed.");
957             close(svritem->fd);
958             OICFree(svritem);
959             ca_mutex_unlock(g_mutexObjectList);
960             return NULL;
961         }
962     }
963     ca_mutex_unlock(g_mutexObjectList);
964
965     CHECKFD(fd);
966
967     // pass the connection information to CA Common Layer.
968     if (g_connectionCallback)
969     {
970         g_connectionCallback(&(svritem->sep.endpoint), true);
971     }
972
973     return svritem;
974 }
975
976 CAResult_t CADisconnectTCPSession(CATCPSessionInfo_t *svritem, size_t index)
977 {
978     VERIFY_NON_NULL(svritem, TAG, "svritem is NULL");
979
980     ca_mutex_lock(g_mutexObjectList);
981
982     // close the socket and remove TCP connection info in list
983     if (svritem->fd >= 0)
984     {
985         close(svritem->fd);
986     }
987     u_arraylist_remove(caglobals.tcp.svrlist, index);
988     OICFree(svritem->data);
989     svritem->data = NULL;
990
991     // pass the connection information to CA Common Layer.
992     if (g_connectionCallback)
993     {
994         g_connectionCallback(&(svritem->sep.endpoint), false);
995     }
996
997     OICFree(svritem);
998     ca_mutex_unlock(g_mutexObjectList);
999
1000     return CA_STATUS_OK;
1001 }
1002
1003 void CATCPDisconnectAll()
1004 {
1005     ca_mutex_lock(g_mutexObjectList);
1006     uint32_t length = u_arraylist_length(caglobals.tcp.svrlist);
1007
1008     CATCPSessionInfo_t *svritem = NULL;
1009     for (size_t i = 0; i < length; i++)
1010     {
1011         svritem = (CATCPSessionInfo_t *) u_arraylist_get(caglobals.tcp.svrlist, i);
1012         if (svritem && svritem->fd >= 0)
1013         {
1014             shutdown(svritem->fd, SHUT_RDWR);
1015             close(svritem->fd);
1016
1017             OICFree(svritem->data);
1018             svritem->data = NULL;
1019         }
1020     }
1021     u_arraylist_destroy(caglobals.tcp.svrlist);
1022     ca_mutex_unlock(g_mutexObjectList);
1023 }
1024
1025 CATCPSessionInfo_t *CAGetTCPSessionInfoFromEndpoint(const CAEndpoint_t *endpoint, size_t *index)
1026 {
1027     VERIFY_NON_NULL_RET(endpoint, TAG, "endpoint is NULL", NULL);
1028     VERIFY_NON_NULL_RET(index, TAG, "index is NULL", NULL);
1029
1030     // get connection info from list
1031     uint32_t length = u_arraylist_length(caglobals.tcp.svrlist);
1032     for (size_t i = 0; i < length; i++)
1033     {
1034         CATCPSessionInfo_t *svritem = (CATCPSessionInfo_t *) u_arraylist_get(
1035                 caglobals.tcp.svrlist, i);
1036         if (!svritem)
1037         {
1038             continue;
1039         }
1040
1041         if (!strncmp(svritem->sep.endpoint.addr, endpoint->addr,
1042                      sizeof(svritem->sep.endpoint.addr))
1043                 && (svritem->sep.endpoint.port == endpoint->port)
1044                 && (svritem->sep.endpoint.flags & endpoint->flags))
1045         {
1046             *index = i;
1047             return svritem;
1048         }
1049     }
1050
1051     return NULL;
1052 }
1053
1054 CATCPSessionInfo_t *CAGetSessionInfoFromFD(int fd, size_t *index)
1055 {
1056     ca_mutex_lock(g_mutexObjectList);
1057
1058     // check from the last item.
1059     CATCPSessionInfo_t *svritem = NULL;
1060     uint32_t length = u_arraylist_length(caglobals.tcp.svrlist);
1061     for (size_t i = 0; i < length; i++)
1062     {
1063         svritem = (CATCPSessionInfo_t *) u_arraylist_get(caglobals.tcp.svrlist, i);
1064
1065         if (svritem && svritem->fd == fd)
1066         {
1067             *index = i;
1068             ca_mutex_unlock(g_mutexObjectList);
1069             return svritem;
1070         }
1071     }
1072
1073     ca_mutex_unlock(g_mutexObjectList);
1074
1075     return NULL;
1076 }
1077
1078 size_t CAGetTotalLengthFromHeader(const unsigned char *recvBuffer)
1079 {
1080     OIC_LOG(DEBUG, TAG, "IN - CAGetTotalLengthFromHeader");
1081
1082     coap_transport_type transport = coap_get_tcp_header_type_from_initbyte(
1083             ((unsigned char *)recvBuffer)[0] >> 4);
1084     size_t optPaylaodLen = coap_get_length_from_header((unsigned char *)recvBuffer,
1085                                                         transport);
1086     size_t headerLen = coap_get_tcp_header_length((unsigned char *)recvBuffer);
1087
1088     OIC_LOG_V(DEBUG, TAG, "option/paylaod length [%zu]", optPaylaodLen);
1089     OIC_LOG_V(DEBUG, TAG, "header length [%zu]", headerLen);
1090     OIC_LOG_V(DEBUG, TAG, "total data length [%zu]", headerLen + optPaylaodLen);
1091
1092     OIC_LOG(DEBUG, TAG, "OUT - CAGetTotalLengthFromHeader");
1093     return headerLen + optPaylaodLen;
1094 }
1095
1096 void CATCPSetErrorHandler(CATCPErrorHandleCallback errorHandleCallback)
1097 {
1098     g_tcpErrorHandler = errorHandleCallback;
1099 }