[Win32] Add conditional compilation directives.
[platform/upstream/iotivity.git] / resource / csdk / connectivity / src / ip_adapter / caipserver.c
1 /*****************************************************************j
2  *
3  * Copyright 2014 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 #ifndef __APPLE_USE_RFC_3542
22 #define __APPLE_USE_RFC_3542 // for PKTINFO
23 #endif
24 #ifndef _GNU_SOURCE
25 #define _GNU_SOURCE // for in6_pktinfo
26 #endif
27
28 #include <sys/types.h>
29 #if !defined(__msys_nt__)
30 #include <sys/socket.h>
31 #endif
32
33 #if defined(__msys_nt__)
34 #include <winsock2.h>
35 #include <ws2def.h>
36 #include <mswsock.h>
37 #include <ws2tcpip.h>
38 #endif
39
40 #include <stdio.h>
41 #include <unistd.h>
42 #include <sys/types.h>
43 #include <fcntl.h>
44 #if !defined(__msys_nt__)
45 #include <sys/select.h>
46 #include <arpa/inet.h>
47 #include <netinet/in.h>
48 #include <net/if.h>
49 #endif
50 #include <errno.h>
51 #ifdef __linux__
52 #include <linux/netlink.h>
53 #include <linux/rtnetlink.h>
54 #endif
55
56 #include "pdu.h"
57 #include "caipinterface.h"
58 #include "caadapterutils.h"
59 #ifdef __WITH_DTLS__
60 #include "caadapternetdtls.h"
61 #endif
62 #include "camutex.h"
63 #include "oic_malloc.h"
64 #include "oic_string.h"
65
66 /*
67  * Logging tag for module name
68  */
69 #define TAG "OIC_CA_IP_SERVER"
70
71 #define SELECT_TIMEOUT 1     // select() seconds (and termination latency)
72
73 #define IPv4_MULTICAST     "224.0.1.187"
74 static struct in_addr IPv4MulticastAddress = { 0 };
75
76 #define IPv6_DOMAINS       16
77 #define IPv6_MULTICAST_INT "ff01::fd"
78 static struct in6_addr IPv6MulticastAddressInt;
79 #define IPv6_MULTICAST_LNK "ff02::fd"
80 static struct in6_addr IPv6MulticastAddressLnk;
81 #define IPv6_MULTICAST_RLM "ff03::fd"
82 static struct in6_addr IPv6MulticastAddressRlm;
83 #define IPv6_MULTICAST_ADM "ff04::fd"
84 static struct in6_addr IPv6MulticastAddressAdm;
85 #define IPv6_MULTICAST_SIT "ff05::fd"
86 static struct in6_addr IPv6MulticastAddressSit;
87 #define IPv6_MULTICAST_ORG "ff08::fd"
88 static struct in6_addr IPv6MulticastAddressOrg;
89 #define IPv6_MULTICAST_GLB "ff0e::fd"
90 static struct in6_addr IPv6MulticastAddressGlb;
91
92 static char *ipv6mcnames[IPv6_DOMAINS] = {
93     NULL,
94     IPv6_MULTICAST_INT,
95     IPv6_MULTICAST_LNK,
96     IPv6_MULTICAST_RLM,
97     IPv6_MULTICAST_ADM,
98     IPv6_MULTICAST_SIT,
99     NULL,
100     NULL,
101     IPv6_MULTICAST_ORG,
102     NULL,
103     NULL,
104     NULL,
105     NULL,
106     NULL,
107     IPv6_MULTICAST_GLB,
108     NULL
109 };
110
111 #if defined (__msys_nt__)
112     char* _caips_get_error(){
113         static char buffer[32];
114         snprintf(buffer, 32, "%i", WSAGetLastError());
115         return buffer;
116     }
117     #define CAIPS_GET_ERROR \
118         _caips_get_error()
119 #else
120     #define CAIPS_GET_ERROR \
121         strerror(errno)
122 #endif
123 static CAIPExceptionCallback g_exceptionCallback;
124
125 static CAIPPacketReceivedCallback g_packetReceivedCallback;
126
127 static void CAHandleNetlink();
128 static void CAFindReadyMessage();
129 static void CASelectReturned(fd_set *readFds, int ret);
130 static void CAProcessNewInterface(CAInterface_t *ifchanged);
131 static CAResult_t CAReceiveMessage(int fd, CATransportFlags_t flags);
132
133 #define SET(TYPE, FDS) \
134     if (caglobals.ip.TYPE.fd != -1) \
135     { \
136         FD_SET(caglobals.ip.TYPE.fd, FDS); \
137     }
138
139 #define ISSET(TYPE, FDS, FLAGS) \
140     if (caglobals.ip.TYPE.fd != -1 && FD_ISSET(caglobals.ip.TYPE.fd, FDS)) \
141     { \
142         fd = caglobals.ip.TYPE.fd; \
143         flags = FLAGS; \
144     }
145
146 #define CLOSE_SOCKET(TYPE) \
147     if (caglobals.ip.TYPE.fd != -1) \
148     { \
149         close(caglobals.ip.TYPE.fd); \
150         caglobals.ip.TYPE.fd = -1; \
151     }
152
153 void CADeInitializeIPGlobals()
154 {
155     CLOSE_SOCKET(u6);
156     CLOSE_SOCKET(u6s);
157     CLOSE_SOCKET(u4);
158     CLOSE_SOCKET(u4s);
159     CLOSE_SOCKET(m6);
160     CLOSE_SOCKET(m6s);
161     CLOSE_SOCKET(m4);
162     CLOSE_SOCKET(m4s);
163
164     if (caglobals.ip.netlinkFd != -1)
165     {
166         close(caglobals.ip.netlinkFd);
167         caglobals.ip.netlinkFd = -1;
168     }
169 }
170
171 static void CAReceiveHandler(void *data)
172 {
173     (void)data;
174
175     while (!caglobals.ip.terminate)
176     {
177         CAFindReadyMessage();
178     }
179 }
180
181 static void CAFindReadyMessage()
182 {
183     fd_set readFds;
184     struct timeval timeout;
185
186     timeout.tv_sec = caglobals.ip.selectTimeout;
187     timeout.tv_usec = 0;
188     struct timeval *tv = caglobals.ip.selectTimeout == -1 ? NULL : &timeout;
189
190     FD_ZERO(&readFds);
191     SET(u6,  &readFds)
192     SET(u6s, &readFds)
193     SET(u4,  &readFds)
194     SET(u4s, &readFds)
195     SET(m6,  &readFds)
196     SET(m6s, &readFds)
197     SET(m4,  &readFds)
198     SET(m4s, &readFds)
199
200 #if !defined(__msys_nt__)
201     if (caglobals.ip.shutdownFds[0] != -1)
202     {
203         FD_SET(caglobals.ip.shutdownFds[0], &readFds);
204     }
205     if (caglobals.ip.netlinkFd != -1)
206     {
207         FD_SET(caglobals.ip.netlinkFd, &readFds);
208     }
209 #endif
210     int ret = select(caglobals.ip.maxfd + 1, &readFds, NULL, NULL, tv);
211
212     if (caglobals.ip.terminate)
213     {
214         OIC_LOG_V(DEBUG, TAG, "Packet receiver Stop request received.");
215         return;
216     }
217
218     if (ret <= 0)
219     {
220         if (ret < 0)
221         {
222             OIC_LOG_V(FATAL, TAG, "select error %s", CAIPS_GET_ERROR);
223         }
224         return;
225     }
226
227     CASelectReturned(&readFds, ret);
228 }
229
230 static void CASelectReturned(fd_set *readFds, int ret)
231 {
232     (void)ret;
233     int fd = -1;
234     CATransportFlags_t flags = CA_DEFAULT_FLAGS;
235
236     while (!caglobals.ip.terminate)
237     {
238         ISSET(u6,  readFds, CA_IPV6)
239         else ISSET(u6s, readFds, CA_IPV6 | CA_SECURE)
240         else ISSET(u4,  readFds, CA_IPV4)
241         else ISSET(u4s, readFds, CA_IPV4 | CA_SECURE)
242         else ISSET(m6,  readFds, CA_MULTICAST | CA_IPV6)
243         else ISSET(m6s, readFds, CA_MULTICAST | CA_IPV6 | CA_SECURE)
244         else ISSET(m4,  readFds, CA_MULTICAST | CA_IPV4)
245         else ISSET(m4s, readFds, CA_MULTICAST | CA_IPV4 | CA_SECURE)
246 #if !defined(__msys_nt__)
247         else if (FD_ISSET(caglobals.ip.netlinkFd, readFds))
248         {
249             CAInterface_t *ifchanged = CAFindInterfaceChange();
250             if (ifchanged)
251             {
252                 CAProcessNewInterface(ifchanged);
253                 OICFree(ifchanged);
254             }
255             break;
256         }
257         else if (FD_ISSET(caglobals.ip.shutdownFds[0], readFds))
258         {
259             char buf[10] = {0};
260             ssize_t len = read(caglobals.ip.shutdownFds[0], buf, sizeof (buf));
261             if (-1 == len)
262             {
263                 continue;
264             }
265             break;
266         }
267         else
268         {
269             break;
270         }
271 #else
272         else
273         {
274             break;
275         }
276 #endif
277         (void)CAReceiveMessage(fd, flags);
278         FD_CLR(fd, readFds);
279     }
280 }
281
282 static CAResult_t CAReceiveMessage(int fd, CATransportFlags_t flags)
283 {
284     char recvBuffer[COAP_MAX_PDU_SIZE];
285
286     size_t len;
287     int level, type, namelen;
288     struct sockaddr_storage srcAddr;
289     unsigned char *pktinfo = NULL;
290 #if !defined(__msys_nt__)
291     struct cmsghdr *cmp = NULL;
292     struct iovec iov = { recvBuffer, sizeof (recvBuffer) };
293     union control
294     {
295         struct cmsghdr cmsg;
296         unsigned char data[CMSG_SPACE(sizeof (struct in6_pktinfo))];
297     } cmsg;
298
299     if (flags & CA_IPV6)
300     {
301         namelen = sizeof (struct sockaddr_in6);
302         level = IPPROTO_IPV6;
303         type = IPV6_PKTINFO;
304         len = sizeof (struct in6_pktinfo);
305     }
306     else
307     {
308         namelen = sizeof (struct sockaddr_in);
309         level = IPPROTO_IP;
310         type = IP_PKTINFO;
311         len = sizeof (struct in6_pktinfo);
312     }
313
314     struct msghdr msg = { .msg_name = &srcAddr,
315                           .msg_namelen = namelen,
316                           .msg_iov = &iov,
317                           .msg_iovlen = 1,
318                           .msg_control = &cmsg,
319                           .msg_controllen = CMSG_SPACE(len) };
320
321     ssize_t recvLen = recvmsg(fd, &msg, flags);
322     if (-1 == recvLen)
323     {
324         OIC_LOG_V(ERROR, TAG, "Recvfrom failed %s", strerror(errno));
325         return CA_STATUS_FAILED;
326     }
327
328     if (flags & CA_MULTICAST)
329     {
330         for (cmp = CMSG_FIRSTHDR(&msg); cmp != NULL; cmp = CMSG_NXTHDR(&msg, cmp))
331         {
332             if (cmp->cmsg_level == level && cmp->cmsg_type == type)
333             {
334                 pktinfo = CMSG_DATA(cmp);
335             }
336         }
337     }
338 #else // if defined(__msys_nt__)
339
340 #endif // !defined(__msys_nt__)
341     CASecureEndpoint_t sep = {.endpoint = {.adapter = CA_ADAPTER_IP, .flags = flags}};
342
343     if (flags & CA_IPV6)
344     {
345         sep.endpoint.ifindex = ((struct sockaddr_in6 *)&srcAddr)->sin6_scope_id;
346         ((struct sockaddr_in6 *)&srcAddr)->sin6_scope_id = 0;
347
348         if ((flags & CA_MULTICAST) && pktinfo)
349         {
350             struct in6_addr *addr = &(((struct in6_pktinfo *)pktinfo)->ipi6_addr);
351             unsigned char topbits = ((unsigned char *)addr)[0];
352             if (topbits != 0xff)
353             {
354                 sep.endpoint.flags &= ~CA_MULTICAST;
355             }
356         }
357     }
358     else
359     {
360         if ((flags & CA_MULTICAST) && pktinfo)
361         {
362             struct in_addr *addr = &((struct in_pktinfo *)pktinfo)->ipi_addr;
363             uint32_t host = ntohl(addr->s_addr);
364             unsigned char topbits = ((unsigned char *)&host)[3];
365             if (topbits < 224 || topbits > 239)
366             {
367                 sep.endpoint.flags &= ~CA_MULTICAST;
368             }
369         }
370     }
371 #if !defined(__msys_nt__)
372     CAConvertAddrToName(&srcAddr, msg.msg_namelen, sep.endpoint.addr, &sep.endpoint.port);
373 #else
374
375 #endif
376     if (flags & CA_SECURE)
377     {
378 #ifdef __WITH_DTLS__
379         int ret = CAAdapterNetDtlsDecrypt(&sep, (uint8_t *)recvBuffer, recvLen);
380         OIC_LOG_V(DEBUG, TAG, "CAAdapterNetDtlsDecrypt returns [%d]", ret);
381 #else
382         OIC_LOG(ERROR, TAG, "Encrypted message but no DTLS");
383 #endif
384     }
385     else
386     {
387         if (g_packetReceivedCallback)
388         {
389             g_packetReceivedCallback(&sep, recvBuffer, recvLen);
390         }
391     }
392
393     return CA_STATUS_OK;
394
395
396 }
397
398 void CAIPPullData()
399 {
400     OIC_LOG(DEBUG, TAG, "IN");
401     OIC_LOG(DEBUG, TAG, "OUT");
402 }
403
404 static int CACreateSocket(int family, uint16_t *port)
405 {
406 #if !defined(__msys_nt__)
407     int socktype = SOCK_DGRAM;
408 #ifdef SOCK_CLOEXEC
409     socktype |= SOCK_CLOEXEC;
410 #endif
411     int fd = socket(family, socktype, IPPROTO_UDP);
412     if (-1 == fd)
413     {
414         OIC_LOG_V(ERROR, TAG, "create socket failed: %s", strerror(errno));
415         return -1;
416     }
417
418 #ifndef SOCK_CLOEXEC
419     int fl = fcntl(fd, F_GETFD);
420     if (-1 == fl || -1 == fcntl(fd, F_SETFD, fl|FD_CLOEXEC))
421     {
422         OIC_LOG_V(ERROR, TAG, "set FD_CLOEXEC failed: %s", strerror(errno));
423         close(fd);
424         return -1;
425     }
426 #endif
427 #else // defined(__msys_nt__)
428
429 #endif
430     struct sockaddr_storage sa = { .ss_family = family };
431     socklen_t socklen;
432
433     if (family == AF_INET6)
434     {
435         int on = 1;
436
437         if (-1 == setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof (on)))
438         {
439             OIC_LOG_V(ERROR, TAG, "IPV6_V6ONLY failed: %s", strerror(errno));
440         }
441
442         if (*port)      // only do this for multicast ports
443         {
444 #if !defined(__msys_nt__)
445             if (-1 == setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof (on)))
446 #else
447
448 #endif
449             {
450                 OIC_LOG_V(ERROR, TAG, "IPV6_RECVPKTINFO failed: %s",CAIPS_GET_ERROR);
451             }
452         }
453
454         ((struct sockaddr_in6 *)&sa)->sin6_port = htons(*port);
455         socklen = sizeof (struct sockaddr_in6);
456     }
457     else
458     {
459         if (*port)      // only do this for multicast ports
460         {
461             int on = 1;
462             if (-1 == setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &on, sizeof (on)))
463             {
464                 OIC_LOG_V(ERROR, TAG, "IP_PKTINFO failed: %s", CAIPS_GET_ERROR);
465             }
466         }
467
468         ((struct sockaddr_in *)&sa)->sin_port = htons(*port);
469         socklen = sizeof (struct sockaddr_in);
470     }
471
472     if (*port)  // use the given port
473     {
474         int on = 1;
475         if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof (on)))
476         {
477             OIC_LOG_V(ERROR, TAG, "SO_REUSEADDR failed: %s", CAIPS_GET_ERROR);
478             close(fd);
479             return -1;
480         }
481     }
482
483     if (-1 == bind(fd, (struct sockaddr *)&sa, socklen))
484     {
485         OIC_LOG_V(ERROR, TAG, "bind socket failed: %s", CAIPS_GET_ERROR);
486         close(fd);
487         return -1;
488     }
489
490     if (!*port)  // return the assigned port
491     {
492         if (-1 == getsockname(fd, (struct sockaddr *)&sa, &socklen))
493         {
494             OIC_LOG_V(ERROR, TAG, "getsockname failed: %s", CAIPS_GET_ERROR);
495             close(fd);
496             return -1;
497         }
498         *port = ntohs(family == AF_INET6 ?
499                       ((struct sockaddr_in6 *)&sa)->sin6_port :
500                       ((struct sockaddr_in *)&sa)->sin_port);
501     }
502
503     return fd;
504 }
505
506 #define CHECKFD(FD) \
507     if (FD > caglobals.ip.maxfd) \
508         caglobals.ip.maxfd = FD;
509 #define NEWSOCKET(FAMILY, NAME) \
510     caglobals.ip.NAME.fd = CACreateSocket(FAMILY, &caglobals.ip.NAME.port); \
511     CHECKFD(caglobals.ip.NAME.fd)
512
513 static void CAInitializeNetlink()
514 {
515 #ifdef __linux__
516     // create NETLINK fd for interface change notifications
517     struct sockaddr_nl sa = { AF_NETLINK, 0, 0, RTMGRP_LINK };
518
519     caglobals.ip.netlinkFd = socket(AF_NETLINK, SOCK_RAW|SOCK_CLOEXEC, NETLINK_ROUTE);
520     if (caglobals.ip.netlinkFd == -1)
521     {
522         OIC_LOG_V(ERROR, TAG, "netlink socket failed: %s", strerror(errno));
523     }
524     else
525     {
526         int r = bind(caglobals.ip.netlinkFd, (struct sockaddr *)&sa, sizeof (sa));
527         if (r)
528         {
529             OIC_LOG_V(ERROR, TAG, "netlink bind failed: %s", strerror(errno));
530             close(caglobals.ip.netlinkFd);
531             caglobals.ip.netlinkFd = -1;
532         }
533         else
534         {
535             CHECKFD(caglobals.ip.netlinkFd);
536         }
537     }
538 #endif
539 }
540
541 static void CAInitializePipe()
542 {
543 #if !defined(__msys_nt__)
544     caglobals.ip.selectTimeout = -1;
545 #ifdef HAVE_PIPE2
546     int ret = pipe2(caglobals.ip.shutdownFds, O_CLOEXEC);
547 #else
548     int ret = pipe(caglobals.ip.shutdownFds);
549     if (-1 != ret)
550     {
551         ret = fcntl(caglobals.ip.shutdownFds[0], F_GETFD);
552         if (-1 != ret)
553         {
554             ret = fcntl(caglobals.ip.shutdownFds[0], F_SETFD, ret|FD_CLOEXEC);
555         }
556         if (-1 != ret)
557         {
558             ret = fcntl(caglobals.ip.shutdownFds[1], F_GETFD);
559         }
560         if (-1 != ret)
561         {
562             ret = fcntl(caglobals.ip.shutdownFds[1], F_SETFD, ret|FD_CLOEXEC);
563         }
564         if (-1 == ret)
565         {
566             close(caglobals.ip.shutdownFds[1]);
567             close(caglobals.ip.shutdownFds[0]);
568             caglobals.ip.shutdownFds[0] = -1;
569             caglobals.ip.shutdownFds[1] = -1;
570         }
571     }
572 #endif
573     if (-1 == ret)
574     {
575         OIC_LOG_V(ERROR, TAG, "pipe failed: %s", strerror(errno));
576         caglobals.ip.selectTimeout = SELECT_TIMEOUT; //poll needed for shutdown
577     }
578 #else
579     //msys stuff here
580 #endif
581 }
582
583 CAResult_t CAIPStartServer(const ca_thread_pool_t threadPool)
584 {
585     CAResult_t res = CA_STATUS_OK;
586
587     if (caglobals.ip.started)
588     {
589         return res;
590     }
591
592     if (!IPv4MulticastAddress.s_addr)
593     {
594         (void)inet_pton(AF_INET, IPv4_MULTICAST, &IPv4MulticastAddress);
595         (void)inet_pton(AF_INET6, IPv6_MULTICAST_INT, &IPv6MulticastAddressInt);
596         (void)inet_pton(AF_INET6, IPv6_MULTICAST_LNK, &IPv6MulticastAddressLnk);
597         (void)inet_pton(AF_INET6, IPv6_MULTICAST_RLM, &IPv6MulticastAddressRlm);
598         (void)inet_pton(AF_INET6, IPv6_MULTICAST_ADM, &IPv6MulticastAddressAdm);
599         (void)inet_pton(AF_INET6, IPv6_MULTICAST_SIT, &IPv6MulticastAddressSit);
600         (void)inet_pton(AF_INET6, IPv6_MULTICAST_ORG, &IPv6MulticastAddressOrg);
601         (void)inet_pton(AF_INET6, IPv6_MULTICAST_GLB, &IPv6MulticastAddressGlb);
602     }
603
604     if (!caglobals.ip.ipv6enabled && !caglobals.ip.ipv4enabled)
605     {
606         caglobals.ip.ipv4enabled = true;  // only needed to run CA tests
607     }
608
609     if (caglobals.ip.ipv6enabled)
610     {
611         NEWSOCKET(AF_INET6, u6)
612         NEWSOCKET(AF_INET6, u6s)
613         NEWSOCKET(AF_INET6, m6)
614         NEWSOCKET(AF_INET6, m6s)
615         OIC_LOG_V(INFO, TAG, "IPv6 unicast port: %u", caglobals.ip.u6.port);
616     }
617     if (caglobals.ip.ipv4enabled)
618     {
619         NEWSOCKET(AF_INET, u4)
620         NEWSOCKET(AF_INET, u4s)
621         NEWSOCKET(AF_INET, m4)
622         NEWSOCKET(AF_INET, m4s)
623         OIC_LOG_V(INFO, TAG, "IPv4 unicast port: %u", caglobals.ip.u4.port);
624     }
625
626     OIC_LOG_V(DEBUG, TAG,
627               "socket summary: u6=%d, u6s=%d, u4=%d, u4s=%d, m6=%d, m6s=%d, m4=%d, m4s=%d",
628               caglobals.ip.u6.fd, caglobals.ip.u6s.fd, caglobals.ip.u4.fd, caglobals.ip.u4s.fd,
629               caglobals.ip.m6.fd, caglobals.ip.m6s.fd, caglobals.ip.m4.fd, caglobals.ip.m4s.fd);
630
631     OIC_LOG_V(DEBUG, TAG,
632               "port summary: u6 port=%d, u6s port=%d, u4 port=%d, u4s port=%d, m6 port=%d,"
633               "m6s port=%d, m4 port=%d, m4s port=%d",
634               caglobals.ip.u6.port, caglobals.ip.u6s.port, caglobals.ip.u4.port,
635               caglobals.ip.u4s.port, caglobals.ip.m6.port, caglobals.ip.m6s.port,
636               caglobals.ip.m4.port, caglobals.ip.m4s.port);
637     // create pipe for fast shutdown
638     CAInitializePipe();
639     CHECKFD(caglobals.ip.shutdownFds[0]);
640     CHECKFD(caglobals.ip.shutdownFds[1]);
641
642     // create source of network interface change notifications
643     CAInitializeNetlink();
644
645     caglobals.ip.selectTimeout = CAGetPollingInterval(caglobals.ip.selectTimeout);
646
647     res = CAIPStartListenServer();
648     if (CA_STATUS_OK != res)
649     {
650         OIC_LOG_V(ERROR, TAG, "Failed to start listening server![%d]", res);
651         return res;
652     }
653
654     caglobals.ip.terminate = false;
655     res = ca_thread_pool_add_task(threadPool, CAReceiveHandler, NULL);
656     if (CA_STATUS_OK != res)
657     {
658         OIC_LOG(ERROR, TAG, "thread_pool_add_task failed");
659         return res;
660     }
661     OIC_LOG(DEBUG, TAG, "CAReceiveHandler thread started successfully.");
662
663     caglobals.ip.started = true;
664     return CA_STATUS_OK;
665 }
666
667 void CAIPStopServer()
668 {
669     caglobals.ip.started = false;
670     caglobals.ip.terminate = true;
671 #if !defined(__msys_nt__)
672
673     if (caglobals.ip.shutdownFds[1] != -1)
674     {
675         close(caglobals.ip.shutdownFds[1]);
676         // receive thread will stop immediately
677     }
678     else
679     {
680         // receive thread will stop in SELECT_TIMEOUT seconds.
681     }
682 #else
683     //msys stuff here
684 #endif
685 }
686
687 void CAWakeUpForChange()
688 {
689 #if !defined(__msys_nt__)
690     if (caglobals.ip.shutdownFds[1] != -1)
691     {
692         ssize_t len = 0;
693         do
694         {
695             len = write(caglobals.ip.shutdownFds[1], "w", 1);
696         } while ((len == -1) && (errno == EINTR));
697         if ((len == -1) && (errno != EINTR) && (errno != EPIPE))
698         {
699             OIC_LOG_V(DEBUG, TAG, "write failed: %s", strerror(errno));
700         }
701     }
702 #else
703     //msys stuff here
704 #endif
705 }
706
707 static void applyMulticastToInterface4(struct in_addr inaddr)
708 {
709     if (!caglobals.ip.ipv4enabled)
710     {
711         return;
712     }
713
714     struct ip_mreqn mreq = { .imr_multiaddr = IPv4MulticastAddress,
715                              .imr_address = inaddr,
716                              .imr_ifindex = 0 };
717     if (setsockopt(caglobals.ip.m4.fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof (mreq)))
718     {
719         if (EADDRINUSE != errno)
720         {
721             OIC_LOG_V(ERROR, TAG, "IPv4 IP_ADD_MEMBERSHIP failed: %s", CAIPS_GET_ERROR);
722         }
723     }
724     if (setsockopt(caglobals.ip.m4s.fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof (mreq)))
725     {
726         if (EADDRINUSE != errno)
727         {
728             OIC_LOG_V(ERROR, TAG, "secure IPv4 IP_ADD_MEMBERSHIP failed: %s", CAIPS_GET_ERROR);
729         }
730     }
731 }
732
733 static void applyMulticast6(int fd, struct in6_addr *addr, uint32_t ifindex)
734 {
735     struct ipv6_mreq mreq = {.ipv6mr_multiaddr = *addr, .ipv6mr_interface = ifindex};
736     if (setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof (mreq)))
737     {
738         if (EADDRINUSE != errno)
739         {
740             OIC_LOG_V(ERROR, TAG, "IPv6 IP_ADD_MEMBERSHIP failed: %s", CAIPS_GET_ERROR);
741         }
742     }
743 }
744
745 static void applyMulticastToInterface6(uint32_t ifindex)
746 {
747     if (!caglobals.ip.ipv6enabled)
748     {
749         return;
750     }
751     //applyMulticast6(caglobals.ip.m6.fd, &IPv6MulticastAddressInt, ifindex);
752     applyMulticast6(caglobals.ip.m6.fd, &IPv6MulticastAddressLnk, ifindex);
753     //applyMulticast6(caglobals.ip.m6.fd, &IPv6MulticastAddressRlm, ifindex);
754     //applyMulticast6(caglobals.ip.m6.fd, &IPv6MulticastAddressAdm, ifindex);
755     //applyMulticast6(caglobals.ip.m6.fd, &IPv6MulticastAddressSit, ifindex);
756     //applyMulticast6(caglobals.ip.m6.fd, &IPv6MulticastAddressOrg, ifindex);
757     //applyMulticast6(caglobals.ip.m6.fd, &IPv6MulticastAddressGlb, ifindex);
758
759     //applyMulticast6(caglobals.ip.m6s.fd, &IPv6MulticastAddressInt, ifindex);
760     applyMulticast6(caglobals.ip.m6s.fd, &IPv6MulticastAddressLnk, ifindex);
761     //applyMulticast6(caglobals.ip.m6s.fd, &IPv6MulticastAddressRlm, ifindex);
762     //applyMulticast6(caglobals.ip.m6s.fd, &IPv6MulticastAddressAdm, ifindex);
763     //applyMulticast6(caglobals.ip.m6s.fd, &IPv6MulticastAddressSit, ifindex);
764     //applyMulticast6(caglobals.ip.m6s.fd, &IPv6MulticastAddressOrg, ifindex);
765     //applyMulticast6(caglobals.ip.m6s.fd, &IPv6MulticastAddressGlb, ifindex);
766 }
767
768 CAResult_t CAIPStartListenServer()
769 {
770     u_arraylist_t *iflist = CAIPGetInterfaceInformation(0);
771     if (!iflist)
772     {
773         OIC_LOG_V(ERROR, TAG, "get interface info failed: %s", strerror(errno));
774         return CA_STATUS_FAILED;
775     }
776
777     uint32_t len = u_arraylist_length(iflist);
778     OIC_LOG_V(DEBUG, TAG, "IP network interfaces found: %d", len);
779
780     for (uint32_t i = 0; i < len; i++)
781     {
782         CAInterface_t *ifitem = (CAInterface_t *)u_arraylist_get(iflist, i);
783
784         if (!ifitem)
785         {
786             continue;
787         }
788 #if !defined(__msys_nt__)
789         if ((ifitem->flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
790 #else
791     //IFF_RUNNING is not on msys or win32
792 #endif
793         {
794             continue;
795         }
796         if (ifitem->family == AF_INET)
797         {
798             struct in_addr inaddr;
799             inaddr.s_addr = ifitem->ipv4addr;
800             applyMulticastToInterface4(inaddr);
801             OIC_LOG_V(DEBUG, TAG, "IPv4 network interface: %s", ifitem->name);
802         }
803         if (ifitem->family == AF_INET6)
804         {
805             applyMulticastToInterface6(ifitem->index);
806             OIC_LOG_V(DEBUG, TAG, "IPv6 network interface: %s", ifitem->name);
807         }
808     }
809
810     u_arraylist_destroy(iflist);
811     return CA_STATUS_OK;
812 }
813
814 CAResult_t CAIPStopListenServer()
815 {
816     u_arraylist_t *iflist = CAIPGetInterfaceInformation(0);
817     if (!iflist)
818     {
819         OIC_LOG_V(ERROR, TAG, "Get interface info failed: %s", strerror(errno));
820         return CA_STATUS_FAILED;
821     }
822
823     uint32_t len = u_arraylist_length(iflist);
824     OIC_LOG_V(DEBUG, TAG, "IP network interfaces found: %d", len);
825
826     for (uint32_t i = 0; i < len; i++)
827     {
828         CAInterface_t *ifitem = (CAInterface_t *)u_arraylist_get(iflist, i);
829
830         if (!ifitem)
831         {
832             continue;
833         }
834 #if !defined(__msys_nt__)
835         if ((ifitem->flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
836 #else
837     //IFF_RUNNING is not on msys or win32
838 #endif
839         {
840             continue;
841         }
842         if (ifitem->family == AF_INET)
843         {
844             close(caglobals.ip.m4.fd);
845             close(caglobals.ip.m4s.fd);
846             caglobals.ip.m4.fd = -1;
847             caglobals.ip.m4s.fd = -1;
848             OIC_LOG_V(DEBUG, TAG, "IPv4 network interface: %s cloed", ifitem->name);
849         }
850         if (ifitem->family == AF_INET6)
851         {
852             close(caglobals.ip.m6.fd);
853             close(caglobals.ip.m6s.fd);
854             caglobals.ip.m6.fd = -1;
855             caglobals.ip.m6s.fd = -1;
856             OIC_LOG_V(DEBUG, TAG, "IPv6 network interface: %s", ifitem->name);
857         }
858     }
859     u_arraylist_destroy(iflist);
860     return CA_STATUS_OK;
861 }
862
863 static void CAProcessNewInterface(CAInterface_t *ifitem)
864 {
865     if (!ifitem)
866     {
867         OIC_LOG(DEBUG, TAG, "ifitem is null");
868         return;
869     }
870     if (ifitem->family == AF_INET6)
871     {
872         applyMulticastToInterface6(ifitem->index);
873     }
874     if (ifitem->family == AF_INET)
875     {
876         struct in_addr inaddr = { .s_addr = ifitem->ipv4addr };
877         applyMulticastToInterface4(inaddr);
878     }
879 }
880
881 void CAIPSetPacketReceiveCallback(CAIPPacketReceivedCallback callback)
882 {
883     g_packetReceivedCallback = callback;
884 }
885
886 void CAIPSetExceptionCallback(CAIPExceptionCallback callback)
887 {
888     g_exceptionCallback = callback;
889 }
890
891 void CAIPSetConnectionStateChangeCallback(CAIPConnectionStateChangeCallback callback)
892 {
893     CAIPSetNetworkMonitorCallback(callback);
894 }
895
896 static void sendData(int fd, const CAEndpoint_t *endpoint,
897                      const void *data, uint32_t dlen,
898                      const char *cast, const char *fam)
899 {
900     OIC_LOG(DEBUG, TAG, "IN");
901
902     if (!endpoint)
903     {
904         OIC_LOG(DEBUG, TAG, "endpoint is null");
905         return;
906     }
907
908     char *secure = (endpoint->flags & CA_SECURE) ? "secure " : "";
909     (void)secure;   // eliminates release warning
910     struct sockaddr_storage sock;
911     CAConvertNameToAddr(endpoint->addr, endpoint->port, &sock);
912
913     socklen_t socklen;
914     if (sock.ss_family == AF_INET6)
915     {
916         struct sockaddr_in6 *sock6 = (struct sockaddr_in6 *)&sock;
917         if (!sock6->sin6_scope_id)
918         {
919             sock6->sin6_scope_id = endpoint->ifindex;
920         }
921         socklen = sizeof(struct sockaddr_in6);
922     }
923     else
924     {
925         socklen = sizeof(struct sockaddr_in);
926     }
927 #if !defined(__msys_nt__)
928     ssize_t len = sendto(fd, data, dlen, 0, (struct sockaddr *)&sock, socklen);
929     if (-1 == len)
930     {
931          // If logging is not defined/enabled.
932          (void)cast;
933          (void)fam;
934         OIC_LOG_V(ERROR, TAG, "%s%s %s sendTo failed: %s", secure, cast, fam, strerror(errno));
935     }
936     else
937     {
938         OIC_LOG_V(INFO, TAG, "%s%s %s sendTo is successful: %zd bytes", secure, cast, fam, len);
939     }
940 #else
941
942 #endif
943 }
944
945 static void sendMulticastData6(const u_arraylist_t *iflist,
946                                CAEndpoint_t *endpoint,
947                                const void *data, uint32_t datalen)
948 {
949     if (!endpoint)
950     {
951         OIC_LOG(DEBUG, TAG, "endpoint is null");
952         return;
953     }
954
955     int scope = endpoint->flags & CA_SCOPE_MASK;
956     char *ipv6mcname = ipv6mcnames[scope];
957     if (!ipv6mcname)
958     {
959         OIC_LOG_V(INFO, TAG, "IPv6 multicast scope invalid: %d", scope);
960         return;
961     }
962     OICStrcpy(endpoint->addr, sizeof(endpoint->addr), ipv6mcname);
963     int fd = caglobals.ip.u6.fd;
964
965     uint32_t len = u_arraylist_length(iflist);
966     for (uint32_t i = 0; i < len; i++)
967     {
968         CAInterface_t *ifitem = (CAInterface_t *)u_arraylist_get(iflist, i);
969         if (!ifitem)
970         {
971             continue;
972         }
973 #if !defined(__msys_nt__)
974         if ((ifitem->flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
975 #else
976
977 #endif
978         {
979             continue;
980         }
981         if (ifitem->family != AF_INET6)
982         {
983             continue;
984         }
985
986         int index = ifitem->index;
987         if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &index, sizeof (index)))
988         {
989             OIC_LOG_V(ERROR, TAG, "setsockopt6 failed: %s", CAIPS_GET_ERROR);
990
991             return;
992         }
993         sendData(fd, endpoint, data, datalen, "multicast", "ipv6");
994     }
995 }
996
997 static void sendMulticastData4(const u_arraylist_t *iflist,
998                                CAEndpoint_t *endpoint,
999                                const void *data, uint32_t datalen)
1000 {
1001     VERIFY_NON_NULL_VOID(endpoint, TAG, "endpoint is NULL");
1002
1003     struct ip_mreqn mreq = { .imr_multiaddr = IPv4MulticastAddress,
1004                              .imr_ifindex = 0 };
1005     OICStrcpy(endpoint->addr, sizeof(endpoint->addr), IPv4_MULTICAST);
1006     int fd = caglobals.ip.u4.fd;
1007
1008     uint32_t len = u_arraylist_length(iflist);
1009     for (uint32_t i = 0; i < len; i++)
1010     {
1011         CAInterface_t *ifitem = (CAInterface_t *)u_arraylist_get(iflist, i);
1012         if (!ifitem)
1013         {
1014             continue;
1015         }
1016 #if !defined(__msys_nt__)
1017         if ((ifitem->flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
1018 #else
1019
1020 #endif
1021         {
1022             continue;
1023         }
1024         if (ifitem->family != AF_INET)
1025         {
1026             continue;
1027         }
1028
1029         struct in_addr inaddr;
1030         inaddr.s_addr = ifitem->ipv4addr;
1031         mreq.imr_address = inaddr;
1032         if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, &mreq, sizeof (mreq)))
1033         {
1034             OIC_LOG_V(ERROR, TAG, "send IP_MULTICAST_IF failed: %s (using defualt)",
1035                     CAIPS_GET_ERROR);
1036         }
1037         sendData(fd, endpoint, data, datalen, "multicast", "ipv4");
1038     }
1039 }
1040
1041 void CAIPSendData(CAEndpoint_t *endpoint, const void *data, uint32_t datalen,
1042                   bool isMulticast)
1043 {
1044     VERIFY_NON_NULL_VOID(endpoint, TAG, "endpoint is NULL");
1045     VERIFY_NON_NULL_VOID(data, TAG, "data is NULL");
1046
1047     bool isSecure = (endpoint->flags & CA_SECURE) != 0;
1048
1049     if (isMulticast)
1050     {
1051         endpoint->port = isSecure ? CA_SECURE_COAP : CA_COAP;
1052
1053         u_arraylist_t *iflist = CAIPGetInterfaceInformation(0);
1054         if (!iflist)
1055         {
1056             OIC_LOG_V(ERROR, TAG, "get interface info failed: %s", strerror(errno));
1057             return;
1058         }
1059
1060         if ((endpoint->flags & CA_IPV6) && caglobals.ip.ipv6enabled)
1061         {
1062             sendMulticastData6(iflist, endpoint, data, datalen);
1063         }
1064         if ((endpoint->flags & CA_IPV4) && caglobals.ip.ipv4enabled)
1065         {
1066             sendMulticastData4(iflist, endpoint, data, datalen);
1067         }
1068
1069         u_arraylist_destroy(iflist);
1070     }
1071     else
1072     {
1073         if (!endpoint->port)    // unicast discovery
1074         {
1075             endpoint->port = isSecure ? CA_SECURE_COAP : CA_COAP;
1076         }
1077
1078         int fd;
1079         if (caglobals.ip.ipv6enabled && (endpoint->flags & CA_IPV6))
1080         {
1081             fd = isSecure ? caglobals.ip.u6s.fd : caglobals.ip.u6.fd;
1082 #ifndef __WITH_DTLS__
1083             fd = caglobals.ip.u6.fd;
1084 #endif
1085             sendData(fd, endpoint, data, datalen, "unicast", "ipv6");
1086         }
1087         if (caglobals.ip.ipv4enabled && (endpoint->flags & CA_IPV4))
1088         {
1089             fd = isSecure ? caglobals.ip.u4s.fd : caglobals.ip.u4.fd;
1090 #ifndef __WITH_DTLS__
1091             fd = caglobals.ip.u4.fd;
1092 #endif
1093             sendData(fd, endpoint, data, datalen, "unicast", "ipv4");
1094         }
1095     }
1096 }
1097
1098 CAResult_t CAGetIPInterfaceInformation(CAEndpoint_t **info, uint32_t *size)
1099 {
1100     VERIFY_NON_NULL(info, TAG, "info is NULL");
1101     VERIFY_NON_NULL(size, TAG, "size is NULL");
1102
1103     u_arraylist_t *iflist = CAIPGetInterfaceInformation(0);
1104     if (!iflist)
1105     {
1106         OIC_LOG_V(ERROR, TAG, "get interface info failed: %s", strerror(errno));
1107         return CA_STATUS_FAILED;
1108     }
1109
1110     uint32_t len = u_arraylist_length(iflist);
1111     uint32_t length = len;
1112
1113 #ifdef __WITH_DTLS__
1114     //If DTLS is supported, each interface can support secure port as well
1115     length = len * 2;
1116 #endif
1117
1118     CAEndpoint_t *eps = (CAEndpoint_t *)OICCalloc(length, sizeof (CAEndpoint_t));
1119     if (!eps)
1120     {
1121         OIC_LOG(ERROR, TAG, "Malloc Failed");
1122         u_arraylist_destroy(iflist);
1123         return CA_MEMORY_ALLOC_FAILED;
1124     }
1125
1126     for (uint32_t i = 0, j = 0; i < len; i++)
1127     {
1128         CAInterface_t *ifitem = (CAInterface_t *)u_arraylist_get(iflist, i);
1129         if(!ifitem)
1130         {
1131             continue;
1132         }
1133
1134         eps[j].adapter = CA_ADAPTER_IP;
1135         eps[j].ifindex = 0;
1136
1137         if (ifitem->family == AF_INET6)
1138         {
1139             eps[j].flags = CA_IPV6;
1140             eps[j].port = caglobals.ip.u6.port;
1141         }
1142         else
1143         {
1144             eps[j].flags = CA_IPV4;
1145             eps[j].port = caglobals.ip.u4.port;
1146
1147             inet_ntop(AF_INET, &(ifitem->ipv4addr), eps[j].addr, MAX_ADDR_STR_SIZE_CA);
1148         }
1149
1150 #ifdef __WITH_DTLS__
1151         j++;
1152
1153         eps[j].adapter = CA_ADAPTER_IP;
1154         eps[j].ifindex = 0;
1155
1156         if (ifitem->family == AF_INET6)
1157         {
1158             eps[j].flags = CA_IPV6 | CA_SECURE;
1159             eps[j].port = caglobals.ip.u6s.port;
1160         }
1161         else
1162         {
1163             eps[j].flags = CA_IPV4 | CA_SECURE;
1164             eps[j].port = caglobals.ip.u4s.port;
1165             inet_ntop(AF_INET, &(ifitem->ipv4addr), eps[j].addr, MAX_ADDR_STR_SIZE_CA);
1166         }
1167 #endif
1168         j++;
1169     }
1170
1171     *info = eps;
1172     *size = len;
1173
1174     u_arraylist_destroy(iflist);
1175
1176     return CA_STATUS_OK;
1177 }