Update snapshot(2017-12-06)
[platform/upstream/iotivity.git] / resource / csdk / connectivity / src / ip_adapter / caipserver.c
1 /* ****************************************************************
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 #ifdef __TIZENRT__
29 #include <tinyara/config.h>
30 #include <uio.h>
31 #endif
32
33 #include "iotivity_config.h"
34 #include <sys/types.h>
35 #if !defined(_WIN32)
36 #include <sys/socket.h>
37 #endif
38
39 #if defined(_WIN32)
40 #include <assert.h>
41 #include <winsock2.h>
42 #include <ws2def.h>
43 #include <mswsock.h>
44 #include <ws2tcpip.h>
45 #endif
46
47 #include <stdio.h>
48 #include <string.h>
49 #if !defined(_MSC_VER)
50 #include <unistd.h>
51 #endif //!defined(_MSC_VER)
52 #include <sys/types.h>
53 #include <fcntl.h>
54 #if !defined(_WIN32)
55 #include <sys/select.h>
56 #include <arpa/inet.h>
57 #include <netinet/in.h>
58 #include <net/if.h>
59 #endif
60 #include <errno.h>
61 #ifdef __linux__
62 #include <linux/netlink.h>
63 #include <linux/rtnetlink.h>
64 #endif
65
66 #ifdef __TIZENRT__
67 #include <uio.h>
68 #include <mqueue.h>
69 #endif
70
71 #include <coap/pdu.h>
72 #include "caipinterface.h"
73 #include "caipnwmonitor.h"
74 #include "caadapterutils.h"
75 #if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
76 #include "ca_adapter_net_ssl.h"
77 #endif
78 #include "octhread.h"
79 #include "oic_malloc.h"
80 #include "oic_string.h"
81
82 #define USE_IP_MREQN
83 #if defined(_WIN32)
84 #undef USE_IP_MREQN
85 #endif
86
87 #ifdef __TIZEN__
88 #include <pthread.h>
89 #endif
90
91 /*
92  * Logging tag for module name
93  */
94 //#define TAG "OIC_CA_IP_SERVER"
95 #define TAG IP_SERVER_TAG
96
97 #ifdef __TIZENRT__
98 mqd_t g_nwevent_mqfd;
99 #ifdef CONFIG_NET_LWIP
100 #define SOCK_CLOEXEC 0
101 #else
102 #define SOCK_CLOEXEC 1
103 #endif
104 #endif
105 #define SELECT_TIMEOUT 1     // select() seconds (and termination latency)
106
107 #define IPv4_MULTICAST     "224.0.1.187"
108 static struct in_addr IPv4MulticastAddress = { 0 };
109
110 #define IPv6_DOMAINS       16
111 #define MOBILE_INTERFACES  2
112 #define IPv6_MULTICAST_INT "ff01::158"
113 static struct in6_addr IPv6MulticastAddressInt;
114 #define IPv6_MULTICAST_LNK "ff02::158"
115 static struct in6_addr IPv6MulticastAddressLnk;
116 #define IPv6_MULTICAST_RLM "ff03::158"
117 static struct in6_addr IPv6MulticastAddressRlm;
118 #define IPv6_MULTICAST_ADM "ff04::158"
119 static struct in6_addr IPv6MulticastAddressAdm;
120 #define IPv6_MULTICAST_SIT "ff05::158"
121 static struct in6_addr IPv6MulticastAddressSit;
122 #define IPv6_MULTICAST_ORG "ff08::158"
123 static struct in6_addr IPv6MulticastAddressOrg;
124 #define IPv6_MULTICAST_GLB "ff0e::158"
125 static struct in6_addr IPv6MulticastAddressGlb;
126
127 /*
128  * Buffer size for the receive message buffer
129  */
130 #define RECV_MSG_BUF_LEN 16384
131
132 static char *ipv6mcnames[IPv6_DOMAINS] = {
133     NULL,
134     IPv6_MULTICAST_INT,
135     IPv6_MULTICAST_LNK,
136     IPv6_MULTICAST_RLM,
137     IPv6_MULTICAST_ADM,
138     IPv6_MULTICAST_SIT,
139     NULL,
140     NULL,
141     IPv6_MULTICAST_ORG,
142     NULL,
143     NULL,
144     NULL,
145     NULL,
146     NULL,
147     IPv6_MULTICAST_GLB,
148     NULL
149 };
150
151 // Samsung Mobile
152 static char *mobileinferfaces[MOBILE_INTERFACES] = {
153     "rmnet", "pdp"
154 };
155
156 #ifdef __TIZENRT__
157 struct in6_pktinfo {
158         struct in6_addr ipi6_addr;
159         int             ipi6_ifindex;
160 };
161
162 struct in_pktinfo
163 {
164   unsigned int   ipi_ifindex;  /* Interface index */
165   struct in_addr ipi_spec_dst; /* Local address */
166   struct in_addr ipi_addr;     /* Header Destination
167                                     address */
168 };
169
170
171 #define RTMGRP_LINK 1
172 #define IP_PKTINFO         8
173 #define IPV6_PKTINFO            50
174 #define IPV6_MULTICAST_IF 9
175 #define IPV6_V6ONLY 27
176 #define IPV6_RECVPKTINFO       50
177 #define IPV6_JOIN_GROUP 12
178 #endif
179
180 /**
181  * By default, IP multicast datagrams are sent with a time-to-live (TTL) of 1.
182  * An application can choose an initial TTL.
183  */
184 static size_t multicastTTL = 1;
185
186 #if defined (_WIN32)
187 #define IFF_UP_RUNNING_FLAGS  (IFF_UP)
188
189     char* caips_get_error(){
190         static char buffer[32];
191         snprintf(buffer, 32, "%i", WSAGetLastError());
192         return buffer;
193     }
194 #define CAIPS_GET_ERROR \
195     caips_get_error()
196 #else
197 #define IFF_UP_RUNNING_FLAGS  (IFF_UP|IFF_RUNNING)
198
199 #define CAIPS_GET_ERROR \
200     strerror(errno)
201 #endif
202 static CAIPErrorHandleCallback g_ipErrorHandler = NULL;
203
204 static CAIPPacketReceivedCallback g_packetReceivedCallback = NULL;
205
206 static void CAFindReadyMessage();
207 #if !defined(WSA_WAIT_EVENT_0)
208 static void CASelectReturned(fd_set *readFds, int ret);
209 #else
210 static void CAEventReturned(CASocketFd_t socket);
211 #endif
212
213 static CAResult_t CAReceiveMessage(CASocketFd_t fd, CATransportFlags_t flags);
214
215 #ifdef __TIZEN__
216 static int cleanup_pop_arg = 1;
217
218 static void CAIPCleanupHandler(void *arg)
219 {
220     (void)arg;
221
222     OIC_LOG(DEBUG, TAG, "Called clean-up handler");
223
224     if (caglobals.ip.shutdownFds[0] != OC_INVALID_SOCKET)
225     {
226         close(caglobals.ip.shutdownFds[0]);
227         caglobals.ip.shutdownFds[0] = OC_INVALID_SOCKET;
228     }
229 }
230
231 static void CAReceiveHandler(void *data)
232 {
233     (void)data;
234     OIC_LOG(DEBUG, TAG, "IN - CAReceiveHandler");
235
236     pthread_cleanup_push(CAIPCleanupHandler, NULL);
237
238     while (!caglobals.ip.terminate)
239     {
240         CAFindReadyMessage();
241     }
242
243     pthread_cleanup_pop(cleanup_pop_arg);
244
245     OIC_LOG(DEBUG, TAG, "OUT - CAReceiveHandler");
246 }
247 #else
248 static void CAReceiveHandler(void *data)
249 {
250     (void)data;
251     OIC_LOG(DEBUG, TAG, "IN - CAReceiveHandler");
252
253     while (!caglobals.ip.terminate)
254     {
255         CAFindReadyMessage();
256     }
257 #ifndef __TIZENRT__
258     if (caglobals.ip.shutdownFds[0] != OC_INVALID_SOCKET)
259     {
260         close(caglobals.ip.shutdownFds[0]);
261         caglobals.ip.shutdownFds[0] = OC_INVALID_SOCKET;
262     }
263 #endif
264     OIC_LOG(DEBUG, TAG, "OUT - CAReceiveHandler");
265 }
266 #endif
267
268 #if !defined(WSA_WAIT_EVENT_0)
269
270 #define CLOSE_SOCKET(TYPE) \
271     if (caglobals.ip.TYPE.fd != OC_INVALID_SOCKET) \
272     { \
273         close(caglobals.ip.TYPE.fd); \
274         caglobals.ip.TYPE.fd = OC_INVALID_SOCKET; \
275     }
276
277 #define SET(TYPE, FDS) \
278     if (caglobals.ip.TYPE.fd != OC_INVALID_SOCKET) \
279     { \
280         FD_SET(caglobals.ip.TYPE.fd, FDS); \
281     }
282
283 #define ISSET(TYPE, FDS, FLAGS) \
284     if (caglobals.ip.TYPE.fd != OC_INVALID_SOCKET && FD_ISSET(caglobals.ip.TYPE.fd, FDS)) \
285     { \
286         fd = caglobals.ip.TYPE.fd; \
287         flags = FLAGS; \
288     }
289
290
291 static void CAFindReadyMessage()
292 {
293     fd_set readFds;
294     struct timeval timeout;
295
296     timeout.tv_sec = caglobals.ip.selectTimeout;
297     timeout.tv_usec = 0;
298     struct timeval *tv = caglobals.ip.selectTimeout == -1 ? NULL : &timeout;
299
300     FD_ZERO(&readFds);
301     SET(u6,  &readFds)
302     SET(u6s, &readFds)
303     SET(u4,  &readFds)
304     SET(u4s, &readFds)
305     SET(m6,  &readFds)
306     SET(m6s, &readFds)
307     SET(m4,  &readFds)
308     SET(m4s, &readFds)
309 #ifndef __TIZENRT__
310     if (caglobals.ip.shutdownFds[0] != -1)
311     {
312         FD_SET(caglobals.ip.shutdownFds[0], &readFds);
313     }
314 #endif
315     if (caglobals.ip.netlinkFd != OC_INVALID_SOCKET)
316     {
317         FD_SET(caglobals.ip.netlinkFd, &readFds);
318     }
319
320     int ret = select(caglobals.ip.maxfd + 1, &readFds, NULL, NULL, tv);
321
322     if (caglobals.ip.terminate)
323     {
324         OIC_LOG_V(INFO, TAG, "Packet receiver Stop request received.");
325         return;
326     }
327 #ifdef __TIZENRT__
328     u_arraylist_t *iflist = CAFindInterfaceChange();
329     if (iflist)
330     {
331         uint32_t listLength = u_arraylist_length(iflist);
332         for (uint32_t i = 0; i < listLength; i++)
333         {
334             CAInterface_t *ifitem = (CAInterface_t *)u_arraylist_get(iflist, i);
335             if (ifitem)
336             {
337                 CAProcessNewInterface(ifitem);
338             }
339         }
340         u_arraylist_destroy(iflist);
341     }
342 #endif
343     if (0 < ret)
344     {
345         CASelectReturned(&readFds, ret);
346     }
347     else if (0 > ret)
348     {
349         OIC_LOG_V(FATAL, TAG, "select error %s", CAIPS_GET_ERROR);
350     }
351 }
352
353 static void CASelectReturned(fd_set *readFds, int ret)
354 {
355     (void)ret;
356     CASocketFd_t fd = OC_INVALID_SOCKET;
357     CATransportFlags_t flags = CA_DEFAULT_FLAGS;
358
359     while (!caglobals.ip.terminate)
360     {
361         ISSET(u6,  readFds, CA_IPV6)
362         else ISSET(u6s, readFds, CA_IPV6 | CA_SECURE)
363         else ISSET(u4,  readFds, CA_IPV4)
364         else ISSET(u4s, readFds, CA_IPV4 | CA_SECURE)
365         else ISSET(m6,  readFds, CA_MULTICAST | CA_IPV6)
366         else ISSET(m6s, readFds, CA_MULTICAST | CA_IPV6 | CA_SECURE)
367         else ISSET(m4,  readFds, CA_MULTICAST | CA_IPV4)
368         else ISSET(m4s, readFds, CA_MULTICAST | CA_IPV4 | CA_SECURE)
369         else if ((caglobals.ip.netlinkFd != OC_INVALID_SOCKET) && FD_ISSET(caglobals.ip.netlinkFd, readFds))
370         {
371 #ifndef __TIZENRT__
372             u_arraylist_t *iflist = CAFindInterfaceChange();
373             if (iflist)
374             {
375                 uint32_t listLength = u_arraylist_length(iflist);
376                 for (uint32_t i = 0; i < listLength; i++)
377                 {
378                     CAInterface_t *ifitem = (CAInterface_t *)u_arraylist_get(iflist, i);
379                     if (ifitem)
380                     {
381                         CAProcessNewInterface(ifitem);
382                     }
383                 }
384                 u_arraylist_destroy(iflist);
385             }
386             break;
387 #endif
388         }
389 #ifndef __TIZENRT__
390         else if (FD_ISSET(caglobals.ip.shutdownFds[0], readFds))
391         {
392             char buf[10] = {0};
393             ssize_t len = read(caglobals.ip.shutdownFds[0], buf, sizeof (buf));
394             if (-1 == len)
395             {
396                 continue;
397             }
398             break;
399         }
400 #endif
401         else
402         {
403             break;
404         }
405         (void)CAReceiveMessage(fd, flags);
406         FD_CLR(fd, readFds);
407     }
408 }
409
410 #else // if defined(WSA_WAIT_EVENT_0)
411
412 #define CLOSE_SOCKET(TYPE) \
413     if (caglobals.ip.TYPE.fd != OC_INVALID_SOCKET) \
414     { \
415         closesocket(caglobals.ip.TYPE.fd); \
416         caglobals.ip.TYPE.fd = OC_INVALID_SOCKET; \
417     }
418
419 #define PUSH_HANDLE(HANDLE, ARRAY, INDEX) \
420 { \
421     ARRAY[INDEX] = HANDLE; \
422     INDEX++; \
423 }
424
425 // Turn handle into WSAEvent and push to ARRAY
426 #define PUSH_SOCKET(SOCKET, ARRAY, INDEX) \
427     if (SOCKET != OC_INVALID_SOCKET) \
428     { \
429         WSAEVENT NewEvent; \
430         NewEvent = WSACreateEvent(); \
431         if (WSA_INVALID_EVENT != NewEvent) \
432         { \
433             if (0 != WSAEventSelect(SOCKET, NewEvent, FD_READ)) \
434             { \
435                 OIC_LOG_V(ERROR, TAG, "WSAEventSelect failed 0x%08x ", WSAGetLastError()); \
436                 if (!WSACloseEvent(NewEvent)) \
437                 { \
438                     OIC_LOG_V(ERROR, TAG, "WSACloseEvent(NewEvent) failed 0x%08x", WSAGetLastError()); \
439                 } \
440             } \
441             else \
442             { \
443                 PUSH_HANDLE(NewEvent, ARRAY, INDEX); \
444             } \
445         } \
446         else \
447         { \
448             OIC_LOG_V(ERROR, TAG, "WSACreateEvent(NewEvent) failed 0x%08x", WSAGetLastError()); \
449         }\
450     }
451
452 #define INSERT_SOCKET(FD, ARRAY, INDEX) \
453     { \
454         if (OC_INVALID_SOCKET != FD) \
455         { \
456             ARRAY[INDEX] = FD; \
457         } \
458     }
459
460
461 // Inserts the socket into the SOCKET_ARRAY and pushes the socket event into EVENT_ARRAY
462 #define PUSH_IP_SOCKET(TYPE, EVENT_ARRAY, SOCKET_ARRAY, INDEX) \
463     { \
464         if (OC_INVALID_SOCKET != caglobals.ip.TYPE.fd) \
465         { \
466             INSERT_SOCKET(caglobals.ip.TYPE.fd, SOCKET_ARRAY, INDEX); \
467             PUSH_SOCKET(caglobals.ip.TYPE.fd, EVENT_ARRAY, INDEX); \
468         } \
469     }
470
471 #define IS_MATCHING_IP_SOCKET(TYPE, SOCKET, FLAGS) \
472     if ((caglobals.ip.TYPE.fd != OC_INVALID_SOCKET) && (caglobals.ip.TYPE.fd == SOCKET)) \
473     { \
474         fd = caglobals.ip.TYPE.fd; \
475         flags = FLAGS; \
476     }
477
478 #define EVENT_ARRAY_SIZE  10
479
480 static void CAFindReadyMessage()
481 {
482     CASocketFd_t socketArray[EVENT_ARRAY_SIZE];
483     HANDLE eventArray[EVENT_ARRAY_SIZE];
484     int arraySize = 0;
485     int eventIndex;
486
487     // socketArray and eventArray should have same number of elements
488     OC_STATIC_ASSERT(_countof(socketArray) == _countof(eventArray), "Arrays should have same number of elements");
489
490     PUSH_IP_SOCKET(u6,  eventArray, socketArray, arraySize);
491     PUSH_IP_SOCKET(u6s, eventArray, socketArray, arraySize);
492     PUSH_IP_SOCKET(u4,  eventArray, socketArray, arraySize);
493     PUSH_IP_SOCKET(u4s, eventArray, socketArray, arraySize);
494     PUSH_IP_SOCKET(m6,  eventArray, socketArray, arraySize);
495     PUSH_IP_SOCKET(m6s, eventArray, socketArray, arraySize);
496     PUSH_IP_SOCKET(m4,  eventArray, socketArray, arraySize);
497     PUSH_IP_SOCKET(m4s, eventArray, socketArray, arraySize);
498
499     if (WSA_INVALID_EVENT != caglobals.ip.shutdownEvent)
500     {
501         INSERT_SOCKET(OC_INVALID_SOCKET, socketArray, arraySize);
502         PUSH_HANDLE(caglobals.ip.shutdownEvent, eventArray, arraySize);
503     }
504
505     /** @todo Support netlink events */
506
507     // Should not have overflowed buffer
508     assert(arraySize <= (_countof(socketArray)));
509
510     // Timeout is unnecessary on Windows
511     assert(-1 == caglobals.ip.selectTimeout);
512
513     while (!caglobals.ip.terminate)
514     {
515         int ret = WSAWaitForMultipleEvents(arraySize, eventArray, FALSE, WSA_INFINITE, FALSE);
516
517         switch (ret)
518         {
519             case WSA_WAIT_FAILED:
520                 OIC_LOG_V(ERROR, TAG, "WSAWaitForMultipleEvents returned WSA_WAIT_FAILED 0x%08x", WSAGetLastError());
521                 break;
522             case WSA_WAIT_IO_COMPLETION:
523                 OIC_LOG_V(ERROR, TAG, "WSAWaitForMultipleEvents returned WSA_WAIT_IO_COMPLETION 0x%08x", WSAGetLastError());
524                 break;
525             case WSA_WAIT_TIMEOUT:
526                 OIC_LOG_V(ERROR, TAG, "WSAWaitForMultipleEvents returned WSA_WAIT_TIMEOUT 0x%08x", WSAGetLastError());
527                 break;
528             default:
529                 eventIndex = ret - WSA_WAIT_EVENT_0;
530                 if ((eventIndex >= 0) && (eventIndex < arraySize))
531                 {
532                     if (false == WSAResetEvent(eventArray[eventIndex]))
533                     {
534                         OIC_LOG_V(ERROR, TAG, "WSAResetEvent failed 0x%08x", WSAGetLastError());
535                     }
536
537                     // Break out if shutdownEvent is triggered.
538                     if ((caglobals.ip.shutdownEvent != WSA_INVALID_EVENT) &&
539                         (caglobals.ip.shutdownEvent == eventArray[eventIndex]))
540                     {
541                         break;
542                     }
543                     CAEventReturned(socketArray[eventIndex]);
544                 }
545                 else
546                 {
547                     OIC_LOG_V(ERROR, TAG, "WSAWaitForMultipleEvents failed 0x%08x", WSAGetLastError());
548                 }
549                 break;
550         }
551
552     }
553
554     while (arraySize > 0)
555     {
556         arraySize--;
557         if (!WSACloseEvent(eventArray[arraySize]))
558         {
559             OIC_LOG_V(ERROR, TAG, "WSACloseEvent (Index %i) failed 0x%08x", arraySize, WSAGetLastError());
560         }
561     }
562
563     if (caglobals.ip.terminate)
564     {
565         caglobals.ip.shutdownEvent = WSA_INVALID_EVENT;
566         WSACleanup();
567     }
568 }
569
570 static void CAEventReturned(CASocketFd_t socket)
571 {
572     CASocketFd_t fd = OC_INVALID_SOCKET;
573     CATransportFlags_t flags = CA_DEFAULT_FLAGS;
574
575     while (!caglobals.ip.terminate)
576     {
577         IS_MATCHING_IP_SOCKET(u6,  socket, CA_IPV6)
578         else IS_MATCHING_IP_SOCKET(u6s, socket, CA_IPV6 | CA_SECURE)
579         else IS_MATCHING_IP_SOCKET(u4,  socket, CA_IPV4)
580         else IS_MATCHING_IP_SOCKET(u4s, socket, CA_IPV4 | CA_SECURE)
581         else IS_MATCHING_IP_SOCKET(m6,  socket, CA_MULTICAST | CA_IPV6)
582         else IS_MATCHING_IP_SOCKET(m6s, socket, CA_MULTICAST | CA_IPV6 | CA_SECURE)
583         else IS_MATCHING_IP_SOCKET(m4,  socket, CA_MULTICAST | CA_IPV4)
584         else IS_MATCHING_IP_SOCKET(m4s, socket, CA_MULTICAST | CA_IPV4 | CA_SECURE)
585         else
586         {
587             break;
588         }
589         (void)CAReceiveMessage(socket, flags);
590         // We will never get more than one match per socket, so always break.
591         break;
592     }
593 }
594
595 #endif
596
597 void CADeInitializeIPGlobals()
598 {
599     CloseMulticastSocket();
600
601     if (caglobals.ip.netlinkFd != OC_INVALID_SOCKET)
602     {
603 #ifdef _WIN32
604         closesocket(caglobals.ip.netlinkFd);
605 #else
606         close(caglobals.ip.netlinkFd);
607 #endif
608         caglobals.ip.netlinkFd = OC_INVALID_SOCKET;
609     }
610 }
611
612 static CAResult_t CAReceiveMessage(CASocketFd_t fd, CATransportFlags_t flags)
613 {
614     OIC_LOG(DEBUG, TAG, "IN - CAReceiveMessage");
615     char recvBuffer[RECV_MSG_BUF_LEN] = {0};
616
617     size_t len = 0;
618     int level = 0;
619     int type = 0;
620     int namelen = 0;
621     struct sockaddr_storage srcAddr = { .ss_family = 0 };
622     unsigned char *pktinfo = NULL;
623 #if !defined(WSA_CMSG_DATA)
624     struct cmsghdr *cmp = NULL;
625     struct iovec iov = { .iov_base = recvBuffer, .iov_len = sizeof (recvBuffer) };
626     union control
627     {
628         struct cmsghdr cmsg;
629         unsigned char data[CMSG_SPACE(sizeof (struct in6_pktinfo))];
630     } cmsg;
631
632     if (flags & CA_IPV6)
633     {
634         namelen = sizeof (struct sockaddr_in6);
635         level = IPPROTO_IPV6;
636         type = IPV6_PKTINFO;
637         len = sizeof (struct in6_pktinfo);
638     }
639     else
640     {
641         namelen = sizeof (struct sockaddr_in);
642         level = IPPROTO_IP;
643         type = IP_PKTINFO;
644         len = sizeof (struct in6_pktinfo);
645     }
646
647     struct msghdr msg = { .msg_name = &srcAddr,
648                           .msg_namelen = namelen,
649                           .msg_iov = &iov,
650                           .msg_iovlen = 1,
651                           .msg_control = &cmsg,
652                           .msg_controllen = CMSG_SPACE(len) };
653
654     ssize_t recvLen = recvmsg(fd, &msg, flags);
655     if (OC_SOCKET_ERROR == recvLen)
656     {
657         OIC_LOG_V(ERROR, TAG, "Recvfrom failed %s", strerror(errno));
658         return CA_STATUS_FAILED;
659     }
660     OIC_LOG_V(DEBUG, TAG, "recvd %u bytes from recvmsg", recvLen);
661
662     if (flags & CA_MULTICAST)
663     {
664         for (cmp = CMSG_FIRSTHDR(&msg); cmp != NULL; cmp = CMSG_NXTHDR(&msg, cmp))
665         {
666             if (cmp->cmsg_level == level && cmp->cmsg_type == type)
667             {
668                 pktinfo = CMSG_DATA(cmp);
669             }
670         }
671     }
672 #else // if defined(WSA_CMSG_DATA)
673     union control
674     {
675         WSACMSGHDR cmsg;
676         uint8_t data[WSA_CMSG_SPACE(sizeof (IN6_PKTINFO))];
677     } cmsg;
678     memset(&cmsg, 0, sizeof(cmsg));
679
680     if (flags & CA_IPV6)
681     {
682         namelen  = sizeof (struct sockaddr_in6);
683         level = IPPROTO_IPV6;
684         type = IPV6_PKTINFO;
685     }
686     else
687     {
688         namelen = sizeof (struct sockaddr_in);
689         level = IPPROTO_IP;
690         type = IP_PKTINFO;
691     }
692
693     WSABUF iov = {.len = sizeof (recvBuffer), .buf = recvBuffer};
694     WSAMSG msg = {.name = (PSOCKADDR)&srcAddr,
695                   .namelen = namelen,
696                   .lpBuffers = &iov,
697                   .dwBufferCount = 1,
698                   .Control = {.buf = cmsg.data, .len = sizeof (cmsg)}
699                  };
700
701     uint32_t recvLen = 0;
702     uint32_t ret = caglobals.ip.wsaRecvMsg(fd, &msg, &recvLen, 0,0);
703     OIC_LOG_V(DEBUG, TAG, "WSARecvMsg recvd %u bytes", recvLen);
704     if (OC_SOCKET_ERROR == ret)
705     {
706         OIC_LOG_V(ERROR, TAG, "WSARecvMsg failed %i", WSAGetLastError());
707     }
708
709     if (flags & CA_MULTICAST)
710     {
711         for (WSACMSGHDR *cmp = WSA_CMSG_FIRSTHDR(&msg); cmp != NULL;
712              cmp = WSA_CMSG_NXTHDR(&msg, cmp))
713         {
714             if (cmp->cmsg_level == level && cmp->cmsg_type == type)
715             {
716                 pktinfo = WSA_CMSG_DATA(cmp);
717             }
718         }
719     }
720 #endif // !defined(WSA_CMSG_DATA)
721     CASecureEndpoint_t sep = {.endpoint = {.adapter = CA_ADAPTER_IP, .flags = flags}};
722
723 #ifndef __TIZENRT__
724     if (flags & CA_IPV6)
725     {
726         /** @todo figure out correct usage for ifindex, and sin6_scope_id.*/
727         if ((flags & CA_MULTICAST) && pktinfo)
728         {
729             struct in6_addr *addr = &(((struct in6_pktinfo *)pktinfo)->ipi6_addr);
730             unsigned char topbits = ((unsigned char *)addr)[0];
731             if (topbits != 0xff)
732             {
733                 sep.endpoint.flags &= ~CA_MULTICAST;
734             }
735         }
736     }
737     else
738 #endif
739     {
740         if ((flags & CA_MULTICAST) && pktinfo)
741         {
742             struct in_addr *addr = &((struct in_pktinfo *)pktinfo)->ipi_addr;
743             uint32_t host = ntohl(addr->s_addr);
744             unsigned char topbits = ((unsigned char *)&host)[3];
745             if (topbits < 224 || topbits > 239)
746             {
747                 sep.endpoint.flags &= ~CA_MULTICAST;
748             }
749         }
750     }
751
752     CAConvertAddrToName(&srcAddr, namelen, sep.endpoint.addr, &sep.endpoint.port);
753
754     if (flags & CA_SECURE)
755     {
756 #ifdef __WITH_DTLS__
757         int ret = CAdecryptSsl(&sep, (uint8_t *)recvBuffer, recvLen);
758         OIC_LOG_V(INFO, TAG, "CAdecryptSsl returns [%d]", ret);
759 #else
760         OIC_LOG(ERROR, TAG, "Encrypted message but no DTLS");
761 #endif
762     }
763     else
764     {
765         if (g_packetReceivedCallback)
766         {
767             OIC_LOG(DEBUG, TAG, "call receivedCB");
768             g_packetReceivedCallback(&sep, recvBuffer, recvLen);
769         }
770     }
771
772     OIC_LOG(DEBUG, TAG, "OUT - CAReceiveMessage");
773     return CA_STATUS_OK;
774
775 }
776
777 void CAIPPullData()
778 {
779     OIC_LOG(DEBUG, TAG, "IN");
780     OIC_LOG(DEBUG, TAG, "OUT");
781 }
782
783 static CASocketFd_t CACreateSocket(int family, uint16_t *port, bool isMulticast)
784 {
785     int socktype = SOCK_DGRAM;
786 #ifdef SOCK_CLOEXEC
787     socktype |= SOCK_CLOEXEC;
788 #endif
789     CASocketFd_t fd = socket(family, socktype, IPPROTO_UDP);
790     if (OC_INVALID_SOCKET == fd)
791     {
792         OIC_LOG_V(ERROR, TAG, "create socket failed: %s", CAIPS_GET_ERROR);
793         return OC_INVALID_SOCKET;
794     }
795
796 #if !defined(SOCK_CLOEXEC) && defined(FD_CLOEXEC)
797     int fl = fcntl(fd, F_GETFD);
798     if (-1 == fl || -1 == fcntl(fd, F_SETFD, fl|FD_CLOEXEC))
799     {
800         OIC_LOG_V(ERROR, TAG, "set FD_CLOEXEC failed: %s", strerror(errno));
801         close(fd);
802         return OC_INVALID_SOCKET;
803     }
804 #endif
805     struct sockaddr_storage sa = { .ss_family = family };
806     socklen_t socklen = 0;
807
808     if (family == AF_INET6)
809     {
810         int on = 1;
811
812         if (OC_SOCKET_ERROR == setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, OPTVAL_T(&on), sizeof (on)))
813         {
814             OIC_LOG_V(ERROR, TAG, "IPV6_V6ONLY failed: %s", CAIPS_GET_ERROR);
815         }
816
817         if (isMulticast && *port) // only do this for multicast ports
818         {
819 #if defined(IPV6_RECVPKTINFO)
820             if (OC_SOCKET_ERROR == setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof (on)))
821 #else
822             if (OC_SOCKET_ERROR == setsockopt(fd, IPPROTO_IPV6, IPV6_PKTINFO, OPTVAL_T(&on), sizeof (on)))
823 #endif
824             {
825                 OIC_LOG_V(ERROR, TAG, "IPV6_RECVPKTINFO failed: %s",CAIPS_GET_ERROR);
826             }
827         }
828
829         ((struct sockaddr_in6 *)&sa)->sin6_port = htons(*port);
830         socklen = sizeof (struct sockaddr_in6);
831     }
832     else
833     {
834         if (isMulticast && *port) // only do this for multicast ports
835         {
836             int on = 1;
837             if (OC_SOCKET_ERROR == setsockopt(fd, IPPROTO_IP, IP_PKTINFO, OPTVAL_T(&on), sizeof (on)))
838             {
839                 OIC_LOG_V(ERROR, TAG, "IP_PKTINFO failed: %s", CAIPS_GET_ERROR);
840             }
841         }
842
843         ((struct sockaddr_in *)&sa)->sin_port = htons(*port);
844         socklen = sizeof (struct sockaddr_in);
845     }
846
847     if (isMulticast && *port) // use the given port
848     {
849         int on = 1;
850         if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, OPTVAL_T(&on), sizeof (on)))
851         {
852             OIC_LOG_V(ERROR, TAG, "SO_REUSEADDR failed: %s", CAIPS_GET_ERROR);
853 #ifdef _WIN32
854             closesocket(fd);
855 #else
856             close(fd);
857 #endif
858             return OC_INVALID_SOCKET;
859         }
860     }
861
862     if (OC_SOCKET_ERROR == bind(fd, (struct sockaddr *)&sa, socklen))
863     {
864         OIC_LOG_V(ERROR, TAG, "bind socket failed: %s", CAIPS_GET_ERROR);
865 #ifdef _WIN32
866         closesocket(fd);
867 #else
868         close(fd);
869 #endif
870         return OC_INVALID_SOCKET;
871     }
872
873     if (!*port) // return the assigned port
874     {
875         if (OC_SOCKET_ERROR == getsockname(fd, (struct sockaddr *)&sa, &socklen))
876         {
877             OIC_LOG_V(ERROR, TAG, "getsockname failed: %s", CAIPS_GET_ERROR);
878 #ifdef _WIN32
879             closesocket(fd);
880 #else
881             close(fd);
882 #endif
883             return OC_INVALID_SOCKET;
884         }
885         *port = ntohs(family == AF_INET6 ?
886                       ((struct sockaddr_in6 *)&sa)->sin6_port :
887                       ((struct sockaddr_in *)&sa)->sin_port);
888     }
889
890     return fd;
891 }
892
893 #define CHECKFD(FD) \
894     if (FD > caglobals.ip.maxfd) \
895         caglobals.ip.maxfd = FD;
896 #define NEWSOCKET(FAMILY, NAME, MULTICAST) \
897     if (caglobals.ip.NAME.fd == OC_INVALID_SOCKET) \
898     {   \
899         caglobals.ip.NAME.fd = CACreateSocket(FAMILY, &caglobals.ip.NAME.port, MULTICAST); \
900         if (caglobals.ip.NAME.fd == OC_INVALID_SOCKET) \
901         {   \
902             caglobals.ip.NAME.port = 0; \
903             caglobals.ip.NAME.fd = CACreateSocket(FAMILY, &caglobals.ip.NAME.port, MULTICAST); \
904         }   \
905         CHECKFD(caglobals.ip.NAME.fd)   \
906     }   \
907
908 void CreateMulticastSocket()
909 {
910     OIC_LOG_V(INFO, TAG, "In %s", __func__);
911
912     if (caglobals.ip.ipv6enabled)
913     {
914         NEWSOCKET(AF_INET6, u6, false)
915         NEWSOCKET(AF_INET6, u6s, false)
916         NEWSOCKET(AF_INET6, m6, true)
917         NEWSOCKET(AF_INET6, m6s, true)
918         OIC_LOG_V(INFO, TAG, "IPv6 unicast port: %u", caglobals.ip.u6.port);
919     }
920     if (caglobals.ip.ipv4enabled)
921     {
922         NEWSOCKET(AF_INET, u4, false)
923         NEWSOCKET(AF_INET, u4s, false)
924         NEWSOCKET(AF_INET, m4, true)
925         NEWSOCKET(AF_INET, m4s, true)
926         OIC_LOG_V(INFO, TAG, "IPv4 unicast port: %u", caglobals.ip.u4.port);
927     }
928
929     OIC_LOG_V(INFO, TAG, "Out %s", __func__);
930 }
931
932 void CloseMulticastSocket()
933 {
934     OIC_LOG_V(INFO, TAG, "In %s", __func__);
935
936     CLOSE_SOCKET(u6);
937     CLOSE_SOCKET(u6s);
938     CLOSE_SOCKET(u4);
939     CLOSE_SOCKET(u4s);
940     CLOSE_SOCKET(m6);
941     CLOSE_SOCKET(m6s);
942     CLOSE_SOCKET(m4);
943     CLOSE_SOCKET(m4s);
944
945     OIC_LOG_V(INFO, TAG, "Out %s", __func__);
946 }
947
948 static void CAInitializeNetlink()
949 {
950     caglobals.ip.netlinkFd = OC_INVALID_SOCKET;
951 #ifdef __linux__
952     // create NETLINK fd for interface change notifications
953     struct sockaddr_nl sa = { AF_NETLINK, 0, 0,
954                               RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR };
955
956     caglobals.ip.netlinkFd = socket(AF_NETLINK, SOCK_RAW|SOCK_CLOEXEC, NETLINK_ROUTE);
957     if (caglobals.ip.netlinkFd == OC_INVALID_SOCKET)
958     {
959         OIC_LOG_V(ERROR, TAG, "netlink socket failed: %s", strerror(errno));
960     }
961     else
962     {
963         int r = bind(caglobals.ip.netlinkFd, (struct sockaddr *)&sa, sizeof (sa));
964         if (r)
965         {
966             OIC_LOG_V(ERROR, TAG, "netlink bind failed: %s", strerror(errno));
967             close(caglobals.ip.netlinkFd);
968             caglobals.ip.netlinkFd = OC_INVALID_SOCKET;
969         }
970         else
971         {
972             CHECKFD(caglobals.ip.netlinkFd);
973         }
974     }
975 #elif defined (__TIZENRT__) // pkmsgq
976         struct mq_attr lq_attr;
977         lq_attr.mq_maxmsg = 10;
978         lq_attr.mq_msgsize = 4;
979         lq_attr.mq_flags = 0;
980         g_nwevent_mqfd = mq_open("netlink_evtq", O_RDWR | O_NONBLOCK | O_CREAT, 0666, &lq_attr);
981         if (g_nwevent_mqfd == (mqd_t) - 1)
982         {
983                 OIC_LOG_V(ERROR, TAG,"RECV mq_open failed\n");
984                 return ;
985         }
986 #endif
987 }
988
989 static void CAInitializeFastShutdownMechanism()
990 {
991     caglobals.ip.selectTimeout = -1; // don't poll for shutdown
992     int ret = -1;
993 #if defined(WSA_WAIT_EVENT_0)
994     caglobals.ip.shutdownEvent = WSACreateEvent();
995     if (WSA_INVALID_EVENT != caglobals.ip.shutdownEvent)
996     {
997         ret = 0;
998     }
999 #elif defined(HAVE_PIPE2)
1000 #ifndef __TIZENRT__
1001     ret = pipe2(caglobals.ip.shutdownFds, O_CLOEXEC);
1002     CHECKFD(caglobals.ip.shutdownFds[0]);
1003     CHECKFD(caglobals.ip.shutdownFds[1]);
1004 #endif
1005 #else
1006 #ifndef __TIZENRT__
1007     ret = pipe(caglobals.ip.shutdownFds);
1008     if (-1 != ret)
1009     {
1010         ret = fcntl(caglobals.ip.shutdownFds[0], F_GETFD);
1011         if (-1 != ret)
1012         {
1013             ret = fcntl(caglobals.ip.shutdownFds[0], F_SETFD, ret|FD_CLOEXEC);
1014         }
1015         if (-1 != ret)
1016         {
1017             ret = fcntl(caglobals.ip.shutdownFds[1], F_GETFD);
1018         }
1019         if (-1 != ret)
1020         {
1021             ret = fcntl(caglobals.ip.shutdownFds[1], F_SETFD, ret|FD_CLOEXEC);
1022         }
1023         if (-1 == ret)
1024         {
1025             close(caglobals.ip.shutdownFds[1]);
1026             close(caglobals.ip.shutdownFds[0]);
1027             caglobals.ip.shutdownFds[0] = -1;
1028             caglobals.ip.shutdownFds[1] = -1;
1029         }
1030     }
1031     CHECKFD(caglobals.ip.shutdownFds[0]);
1032     CHECKFD(caglobals.ip.shutdownFds[1]);
1033 #endif
1034 #endif
1035     if (-1 == ret)
1036     {
1037         OIC_LOG_V(ERROR, TAG, "fast shutdown mechanism init failed: %s", CAIPS_GET_ERROR);
1038         caglobals.ip.selectTimeout = SELECT_TIMEOUT; //poll needed for shutdown
1039     }
1040 }
1041
1042 CAResult_t CAIPStartServer(const ca_thread_pool_t threadPool)
1043 {
1044     CAResult_t res = CA_STATUS_OK;
1045
1046     if (caglobals.ip.started)
1047     {
1048         return res;
1049     }
1050 #if defined (_WIN32)
1051     WORD wVersionRequested = MAKEWORD(2, 2);
1052     WSADATA wsaData ={.wVersion = 0};
1053     int err = WSAStartup(wVersionRequested, &wsaData);
1054     if (err != 0)
1055     {
1056         OIC_LOG_V(ERROR, TAG, "WSAStartup failed: %i", err);
1057         return CA_STATUS_FAILED;
1058     }
1059     OIC_LOG(DEBUG, TAG, "WSAStartup Succeeded");
1060 #endif
1061     if (!IPv4MulticastAddress.s_addr)
1062     {
1063         (void)inet_pton(AF_INET, IPv4_MULTICAST, &IPv4MulticastAddress);
1064         (void)inet_pton(AF_INET6, IPv6_MULTICAST_INT, &IPv6MulticastAddressInt);
1065         (void)inet_pton(AF_INET6, IPv6_MULTICAST_LNK, &IPv6MulticastAddressLnk);
1066         (void)inet_pton(AF_INET6, IPv6_MULTICAST_RLM, &IPv6MulticastAddressRlm);
1067         (void)inet_pton(AF_INET6, IPv6_MULTICAST_ADM, &IPv6MulticastAddressAdm);
1068         (void)inet_pton(AF_INET6, IPv6_MULTICAST_SIT, &IPv6MulticastAddressSit);
1069         (void)inet_pton(AF_INET6, IPv6_MULTICAST_ORG, &IPv6MulticastAddressOrg);
1070         (void)inet_pton(AF_INET6, IPv6_MULTICAST_GLB, &IPv6MulticastAddressGlb);
1071     }
1072
1073     if (!caglobals.ip.ipv6enabled && !caglobals.ip.ipv4enabled)
1074     {
1075         caglobals.ip.ipv4enabled = true;  // only needed to run CA tests
1076     }
1077
1078     CreateMulticastSocket();
1079
1080     OIC_LOG_V(INFO, TAG,
1081               "socket summary: u6=%d, u6s=%d, u4=%d, u4s=%d, m6=%d, m6s=%d, m4=%d, m4s=%d",
1082               caglobals.ip.u6.fd, caglobals.ip.u6s.fd, caglobals.ip.u4.fd, caglobals.ip.u4s.fd,
1083               caglobals.ip.m6.fd, caglobals.ip.m6s.fd, caglobals.ip.m4.fd, caglobals.ip.m4s.fd);
1084
1085     OIC_LOG_V(INFO, TAG,
1086               "port summary: u6 port=%d, u6s port=%d, u4 port=%d, u4s port=%d, m6 port=%d,"
1087               "m6s port=%d, m4 port=%d, m4s port=%d",
1088               caglobals.ip.u6.port, caglobals.ip.u6s.port, caglobals.ip.u4.port,
1089               caglobals.ip.u4s.port, caglobals.ip.m6.port, caglobals.ip.m6s.port,
1090               caglobals.ip.m4.port, caglobals.ip.m4s.port);
1091 #if defined (SIO_GET_EXTENSION_FUNCTION_POINTER)
1092     caglobals.ip.wsaRecvMsg = NULL;
1093     GUID GuidWSARecvMsg = WSAID_WSARECVMSG;
1094     DWORD copied = 0;
1095     err = WSAIoctl(caglobals.ip.u4.fd, SIO_GET_EXTENSION_FUNCTION_POINTER, &GuidWSARecvMsg, sizeof(GuidWSARecvMsg), &(caglobals.ip.wsaRecvMsg), sizeof(caglobals.ip.wsaRecvMsg), &copied, 0, 0);
1096     if (0 != err)
1097     {
1098         OIC_LOG_V(ERROR, TAG, "WSAIoctl failed %i", WSAGetLastError());
1099         return CA_STATUS_FAILED;
1100     }
1101 #endif
1102     // set up appropriate FD mechanism for fast shutdown
1103     CAInitializeFastShutdownMechanism();
1104
1105     // create source of network interface change notifications
1106     CAInitializeNetlink();
1107
1108     caglobals.ip.selectTimeout = CAGetPollingInterval(caglobals.ip.selectTimeout);
1109
1110     res = CAIPStartListenServer();
1111     if (CA_STATUS_OK != res)
1112     {
1113         OIC_LOG_V(ERROR, TAG, "Failed to start listening server![%d]", res);
1114         return res;
1115     }
1116
1117     caglobals.ip.terminate = false;
1118 #ifndef __TIZENRT__
1119     res = ca_thread_pool_add_task(threadPool, CAReceiveHandler, NULL, NULL);
1120 #else
1121     res = ca_thread_pool_add_task(threadPool, CAReceiveHandler, NULL, NULL, "IoT_ReceiveHandler",
1122                                   CONFIG_IOTIVITY_RECEIVEHANDLER_PTHREAD_STACKSIZE);
1123 #endif
1124     if (CA_STATUS_OK != res)
1125     {
1126         OIC_LOG(ERROR, TAG, "thread_pool_add_task failed");
1127         CAIPStopServer();
1128         return res;
1129     }
1130     OIC_LOG(INFO, TAG, "CAReceiveHandler thread started successfully.");
1131
1132     caglobals.ip.started = true;
1133     return CA_STATUS_OK;
1134 }
1135
1136 void CAIPStopServer()
1137 {
1138     caglobals.ip.started = false;
1139     caglobals.ip.terminate = true;
1140
1141     CADeInitializeIPGlobals();
1142
1143 #if !defined(WSA_WAIT_EVENT_0)
1144 #ifndef __TIZENRT__
1145     if (caglobals.ip.shutdownFds[1] != -1)
1146     {
1147         close(caglobals.ip.shutdownFds[1]);
1148         // receive thread will stop immediately
1149     }
1150     else
1151     {
1152         // receive thread will stop in SELECT_TIMEOUT seconds.
1153     }
1154 #endif
1155 #else
1156     // receive thread will stop immediately.
1157     if (!WSASetEvent(caglobals.ip.shutdownEvent))
1158     {
1159         OIC_LOG_V(DEBUG, TAG, "set shutdown event failed: %#08X", GetLastError());
1160     }
1161 #endif
1162
1163     OIC_LOG(INFO, TAG, "Adapter terminated successfully");
1164 }
1165
1166 static void applyMulticastToInterface4(uint32_t ifindex)
1167 {
1168     if (!caglobals.ip.ipv4enabled)
1169     {
1170         return;
1171     }
1172
1173 #if defined(USE_IP_MREQN)
1174     struct ip_mreqn mreq = { .imr_multiaddr = IPv4MulticastAddress,
1175                              .imr_address.s_addr = htonl(INADDR_ANY),
1176                              .imr_ifindex = ifindex };
1177 #else
1178     struct ip_mreq mreq  = { .imr_multiaddr.s_addr = IPv4MulticastAddress.s_addr,
1179                              .imr_interface.s_addr = htonl(ifindex) };
1180 #endif
1181
1182     int ret = setsockopt(caglobals.ip.m4.fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, OPTVAL_T(&mreq), sizeof (mreq));
1183     if (OC_SOCKET_ERROR == ret)
1184     {
1185 #if !defined(WSAEINVAL)
1186         if (EADDRINUSE != errno)
1187 #else
1188         if (WSAEINVAL != WSAGetLastError()) // Joining multicast group more than once (IPv4 Flavor)
1189 #endif
1190         {
1191             OIC_LOG_V(ERROR, TAG, "       IPv4 IP_ADD_MEMBERSHIP failed: %s", CAIPS_GET_ERROR);
1192         }
1193     }
1194     ret = setsockopt(caglobals.ip.m4s.fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, OPTVAL_T(&mreq), sizeof (mreq));
1195     if (OC_SOCKET_ERROR == ret)
1196     {
1197 #if !defined(WSAEINVAL)
1198         if (EADDRINUSE != errno)
1199 #else
1200         if (WSAEINVAL != WSAGetLastError()) // Joining multicast group more than once (IPv4 Flavor)
1201 #endif
1202         {
1203             OIC_LOG_V(ERROR, TAG, "SECURE IPv4 IP_ADD_MEMBERSHIP failed: %s", CAIPS_GET_ERROR);
1204         }
1205     }
1206 }
1207
1208 static void applyMulticast6(int fd, struct in6_addr *addr, uint32_t ifindex)
1209 {
1210 #ifndef __TIZENRT__
1211     struct ipv6_mreq mreq = {.ipv6mr_multiaddr = {{{0}}},
1212                              .ipv6mr_interface = ifindex };
1213
1214     // VS2013 has problems with struct copies inside struct initializers, so copy separately.
1215     mreq.ipv6mr_multiaddr = *addr;
1216
1217     int ret = setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, OPTVAL_T(&mreq), sizeof (mreq));
1218     if (OC_SOCKET_ERROR == ret)
1219     {
1220 #if !defined(_WIN32)
1221                 if (EADDRINUSE != errno)
1222 #else
1223                 if (WSAEINVAL != WSAGetLastError()) // Joining multicast group more than once (IPv6 Flavor)
1224 #endif
1225         {
1226             OIC_LOG_V(ERROR, TAG, "IPv6 IPV6_JOIN_GROUP failed: %s", CAIPS_GET_ERROR);
1227         }
1228     }
1229 #endif
1230 }
1231
1232 static void applyMulticastToInterface6(uint32_t ifindex)
1233 {
1234     if (!caglobals.ip.ipv6enabled)
1235     {
1236         return;
1237     }
1238     //applyMulticast6(caglobals.ip.m6.fd, &IPv6MulticastAddressInt, ifindex);
1239     applyMulticast6(caglobals.ip.m6.fd, &IPv6MulticastAddressLnk, ifindex);
1240     applyMulticast6(caglobals.ip.m6.fd, &IPv6MulticastAddressRlm, ifindex);
1241     //applyMulticast6(caglobals.ip.m6.fd, &IPv6MulticastAddressAdm, ifindex);
1242     applyMulticast6(caglobals.ip.m6.fd, &IPv6MulticastAddressSit, ifindex);
1243     //applyMulticast6(caglobals.ip.m6.fd, &IPv6MulticastAddressOrg, ifindex);
1244     //applyMulticast6(caglobals.ip.m6.fd, &IPv6MulticastAddressGlb, ifindex);
1245
1246     //applyMulticast6(caglobals.ip.m6s.fd, &IPv6MulticastAddressInt, ifindex);
1247     applyMulticast6(caglobals.ip.m6s.fd, &IPv6MulticastAddressLnk, ifindex);
1248     applyMulticast6(caglobals.ip.m6s.fd, &IPv6MulticastAddressRlm, ifindex);
1249     //applyMulticast6(caglobals.ip.m6s.fd, &IPv6MulticastAddressAdm, ifindex);
1250     applyMulticast6(caglobals.ip.m6s.fd, &IPv6MulticastAddressSit, ifindex);
1251     //applyMulticast6(caglobals.ip.m6s.fd, &IPv6MulticastAddressOrg, ifindex);
1252     //applyMulticast6(caglobals.ip.m6s.fd, &IPv6MulticastAddressGlb, ifindex);
1253 }
1254
1255 CAResult_t CAIPStartListenServer()
1256 {
1257     u_arraylist_t *iflist = CAIPGetInterfaceInformation(0);
1258     if (!iflist)
1259     {
1260         OIC_LOG_V(ERROR, TAG, "CAIPGetInterfaceInformation() failed: %s", strerror(errno));
1261         return CA_STATUS_FAILED;
1262     }
1263
1264     uint32_t len = u_arraylist_length(iflist);
1265     OIC_LOG_V(DEBUG, TAG, "IP network interfaces found: %d", len);
1266
1267     for (uint32_t i = 0; i < len; i++)
1268     {
1269         CAInterface_t *ifitem = (CAInterface_t *)u_arraylist_get(iflist, i);
1270
1271         if (!ifitem)
1272         {
1273             continue;
1274         }
1275         if ((ifitem->flags & IFF_UP_RUNNING_FLAGS) != IFF_UP_RUNNING_FLAGS)
1276         {
1277             continue;
1278         }
1279         if (ifitem->family == AF_INET)
1280         {
1281             OIC_LOG_V(DEBUG, TAG, "Adding IPv4 interface(%d) to multicast group", ifitem->index);
1282             applyMulticastToInterface4(ifitem->index);
1283         }
1284         if (ifitem->family == AF_INET6)
1285         {
1286             OIC_LOG_V(DEBUG, TAG, "Adding IPv6 interface(%d) to multicast group", ifitem->index);
1287             applyMulticastToInterface6(ifitem->index);
1288         }
1289     }
1290
1291     u_arraylist_destroy(iflist);
1292     return CA_STATUS_OK;
1293 }
1294
1295 CAResult_t CAIPStopListenServer()
1296 {
1297     u_arraylist_t *iflist = CAIPGetInterfaceInformation(0);
1298     if (!iflist)
1299     {
1300         OIC_LOG_V(ERROR, TAG, "Get interface info failed: %s", strerror(errno));
1301         return CA_STATUS_FAILED;
1302     }
1303
1304     uint32_t len = u_arraylist_length(iflist);
1305     OIC_LOG_V(DEBUG, TAG, "IP network interfaces found: %d", len);
1306
1307     for (uint32_t i = 0; i < len; i++)
1308     {
1309         CAInterface_t *ifitem = (CAInterface_t *)u_arraylist_get(iflist, i);
1310
1311         if (!ifitem)
1312         {
1313             continue;
1314         }
1315         if ((ifitem->flags & IFF_UP_RUNNING_FLAGS) != IFF_UP_RUNNING_FLAGS)
1316         {
1317             continue;
1318         }
1319         if (ifitem->family == AF_INET)
1320         {
1321             CLOSE_SOCKET(m4);
1322             CLOSE_SOCKET(m4s);
1323             OIC_LOG_V(DEBUG, TAG, "IPv4 network interface: %s cloed", ifitem->name);
1324         }
1325         if (ifitem->family == AF_INET6)
1326         {
1327             CLOSE_SOCKET(m6);
1328             CLOSE_SOCKET(m6s);
1329             OIC_LOG_V(DEBUG, TAG, "IPv6 network interface: %s", ifitem->name);
1330         }
1331     }
1332     u_arraylist_destroy(iflist);
1333     return CA_STATUS_OK;
1334 }
1335
1336 void CAProcessNewInterface(CAInterface_t *ifitem)
1337 {
1338     if (!ifitem)
1339     {
1340         OIC_LOG(DEBUG, TAG, "ifitem is null");
1341         return;
1342     }
1343
1344     if (ifitem->family == AF_INET6)
1345     {
1346         OIC_LOG_V(DEBUG, TAG, "Adding a new IPv6 interface(%d) to multicast group", ifitem->index);
1347         applyMulticastToInterface6(ifitem->index);
1348     }
1349     if (ifitem->family == AF_INET)
1350     {
1351         OIC_LOG_V(DEBUG, TAG, "Adding a new IPv4 interface(%d) to multicast group", ifitem->index);
1352         applyMulticastToInterface4(ifitem->index);
1353     }
1354 }
1355
1356 void CAIPSetPacketReceiveCallback(CAIPPacketReceivedCallback callback)
1357 {
1358     g_packetReceivedCallback = callback;
1359 }
1360
1361 static void sendData(int fd, const CAEndpoint_t *endpoint,
1362                      const void *data, uint32_t dlen,
1363                      const char *cast, const char *fam)
1364 {
1365     OIC_LOG(DEBUG, TAG, "IN");
1366
1367     if (!endpoint)
1368     {
1369         OIC_LOG(DEBUG, TAG, "endpoint is null");
1370         if (g_ipErrorHandler)
1371         {
1372             g_ipErrorHandler(endpoint, data, dlen, CA_STATUS_INVALID_PARAM);
1373         }
1374         return;
1375     }
1376
1377     (void)cast;  // eliminates release warning
1378     (void)fam;
1379
1380     struct sockaddr_storage sock = { .ss_family = 0 };
1381     CAConvertNameToAddr(endpoint->addr, endpoint->port, &sock);
1382
1383     socklen_t socklen = 0;
1384     if (sock.ss_family == AF_INET6)
1385     {
1386         /** @todo figure out correct usage for ifindex, and sin6_scope_id */
1387         socklen = sizeof(struct sockaddr_in6);
1388     }
1389     else
1390     {
1391         socklen = sizeof(struct sockaddr_in);
1392     }
1393
1394 #ifdef TB_LOG
1395     const char *secure = (endpoint->flags & CA_SECURE) ? "secure " : "";
1396 #endif
1397 #if !defined(_WIN32)
1398     ssize_t len = sendto(fd, data, dlen, 0, (struct sockaddr *)&sock, socklen);
1399     if (OC_SOCKET_ERROR == len)
1400     {
1401          // If logging is not defined/enabled.
1402         if (g_ipErrorHandler)
1403         {
1404             g_ipErrorHandler(endpoint, data, dlen, CA_SEND_FAILED);
1405         }
1406         OIC_LOG_V(ERROR, TAG, "%s%s %s sendTo failed: %s", secure, cast, fam, strerror(errno));
1407         CALogSendStateInfo(endpoint->adapter, endpoint->addr, endpoint->port,
1408                            len, false, strerror(errno));
1409     }
1410     else
1411     {
1412         OIC_LOG_V(INFO, TAG, "%s%s %s sendTo is successful: %zd bytes", secure, cast, fam, len);
1413         CALogSendStateInfo(endpoint->adapter, endpoint->addr, endpoint->port,
1414                            len, true, NULL);
1415     }
1416 #else
1417     int err = 0;
1418     int len = 0;
1419     int sent = 0;
1420     do {
1421         len = sendto(fd, ((char*)data) + sent, dlen - sent, 0, (struct sockaddr *)&sock, socklen);
1422         if (OC_SOCKET_ERROR == len)
1423         {
1424             err = WSAGetLastError();
1425             if ((WSAEWOULDBLOCK != err) && (WSAENOBUFS != err))
1426             {
1427                  // If logging is not defined/enabled.
1428                 if (g_ipErrorHandler)
1429                 {
1430                     g_ipErrorHandler(endpoint, data, dlen, CA_SEND_FAILED);
1431                 }
1432
1433                 OIC_LOG_V(ERROR, TAG, "%s%s %s sendTo failed: %i", secure, cast, fam, err);
1434             }
1435         }
1436         else
1437         {
1438             sent += len;
1439             if (sent != len)
1440             {
1441                 OIC_LOG_V(INFO, TAG, "%s%s %s sendTo (Partial Send) is successful: "
1442                           "currently sent: %ld bytes, "
1443                           "total sent: %ld bytes, "
1444                           "remaining: %ld bytes",
1445                           secure, cast, fam, len, sent, dlen-sent);
1446             }
1447             else
1448             {
1449                 OIC_LOG_V(INFO, TAG, "%s%s %s sendTo is successful: %ld bytes",
1450                                      secure, cast, fam, len);
1451             }
1452         }
1453     } while ((OC_SOCKET_ERROR == len) && ((WSAEWOULDBLOCK == err) || (WSAENOBUFS == err)) || (sent < dlen));
1454 #endif
1455 }
1456
1457 static void sendMulticastData6(const u_arraylist_t *iflist,
1458                                CAEndpoint_t *endpoint,
1459                                const void *data, uint32_t datalen)
1460 {
1461     if (!endpoint)
1462     {
1463         OIC_LOG(DEBUG, TAG, "endpoint is null");
1464         return;
1465     }
1466
1467     int scope = endpoint->flags & CA_SCOPE_MASK;
1468     char *ipv6mcname = ipv6mcnames[scope];
1469     if (!ipv6mcname)
1470     {
1471         OIC_LOG_V(INFO, TAG, "IPv6 multicast scope invalid: %d", scope);
1472         return;
1473     }
1474     OICStrcpy(endpoint->addr, sizeof(endpoint->addr), ipv6mcname);
1475     int fd = caglobals.ip.u6.fd;
1476
1477     uint32_t len = u_arraylist_length(iflist);
1478     for (uint32_t i = 0; i < len; i++)
1479     {
1480         CAInterface_t *ifitem = (CAInterface_t *)u_arraylist_get(iflist, i);
1481         if (!ifitem)
1482         {
1483             continue;
1484         }
1485         if ((ifitem->flags & IFF_UP_RUNNING_FLAGS) != IFF_UP_RUNNING_FLAGS)
1486         {
1487             continue;
1488         }
1489         if (ifitem->family != AF_INET6)
1490         {
1491             continue;
1492         }
1493
1494         bool isMobile = false;
1495         for (uint32_t j = 0; j < MOBILE_INTERFACES; j++)
1496         {
1497             if (strstr(ifitem->name, mobileinferfaces[j]))
1498             {
1499                 isMobile = true;
1500                 break;
1501             }
1502         }
1503         if (isMobile)
1504         {
1505             continue;
1506         }
1507
1508         int index = ifitem->index;
1509         if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, OPTVAL_T(&index), sizeof (index)))
1510         {
1511             OIC_LOG_V(ERROR, TAG, "setsockopt6 failed: %s", CAIPS_GET_ERROR);
1512             return;
1513         }
1514
1515 #ifndef __TIZENRT__
1516         // Set multicast packet TTL; default TTL is 1
1517         if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &multicastTTL, sizeof(multicastTTL)))
1518         {
1519             OIC_LOG_V(ERROR, TAG, "IPV6_MULTICAST_HOPS failed: %s", CAIPS_GET_ERROR);
1520         }
1521 #endif
1522         sendData(fd, endpoint, data, datalen, "multicast", "ipv6");
1523     }
1524 }
1525
1526 static void sendMulticastData4(const u_arraylist_t *iflist,
1527                                CAEndpoint_t *endpoint,
1528                                const void *data, uint32_t datalen)
1529 {
1530     VERIFY_NON_NULL_VOID(endpoint, TAG, "endpoint is NULL");
1531
1532 #if defined(USE_IP_MREQN)
1533     struct ip_mreqn mreq = { .imr_multiaddr = IPv4MulticastAddress,
1534                              .imr_address.s_addr = htonl(INADDR_ANY),
1535                              .imr_ifindex = 0};
1536 #else
1537     struct ip_mreq mreq  = { .imr_multiaddr.s_addr = IPv4MulticastAddress.s_addr,
1538                              .imr_interface = {0}};
1539 #endif
1540
1541     OICStrcpy(endpoint->addr, sizeof(endpoint->addr), IPv4_MULTICAST);
1542     int fd = caglobals.ip.u4.fd;
1543
1544     uint32_t len = u_arraylist_length(iflist);
1545     for (uint32_t i = 0; i < len; i++)
1546     {
1547         CAInterface_t *ifitem = (CAInterface_t *)u_arraylist_get(iflist, i);
1548         if (!ifitem)
1549         {
1550             continue;
1551         }
1552         if ((ifitem->flags & IFF_UP_RUNNING_FLAGS) != IFF_UP_RUNNING_FLAGS)
1553         {
1554             continue;
1555         }
1556         if (ifitem->family != AF_INET)
1557         {
1558             continue;
1559         }
1560
1561         bool isMobile = false;
1562         for (uint32_t j = 0; j < MOBILE_INTERFACES; j++)
1563         {
1564             if (strstr(ifitem->name, mobileinferfaces[j]))
1565             {
1566                 isMobile = true;
1567                 break;
1568             }
1569         }
1570         if (isMobile)
1571         {
1572             continue;
1573         }
1574
1575 #if defined(USE_IP_MREQN)
1576         mreq.imr_ifindex = ifitem->index;
1577 #else
1578         mreq.imr_interface.s_addr = htonl(ifitem->index);
1579 #endif
1580         if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, OPTVAL_T(&mreq), sizeof (mreq)))
1581         {
1582             OIC_LOG_V(ERROR, TAG, "send IP_MULTICAST_IF failed: %s (using defualt)",
1583                     CAIPS_GET_ERROR);
1584         }
1585
1586         // Set multicast packet TTL; default TTL is 1
1587         if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, &multicastTTL, sizeof(multicastTTL)))
1588         {
1589             OIC_LOG_V(ERROR, TAG, "IP_MULTICAST_TTL failed: %s", CAIPS_GET_ERROR);
1590         }
1591         sendData(fd, endpoint, data, datalen, "multicast", "ipv4");
1592     }
1593 }
1594
1595 void CAIPSendData(CAEndpoint_t *endpoint, const void *data, uint32_t datalen,
1596                   bool isMulticast)
1597 {
1598     VERIFY_NON_NULL_VOID(endpoint, TAG, "endpoint is NULL");
1599     VERIFY_NON_NULL_VOID(data, TAG, "data is NULL");
1600
1601     bool isSecure = (endpoint->flags & CA_SECURE) != 0;
1602
1603     if (isMulticast)
1604     {
1605         endpoint->port = isSecure ? CA_SECURE_COAP : CA_COAP;
1606
1607         u_arraylist_t *iflist = CAIPGetInterfaceInformation(0);
1608         if (!iflist)
1609         {
1610             OIC_LOG_V(ERROR, TAG, "get interface info failed: %s", strerror(errno));
1611             return;
1612         }
1613
1614         if ((endpoint->flags & CA_IPV6) && caglobals.ip.ipv6enabled)
1615         {
1616             sendMulticastData6(iflist, endpoint, data, datalen);
1617         }
1618         if ((endpoint->flags & CA_IPV4) && caglobals.ip.ipv4enabled)
1619         {
1620             sendMulticastData4(iflist, endpoint, data, datalen);
1621         }
1622
1623         u_arraylist_destroy(iflist);
1624     }
1625     else
1626     {
1627         if (!endpoint->port)    // unicast discovery
1628         {
1629             endpoint->port = isSecure ? CA_SECURE_COAP : CA_COAP;
1630         }
1631
1632         CASocketFd_t fd;
1633         if (caglobals.ip.ipv6enabled && (endpoint->flags & CA_IPV6))
1634         {
1635             fd = isSecure ? caglobals.ip.u6s.fd : caglobals.ip.u6.fd;
1636 #ifndef __WITH_DTLS__
1637             fd = caglobals.ip.u6.fd;
1638 #endif
1639             sendData(fd, endpoint, data, datalen, "unicast", "ipv6");
1640         }
1641         if (caglobals.ip.ipv4enabled && (endpoint->flags & CA_IPV4))
1642         {
1643             fd = isSecure ? caglobals.ip.u4s.fd : caglobals.ip.u4.fd;
1644 #ifndef __WITH_DTLS__
1645             fd = caglobals.ip.u4.fd;
1646 #endif
1647             sendData(fd, endpoint, data, datalen, "unicast", "ipv4");
1648         }
1649     }
1650 }
1651
1652 CAResult_t CAGetIPInterfaceInformation(CAEndpoint_t **info, uint32_t *size)
1653 {
1654     VERIFY_NON_NULL(info, TAG, "info is NULL");
1655     VERIFY_NON_NULL(size, TAG, "size is NULL");
1656
1657     u_arraylist_t *iflist = CAIPGetInterfaceInformation(0);
1658     if (!iflist)
1659     {
1660         OIC_LOG_V(ERROR, TAG, "get interface info failed: %s", strerror(errno));
1661         return CA_STATUS_FAILED;
1662     }
1663
1664     uint32_t len = u_arraylist_length(iflist);
1665     uint32_t length = len;
1666
1667 #ifdef __WITH_DTLS__
1668     //If DTLS is supported, each interface can support secure port as well
1669     length = len * 2;
1670 #endif
1671
1672     CAEndpoint_t *eps = (CAEndpoint_t *)OICCalloc(length, sizeof (CAEndpoint_t));
1673     if (!eps)
1674     {
1675         OIC_LOG(ERROR, TAG, "Malloc Failed");
1676         u_arraylist_destroy(iflist);
1677         return CA_MEMORY_ALLOC_FAILED;
1678     }
1679
1680     for (uint32_t i = 0, j = 0; i < len; i++)
1681     {
1682         CAInterface_t *ifitem = (CAInterface_t *)u_arraylist_get(iflist, i);
1683         if(!ifitem)
1684         {
1685             continue;
1686         }
1687
1688         eps[j].adapter = CA_ADAPTER_IP;
1689         eps[j].ifindex = 0;
1690
1691         if (ifitem->family == AF_INET6)
1692         {
1693             eps[j].flags = CA_IPV6;
1694             eps[j].port = caglobals.ip.u6.port;
1695         }
1696         else
1697         {
1698             eps[j].flags = CA_IPV4;
1699             eps[j].port = caglobals.ip.u4.port;
1700         }
1701         OICStrcpy(eps[j].addr, sizeof(eps[j].addr), ifitem->addr);
1702
1703 #ifdef __WITH_DTLS__
1704         j++;
1705
1706         eps[j].adapter = CA_ADAPTER_IP;
1707         eps[j].ifindex = 0;
1708
1709         if (ifitem->family == AF_INET6)
1710         {
1711             eps[j].flags = CA_IPV6 | CA_SECURE;
1712             eps[j].port = caglobals.ip.u6s.port;
1713         }
1714         else
1715         {
1716             eps[j].flags = CA_IPV4 | CA_SECURE;
1717             eps[j].port = caglobals.ip.u4s.port;
1718         }
1719         OICStrcpy(eps[j].addr, sizeof(eps[j].addr), ifitem->addr);
1720 #endif
1721         j++;
1722     }
1723
1724     *info = eps;
1725     *size = length;
1726
1727     u_arraylist_destroy(iflist);
1728
1729     return CA_STATUS_OK;
1730 }
1731
1732 void CAIPSetErrorHandler(CAIPErrorHandleCallback errorHandleCallback)
1733 {
1734     g_ipErrorHandler = errorHandleCallback;
1735 }
1736
1737 CAResult_t CAIPSetMulticastTTL(size_t ttl)
1738 {
1739     multicastTTL = ttl;
1740     return CA_STATUS_OK;
1741 }
1742
1743 CAResult_t CAIPGetMulticastTTL(size_t *ttl)
1744 {
1745     VERIFY_NON_NULL(ttl, TAG, "ttl is NULL");
1746
1747     *ttl = multicastTTL;
1748     return CA_STATUS_OK;
1749 }