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