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