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