caipserver.c 51.7 KB
Newer Older
1
/* ****************************************************************
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
 *
 * Copyright 2014 Samsung Electronics All Rights Reserved.
 *
 *
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 ******************************************************************/

Jaewook Jung's avatar
Jaewook Jung committed
21
#ifndef __APPLE_USE_RFC_3542
22
#define __APPLE_USE_RFC_3542 // for PKTINFO
Jaewook Jung's avatar
Jaewook Jung committed
23 24
#endif
#ifndef _GNU_SOURCE
25
#define _GNU_SOURCE // for in6_pktinfo
Jaewook Jung's avatar
Jaewook Jung committed
26
#endif
27

28
#include "iotivity_config.h"
Dan Mihai's avatar
Dan Mihai committed
29 30
#include "iotivity_debug.h"

31
#include <sys/types.h>
Dave Thaler's avatar
Dave Thaler committed
32
#ifdef HAVE_SYS_SOCKET_H
33
#include <sys/socket.h>
34
#endif
Dave Thaler's avatar
Dave Thaler committed
35
#ifdef HAVE_WINSOCK2_H
36
#include <winsock2.h>
Dave Thaler's avatar
Dave Thaler committed
37 38
#endif
#ifdef HAVE_WS2TCPIP_H
39 40
#include <ws2tcpip.h>
#endif
John Light's avatar
John Light committed
41
#include <stdio.h>
Dave Thaler's avatar
Dave Thaler committed
42
#ifdef HAVE_UNISTD_H
43
#include <unistd.h>
Dave Thaler's avatar
Dave Thaler committed
44
#endif
45
#include <fcntl.h>
Dave Thaler's avatar
Dave Thaler committed
46
#ifdef HAVE_SYS_SELECT_H
47
#include <sys/select.h>
Dave Thaler's avatar
Dave Thaler committed
48 49
#endif
#ifdef HAVE_ARPA_INET_H
50
#include <arpa/inet.h>
Dave Thaler's avatar
Dave Thaler committed
51 52
#endif
#ifdef HAVE_NETINET_IN_H
53
#include <netinet/in.h>
Dave Thaler's avatar
Dave Thaler committed
54 55
#endif
#ifdef HAVE_NET_IF_H
John Light's avatar
John Light committed
56
#include <net/if.h>
57
#endif
58
#include <errno.h>
John Light's avatar
John Light committed
59 60 61 62
#ifdef __linux__
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#endif
63

64
#include <coap/pdu.h>
65
#include <inttypes.h>
66
#include "caipinterface.h"
67
#include "caipnwmonitor.h"
68
#include "caadapterutils.h"
69 70
#if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
#include "ca_adapter_net_ssl.h"
71
#endif
72
#include "octhread.h"
73
#include "oic_malloc.h"
74
#include "oic_string.h"
75

76 77 78 79
#define USE_IP_MREQN
#if defined(_WIN32)
#undef USE_IP_MREQN
#endif
80

81 82
/*
 * Logging tag for module name
83
 */
84
#define TAG "OIC_CA_IP_SERVER"
John Light's avatar
John Light committed
85

86 87 88 89 90
/*
 * Enable or disable log for network changed event
 */
#define NETWORK_INTERFACE_CHANGED_LOGGING 1

John Light's avatar
John Light committed
91 92 93 94 95 96
#define SELECT_TIMEOUT 1     // select() seconds (and termination latency)

#define IPv4_MULTICAST     "224.0.1.187"
static struct in_addr IPv4MulticastAddress = { 0 };

#define IPv6_DOMAINS       16
97
#define IPv6_MULTICAST_INT "ff01::158"
John Light's avatar
John Light committed
98
static struct in6_addr IPv6MulticastAddressInt;
99
#define IPv6_MULTICAST_LNK "ff02::158"
John Light's avatar
John Light committed
100
static struct in6_addr IPv6MulticastAddressLnk;
101
#define IPv6_MULTICAST_RLM "ff03::158"
John Light's avatar
John Light committed
102
static struct in6_addr IPv6MulticastAddressRlm;
103
#define IPv6_MULTICAST_ADM "ff04::158"
John Light's avatar
John Light committed
104
static struct in6_addr IPv6MulticastAddressAdm;
105
#define IPv6_MULTICAST_SIT "ff05::158"
John Light's avatar
John Light committed
106
static struct in6_addr IPv6MulticastAddressSit;
107
#define IPv6_MULTICAST_ORG "ff08::158"
John Light's avatar
John Light committed
108
static struct in6_addr IPv6MulticastAddressOrg;
109
#define IPv6_MULTICAST_GLB "ff0e::158"
John Light's avatar
John Light committed
110 111
static struct in6_addr IPv6MulticastAddressGlb;

112 113 114 115 116
/*
 * Buffer size for the receive message buffer
 */
#define RECV_MSG_BUF_LEN 16384

John Light's avatar
John Light committed
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
static char *ipv6mcnames[IPv6_DOMAINS] = {
    NULL,
    IPv6_MULTICAST_INT,
    IPv6_MULTICAST_LNK,
    IPv6_MULTICAST_RLM,
    IPv6_MULTICAST_ADM,
    IPv6_MULTICAST_SIT,
    NULL,
    NULL,
    IPv6_MULTICAST_ORG,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    IPv6_MULTICAST_GLB,
    NULL
};

136 137
#if defined (_WIN32)
#define IFF_UP_RUNNING_FLAGS  (IFF_UP)
John Light's avatar
John Light committed
138

139
    char* caips_get_error(){
140 141 142 143
        static char buffer[32];
        snprintf(buffer, 32, "%i", WSAGetLastError());
        return buffer;
    }
144 145
#define CAIPS_GET_ERROR \
    caips_get_error()
146
#else
147 148 149 150
#define IFF_UP_RUNNING_FLAGS  (IFF_UP|IFF_RUNNING)

#define CAIPS_GET_ERROR \
    strerror(errno)
151
#endif
152
static CAIPErrorHandleCallback g_ipErrorHandler = NULL;
John Light's avatar
John Light committed
153

154
static CAIPPacketReceivedCallback g_packetReceivedCallback = NULL;
John Light's avatar
John Light committed
155

156 157 158 159 160 161 162
static oc_mutex g_mutex = NULL;
static oc_cond g_condVar = NULL;

static CAResult_t CAIPCreateMutex(void);
static void CAIPDestroyMutex(void);
static CAResult_t CAIPCreateCond(void);
static void CAIPDestroyCond(void);
163
static void CAFindReadyMessage(void);
164
#if !defined(WSA_WAIT_EVENT_0)
John Light's avatar
John Light committed
165
static void CASelectReturned(fd_set *readFds, int ret);
166
#else
167
static void CAEventReturned(CASocketFd_t socket);
168
#endif
169

170
static CAResult_t CAReceiveMessage(CASocketFd_t fd, CATransportFlags_t flags);
John Light's avatar
John Light committed
171

172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
static CAResult_t CAIPCreateMutex(void)
{
    if (!g_mutex)
    {
        if (NULL == (g_mutex = oc_mutex_new()))
        {
            OIC_LOG(ERROR, TAG, "Failed to created mutex!");
            return CA_STATUS_FAILED;
        }
    }
    return CA_STATUS_OK;
}
static void CAIPDestroyMutex(void)
{
    if (g_mutex)
    {
        oc_mutex_free(g_mutex);
        g_mutex = NULL;
    }
}
static CAResult_t CAIPCreateCond(void)
{
    if (!g_condVar)
    {
        if (NULL == (g_condVar = oc_cond_new()))
        {
            OIC_LOG(ERROR, TAG, "Failed to created cond!");
            return CA_STATUS_FAILED;
        }
    }
    return CA_STATUS_OK;
}
static void CAIPDestroyCond(void)
{
    if (g_condVar)
    {
        oc_cond_free(g_condVar);
        g_condVar = NULL;
    }
}

213
static void CACloseFDs(void)
214 215 216 217 218 219 220 221 222 223 224
{
#if !defined(WSA_WAIT_EVENT_0)
    if (caglobals.ip.shutdownFds[0] != -1)
    {
        close(caglobals.ip.shutdownFds[0]);
        caglobals.ip.shutdownFds[0] = -1;
    }
#endif
    CADeInitializeIPGlobals();
}

225 226 227
static void CAReceiveHandler(void *data)
{
    (void)data;
John Light's avatar
John Light committed
228

229 230 231
    while (!caglobals.ip.terminate)
    {
        CAFindReadyMessage();
John Light's avatar
John Light committed
232
    }
233
    CACloseFDs();
234 235 236 237

    oc_mutex_lock(g_mutex);
    oc_cond_signal(g_condVar);
    oc_mutex_unlock(g_mutex);
238 239
}

240
#define CLOSE_SOCKET(TYPE) \
241
    if (caglobals.ip.TYPE.fd != OC_INVALID_SOCKET) \
242
    { \
Dave Thaler's avatar
Dave Thaler committed
243
        OC_CLOSE_SOCKET(caglobals.ip.TYPE.fd); \
244
        caglobals.ip.TYPE.fd = OC_INVALID_SOCKET; \
245 246
    }

Dave Thaler's avatar
Dave Thaler committed
247 248
#if !defined(WSA_WAIT_EVENT_0)

249
#define SET(TYPE, FDS) \
250
    if (caglobals.ip.TYPE.fd != OC_INVALID_SOCKET) \
251 252
    { \
        FD_SET(caglobals.ip.TYPE.fd, FDS); \
253
    }
hyuna0213.jo's avatar
hyuna0213.jo committed
254

255
#define ISSET(TYPE, FDS, FLAGS) \
256
    if (caglobals.ip.TYPE.fd != OC_INVALID_SOCKET && FD_ISSET(caglobals.ip.TYPE.fd, FDS)) \
257 258 259
    { \
        fd = caglobals.ip.TYPE.fd; \
        flags = FLAGS; \
John Light's avatar
John Light committed
260
    }
261

262

263
static void CAFindReadyMessage(void)
264 265 266 267
{
    fd_set readFds;
    struct timeval timeout;

John Light's avatar
John Light committed
268 269 270 271 272 273 274 275 276 277 278 279 280
    timeout.tv_sec = caglobals.ip.selectTimeout;
    timeout.tv_usec = 0;
    struct timeval *tv = caglobals.ip.selectTimeout == -1 ? NULL : &timeout;

    FD_ZERO(&readFds);
    SET(u6,  &readFds)
    SET(u6s, &readFds)
    SET(u4,  &readFds)
    SET(u4s, &readFds)
    SET(m6,  &readFds)
    SET(m6s, &readFds)
    SET(m4,  &readFds)
    SET(m4s, &readFds)
281

John Light's avatar
John Light committed
282
    if (caglobals.ip.shutdownFds[0] != -1)
283
    {
John Light's avatar
John Light committed
284 285
        FD_SET(caglobals.ip.shutdownFds[0], &readFds);
    }
286
    if (caglobals.ip.netlinkFd != OC_INVALID_SOCKET)
John Light's avatar
John Light committed
287 288 289
    {
        FD_SET(caglobals.ip.netlinkFd, &readFds);
    }
290

John Light's avatar
John Light committed
291
    int ret = select(caglobals.ip.maxfd + 1, &readFds, NULL, NULL, tv);
292

John Light's avatar
John Light committed
293 294 295 296 297
    if (caglobals.ip.terminate)
    {
        OIC_LOG_V(DEBUG, TAG, "Packet receiver Stop request received.");
        return;
    }
298

299
    if (0 == ret)
John Light's avatar
John Light committed
300 301 302
    {
        return;
    }
303 304 305 306 307 308 309 310 311
    else if (0 < ret)
    {
        CASelectReturned(&readFds, ret);
    }
    else // if (0 > ret)
    {
        OIC_LOG_V(FATAL, TAG, "select error %s", CAIPS_GET_ERROR);
        return;
    }
John Light's avatar
John Light committed
312
}
313

John Light's avatar
John Light committed
314 315
static void CASelectReturned(fd_set *readFds, int ret)
{
316
    (void)ret;
317
    CASocketFd_t fd = OC_INVALID_SOCKET;
John Light's avatar
John Light committed
318 319 320 321 322 323 324 325 326 327 328 329
    CATransportFlags_t flags = CA_DEFAULT_FLAGS;

    while (!caglobals.ip.terminate)
    {
        ISSET(u6,  readFds, CA_IPV6)
        else ISSET(u6s, readFds, CA_IPV6 | CA_SECURE)
        else ISSET(u4,  readFds, CA_IPV4)
        else ISSET(u4s, readFds, CA_IPV4 | CA_SECURE)
        else ISSET(m6,  readFds, CA_MULTICAST | CA_IPV6)
        else ISSET(m6s, readFds, CA_MULTICAST | CA_IPV6 | CA_SECURE)
        else ISSET(m4,  readFds, CA_MULTICAST | CA_IPV4)
        else ISSET(m4s, readFds, CA_MULTICAST | CA_IPV4 | CA_SECURE)
330
        else if ((caglobals.ip.netlinkFd != OC_INVALID_SOCKET) && FD_ISSET(caglobals.ip.netlinkFd, readFds))
John Light's avatar
John Light committed
331
        {
332
#if NETWORK_INTERFACE_CHANGED_LOGGING
333
            OIC_LOG_V(DEBUG, TAG, "Netlink event detected");
334
#endif
335 336
            u_arraylist_t *iflist = CAFindInterfaceChange();
            if (iflist)
337
            {
338 339
                size_t listLength = u_arraylist_length(iflist);
                for (size_t i = 0; i < listLength; i++)
340 341 342 343 344 345 346 347
                {
                    CAInterface_t *ifitem = (CAInterface_t *)u_arraylist_get(iflist, i);
                    if (ifitem)
                    {
                        CAProcessNewInterface(ifitem);
                    }
                }
                u_arraylist_destroy(iflist);
348
            }
John Light's avatar
John Light committed
349 350
            break;
        }
Tim Kourt's avatar
Tim Kourt committed
351
        else if (FD_ISSET(caglobals.ip.shutdownFds[0], readFds))
John Light's avatar
John Light committed
352
        {
Tim Kourt's avatar
Tim Kourt committed
353
            char buf[10] = {0};
hyuna0213.jo's avatar
hyuna0213.jo committed
354 355 356 357 358
            ssize_t len = read(caglobals.ip.shutdownFds[0], buf, sizeof (buf));
            if (-1 == len)
            {
                continue;
            }
John Light's avatar
John Light committed
359 360
            break;
        }
Tim Kourt's avatar
Tim Kourt committed
361 362 363 364
        else
        {
            break;
        }
John Light's avatar
John Light committed
365 366 367 368
        (void)CAReceiveMessage(fd, flags);
        FD_CLR(fd, readFds);
    }
}
369

370 371 372 373 374 375 376 377
#else // if defined(WSA_WAIT_EVENT_0)

#define PUSH_HANDLE(HANDLE, ARRAY, INDEX) \
{ \
    ARRAY[INDEX] = HANDLE; \
    INDEX++; \
}

Dan Mihai's avatar
Dan Mihai committed
378
// Create WSAEvent for SOCKET and push the new event into ARRAY
379
#define PUSH_SOCKET(SOCKET, ARRAY, INDEX) \
380
    if (SOCKET != OC_INVALID_SOCKET) \
381
    { \
Dan Mihai's avatar
Dan Mihai committed
382
        WSAEVENT NewEvent = WSACreateEvent(); \
383 384 385 386
        if (WSA_INVALID_EVENT != NewEvent) \
        { \
            if (0 != WSAEventSelect(SOCKET, NewEvent, FD_READ)) \
            { \
Dan Mihai's avatar
Dan Mihai committed
387 388 389 390
                OIC_LOG_V(ERROR, TAG, "WSAEventSelect failed %d", WSAGetLastError()); \
                BOOL closed = WSACloseEvent(NewEvent); \
                assert(closed); \
                if (!closed) \
391
                { \
Dan Mihai's avatar
Dan Mihai committed
392
                    OIC_LOG_V(ERROR, TAG, "WSACloseEvent(NewEvent) failed %d", WSAGetLastError()); \
393 394 395 396 397 398 399 400 401
                } \
            } \
            else \
            { \
                PUSH_HANDLE(NewEvent, ARRAY, INDEX); \
            } \
        } \
        else \
        { \
Dan Mihai's avatar
Dan Mihai committed
402
            OIC_LOG_V(ERROR, TAG, "WSACreateEvent failed %d", WSAGetLastError()); \
403 404 405
        }\
    }

406
#define INSERT_SOCKET(FD, ARRAY, INDEX) \
407
    { \
408
        if (OC_INVALID_SOCKET != FD) \
409 410 411 412 413 414
        { \
            ARRAY[INDEX] = FD; \
        } \
    }


415 416
// Inserts the socket into the SOCKET_ARRAY and pushes the socket event into EVENT_ARRAY
#define PUSH_IP_SOCKET(TYPE, EVENT_ARRAY, SOCKET_ARRAY, INDEX) \
417
    { \
418
        if (OC_INVALID_SOCKET != caglobals.ip.TYPE.fd) \
419
        { \
420 421
            INSERT_SOCKET(caglobals.ip.TYPE.fd, SOCKET_ARRAY, INDEX); \
            PUSH_SOCKET(caglobals.ip.TYPE.fd, EVENT_ARRAY, INDEX); \
422 423 424
        } \
    }

425 426
#define IS_MATCHING_IP_SOCKET(TYPE, SOCKET, FLAGS) \
    if ((caglobals.ip.TYPE.fd != OC_INVALID_SOCKET) && (caglobals.ip.TYPE.fd == SOCKET)) \
427 428 429 430 431 432 433
    { \
        fd = caglobals.ip.TYPE.fd; \
        flags = FLAGS; \
    }

#define EVENT_ARRAY_SIZE  10

434
static void CAFindReadyMessage(void)
435
{
436
    CASocketFd_t socketArray[EVENT_ARRAY_SIZE];
437
    HANDLE eventArray[EVENT_ARRAY_SIZE];
438 439
    DWORD arraySize = 0;
    DWORD eventIndex;
440

441 442
    // socketArray and eventArray should have same number of elements
    OC_STATIC_ASSERT(_countof(socketArray) == _countof(eventArray), "Arrays should have same number of elements");
Dan Mihai's avatar
Dan Mihai committed
443
    OC_STATIC_ASSERT(_countof(eventArray) <= WSA_MAXIMUM_WAIT_EVENTS, "Too many events for a single Wait");
444

445 446 447 448 449 450 451 452
    PUSH_IP_SOCKET(u6,  eventArray, socketArray, arraySize);
    PUSH_IP_SOCKET(u6s, eventArray, socketArray, arraySize);
    PUSH_IP_SOCKET(u4,  eventArray, socketArray, arraySize);
    PUSH_IP_SOCKET(u4s, eventArray, socketArray, arraySize);
    PUSH_IP_SOCKET(m6,  eventArray, socketArray, arraySize);
    PUSH_IP_SOCKET(m6s, eventArray, socketArray, arraySize);
    PUSH_IP_SOCKET(m4,  eventArray, socketArray, arraySize);
    PUSH_IP_SOCKET(m4s, eventArray, socketArray, arraySize);
453

Daniel Ferguson's avatar
Daniel Ferguson committed
454
    if (WSA_INVALID_EVENT != caglobals.ip.shutdownEvent)
455
    {
456
        INSERT_SOCKET(OC_INVALID_SOCKET, socketArray, arraySize);
457 458 459
        PUSH_HANDLE(caglobals.ip.shutdownEvent, eventArray, arraySize);
    }

460 461 462 463 464
    if (WSA_INVALID_EVENT != caglobals.ip.addressChangeEvent)
    {
        INSERT_SOCKET(OC_INVALID_SOCKET, socketArray, arraySize);
        PUSH_HANDLE(caglobals.ip.addressChangeEvent, eventArray, arraySize);
    }
465 466

    // Should not have overflowed buffer
467
    assert(arraySize <= (_countof(socketArray)));
468 469 470 471 472 473

    // Timeout is unnecessary on Windows
    assert(-1 == caglobals.ip.selectTimeout);

    while (!caglobals.ip.terminate)
    {
474
        DWORD ret = WSAWaitForMultipleEvents(arraySize, eventArray, FALSE, WSA_INFINITE, FALSE);
Dan Mihai's avatar
Dan Mihai committed
475 476
        assert(ret >= WSA_WAIT_EVENT_0);
        assert(ret < (WSA_WAIT_EVENT_0 + arraySize));
477 478 479 480

        switch (ret)
        {
            case WSA_WAIT_FAILED:
Dan Mihai's avatar
Dan Mihai committed
481
                OIC_LOG_V(ERROR, TAG, "WSAWaitForMultipleEvents returned WSA_WAIT_FAILED %d", WSAGetLastError());
482 483
                break;
            case WSA_WAIT_IO_COMPLETION:
Dan Mihai's avatar
Dan Mihai committed
484
                OIC_LOG_V(ERROR, TAG, "WSAWaitForMultipleEvents returned WSA_WAIT_IO_COMPLETION %d", WSAGetLastError());
485 486
                break;
            case WSA_WAIT_TIMEOUT:
Dan Mihai's avatar
Dan Mihai committed
487
                OIC_LOG_V(ERROR, TAG, "WSAWaitForMultipleEvents returned WSA_WAIT_TIMEOUT %d", WSAGetLastError());
488 489 490 491 492 493 494
                break;
            default:
                eventIndex = ret - WSA_WAIT_EVENT_0;
                if ((eventIndex >= 0) && (eventIndex < arraySize))
                {
                    if (false == WSAResetEvent(eventArray[eventIndex]))
                    {
Dan Mihai's avatar
Dan Mihai committed
495
                        OIC_LOG_V(ERROR, TAG, "WSAResetEvent failed %d", WSAGetLastError());
496
                    }
497

498 499 500 501
                    // Handle address changes if addressChangeEvent is triggered.
                    if ((caglobals.ip.addressChangeEvent != WSA_INVALID_EVENT) &&
                        (caglobals.ip.addressChangeEvent == eventArray[eventIndex]))
                    {
502 503
                        u_arraylist_t *iflist = CAFindInterfaceChange();
                        if (iflist)
504
                        {
505 506
                            size_t listLength = u_arraylist_length(iflist);
                            for (size_t i = 0; i < listLength; i++)
507 508 509 510 511 512 513 514
                            {
                                CAInterface_t *ifitem = (CAInterface_t *)u_arraylist_get(iflist, i);
                                if (ifitem)
                                {
                                    CAProcessNewInterface(ifitem);
                                }
                            }
                            u_arraylist_destroy(iflist);
515 516 517 518 519
                        }
                        break;
                    }

                    // Break out if shutdownEvent is triggered.
Daniel Ferguson's avatar
Daniel Ferguson committed
520
                    if ((caglobals.ip.shutdownEvent != WSA_INVALID_EVENT) &&
521 522 523 524 525
                        (caglobals.ip.shutdownEvent == eventArray[eventIndex]))
                    {
                        break;
                    }
                    CAEventReturned(socketArray[eventIndex]);
526 527 528
                }
                else
                {
Dan Mihai's avatar
Dan Mihai committed
529
                    OIC_LOG_V(ERROR, TAG, "WSAWaitForMultipleEvents failed %d", WSAGetLastError());
530 531 532 533 534 535
                }
                break;
        }

    }

536
    for (size_t i = 0; i < arraySize; i++)
537
    {
Dan Mihai's avatar
Dan Mihai committed
538 539
        HANDLE h = eventArray[i];
        if (h != caglobals.ip.addressChangeEvent)
540
        {
Dan Mihai's avatar
Dan Mihai committed
541 542 543 544 545 546
            BOOL closed = WSACloseEvent(h);
            assert(closed);
            if (!closed)
            {
                OIC_LOG_V(ERROR, TAG, "WSACloseEvent (Index %i) failed %d", i, WSAGetLastError());
            }
547 548
        }
    }
549 550 551

    if (caglobals.ip.terminate)
    {
Daniel Ferguson's avatar
Daniel Ferguson committed
552
        caglobals.ip.shutdownEvent = WSA_INVALID_EVENT;
553
    }
554 555
}

556
static void CAEventReturned(CASocketFd_t socket)
557
{
558
    CASocketFd_t fd = OC_INVALID_SOCKET;
559 560 561 562
    CATransportFlags_t flags = CA_DEFAULT_FLAGS;

    while (!caglobals.ip.terminate)
    {
563 564 565 566 567 568 569 570
        IS_MATCHING_IP_SOCKET(u6,  socket, CA_IPV6)
        else IS_MATCHING_IP_SOCKET(u6s, socket, CA_IPV6 | CA_SECURE)
        else IS_MATCHING_IP_SOCKET(u4,  socket, CA_IPV4)
        else IS_MATCHING_IP_SOCKET(u4s, socket, CA_IPV4 | CA_SECURE)
        else IS_MATCHING_IP_SOCKET(m6,  socket, CA_MULTICAST | CA_IPV6)
        else IS_MATCHING_IP_SOCKET(m6s, socket, CA_MULTICAST | CA_IPV6 | CA_SECURE)
        else IS_MATCHING_IP_SOCKET(m4,  socket, CA_MULTICAST | CA_IPV4)
        else IS_MATCHING_IP_SOCKET(m4s, socket, CA_MULTICAST | CA_IPV4 | CA_SECURE)
571 572 573 574
        else
        {
            break;
        }
575 576
        (void)CAReceiveMessage(socket, flags);
        // We will never get more than one match per socket, so always break.
577 578 579 580
        break;
    }
}

581
#endif
582

583
void CAUnregisterForAddressChanges(void)
584 585 586 587
{
#ifdef _WIN32
    if (caglobals.ip.addressChangeEvent != WSA_INVALID_EVENT)
    {
Dan Mihai's avatar
Dan Mihai committed
588
        OC_VERIFY(WSACloseEvent(caglobals.ip.addressChangeEvent));
589 590 591 592 593 594 595 596 597 598 599
        caglobals.ip.addressChangeEvent = WSA_INVALID_EVENT;
    }
#else
    if (caglobals.ip.netlinkFd != OC_INVALID_SOCKET)
    {
        close(caglobals.ip.netlinkFd);
        caglobals.ip.netlinkFd = OC_INVALID_SOCKET;
    }
#endif
}

600
void CADeInitializeIPGlobals(void)
601 602 603 604 605 606 607 608 609 610
{
    CLOSE_SOCKET(u6);
    CLOSE_SOCKET(u6s);
    CLOSE_SOCKET(u4);
    CLOSE_SOCKET(u4s);
    CLOSE_SOCKET(m6);
    CLOSE_SOCKET(m6s);
    CLOSE_SOCKET(m4);
    CLOSE_SOCKET(m4s);

611
    CAUnregisterForAddressChanges();
John Light's avatar
John Light committed
612
}
613

614
static CAResult_t CAReceiveMessage(CASocketFd_t fd, CATransportFlags_t flags)
John Light's avatar
John Light committed
615
{
616
    char recvBuffer[RECV_MSG_BUF_LEN] = {0};
617 618 619 620
    int level = 0;
    int type = 0;
    int namelen = 0;
    struct sockaddr_storage srcAddr = { .ss_family = 0 };
621
    unsigned char *pktinfo = NULL;
622
#if !defined(WSA_CMSG_DATA)
623
    size_t len = 0;
hyuna0213.jo's avatar
hyuna0213.jo committed
624
    struct cmsghdr *cmp = NULL;
625
    struct iovec iov = { .iov_base = recvBuffer, .iov_len = sizeof (recvBuffer) };
626 627 628 629 630 631 632 633
    union control
    {
        struct cmsghdr cmsg;
        unsigned char data[CMSG_SPACE(sizeof (struct in6_pktinfo))];
    } cmsg;

    if (flags & CA_IPV6)
    {
hyuna0213.jo's avatar
hyuna0213.jo committed
634
        namelen = sizeof (struct sockaddr_in6);
635 636 637 638 639 640
        level = IPPROTO_IPV6;
        type = IPV6_PKTINFO;
        len = sizeof (struct in6_pktinfo);
    }
    else
    {
hyuna0213.jo's avatar
hyuna0213.jo committed
641
        namelen = sizeof (struct sockaddr_in);
642 643 644 645 646
        level = IPPROTO_IP;
        type = IP_PKTINFO;
        len = sizeof (struct in6_pktinfo);
    }

hyuna0213.jo's avatar
hyuna0213.jo committed
647 648 649 650 651 652
    struct msghdr msg = { .msg_name = &srcAddr,
                          .msg_namelen = namelen,
                          .msg_iov = &iov,
                          .msg_iovlen = 1,
                          .msg_control = &cmsg,
                          .msg_controllen = CMSG_SPACE(len) };
653 654

    ssize_t recvLen = recvmsg(fd, &msg, flags);
655
    if (OC_SOCKET_ERROR == recvLen)
John Light's avatar
John Light committed
656 657 658 659
    {
        OIC_LOG_V(ERROR, TAG, "Recvfrom failed %s", strerror(errno));
        return CA_STATUS_FAILED;
    }
660

Dave Thaler's avatar
Dave Thaler committed
661
    for (cmp = CMSG_FIRSTHDR(&msg); cmp != NULL; cmp = CMSG_NXTHDR(&msg, cmp))
662
    {
Dave Thaler's avatar
Dave Thaler committed
663
        if (cmp->cmsg_level == level && cmp->cmsg_type == type)
664
        {
Dave Thaler's avatar
Dave Thaler committed
665
            pktinfo = CMSG_DATA(cmp);
666 667
        }
    }
668 669 670 671 672 673 674
#else // if defined(WSA_CMSG_DATA)
    union control
    {
        WSACMSGHDR cmsg;
        uint8_t data[WSA_CMSG_SPACE(sizeof (IN6_PKTINFO))];
    } cmsg;
    memset(&cmsg, 0, sizeof(cmsg));
675

676 677 678 679 680 681 682 683 684 685 686 687
    if (flags & CA_IPV6)
    {
        namelen  = sizeof (struct sockaddr_in6);
        level = IPPROTO_IPV6;
        type = IPV6_PKTINFO;
    }
    else
    {
        namelen = sizeof (struct sockaddr_in);
        level = IPPROTO_IP;
        type = IP_PKTINFO;
    }
688

689
    WSABUF iov = {.len = sizeof (recvBuffer), .buf = recvBuffer};
Daniel Ferguson's avatar
Daniel Ferguson committed
690
    WSAMSG msg = {.name = (PSOCKADDR)&srcAddr,
691 692 693
                  .namelen = namelen,
                  .lpBuffers = &iov,
                  .dwBufferCount = 1,
694
                  .Control = {.buf = (char*)cmsg.data, .len = sizeof (cmsg)}
695 696 697
                 };

    uint32_t recvLen = 0;
698
    uint32_t ret = caglobals.ip.wsaRecvMsg(fd, &msg, (LPDWORD)&recvLen, 0,0);
699
    if (OC_SOCKET_ERROR == ret)
700 701
    {
        OIC_LOG_V(ERROR, TAG, "WSARecvMsg failed %i", WSAGetLastError());
702
        return CA_STATUS_FAILED;
703 704
    }

705 706
    OIC_LOG_V(DEBUG, TAG, "WSARecvMsg recvd %u bytes", recvLen);

Dave Thaler's avatar
Dave Thaler committed
707 708
    for (WSACMSGHDR *cmp = WSA_CMSG_FIRSTHDR(&msg); cmp != NULL;
         cmp = WSA_CMSG_NXTHDR(&msg, cmp))
709
    {
Dave Thaler's avatar
Dave Thaler committed
710
        if (cmp->cmsg_level == level && cmp->cmsg_type == type)
711
        {
Dave Thaler's avatar
Dave Thaler committed
712
            pktinfo = WSA_CMSG_DATA(cmp);
713 714 715
        }
    }
#endif // !defined(WSA_CMSG_DATA)
716 717 718 719 720 721
    if (!pktinfo)
    {
        OIC_LOG(ERROR, TAG, "pktinfo is null");
        return CA_STATUS_FAILED;
    }

722
    CASecureEndpoint_t sep = {.endpoint = {.adapter = CA_ADAPTER_IP, .flags = flags}};
723

John Light's avatar
John Light committed
724 725
    if (flags & CA_IPV6)
    {
Dave Thaler's avatar
Dave Thaler committed
726 727 728
        sep.endpoint.ifindex = ((struct in6_pktinfo *)pktinfo)->ipi6_ifindex;

        if (flags & CA_MULTICAST)
729 730 731 732 733 734 735 736
        {
            struct in6_addr *addr = &(((struct in6_pktinfo *)pktinfo)->ipi6_addr);
            unsigned char topbits = ((unsigned char *)addr)[0];
            if (topbits != 0xff)
            {
                sep.endpoint.flags &= ~CA_MULTICAST;
            }
        }
John Light's avatar
John Light committed
737
    }
738 739
    else
    {
Dave Thaler's avatar
Dave Thaler committed
740 741 742
        sep.endpoint.ifindex = ((struct in_pktinfo *)pktinfo)->ipi_ifindex;

        if (flags & CA_MULTICAST)
743 744 745 746 747 748 749 750 751 752 753
        {
            struct in_addr *addr = &((struct in_pktinfo *)pktinfo)->ipi_addr;
            uint32_t host = ntohl(addr->s_addr);
            unsigned char topbits = ((unsigned char *)&host)[3];
            if (topbits < 224 || topbits > 239)
            {
                sep.endpoint.flags &= ~CA_MULTICAST;
            }
        }
    }

754
    CAConvertAddrToName(&srcAddr, namelen, sep.endpoint.addr, &sep.endpoint.port);
755

John Light's avatar
John Light committed
756 757
    if (flags & CA_SECURE)
    {
758
#ifdef __WITH_DTLS__
759
#ifdef TB_LOG
760
        int decryptResult =
761 762 763
#endif
        CAdecryptSsl(&sep, (uint8_t *)recvBuffer, recvLen);
        OIC_LOG_V(DEBUG, TAG, "CAdecryptSsl returns [%d]", decryptResult);
John Light's avatar
John Light committed
764 765
#else
        OIC_LOG(ERROR, TAG, "Encrypted message but no DTLS");
766
#endif // __WITH_DTLS__
John Light's avatar
John Light committed
767 768 769 770 771
    }
    else
    {
        if (g_packetReceivedCallback)
        {
772
            g_packetReceivedCallback(&sep, recvBuffer, recvLen);
773 774
        }
    }
John Light's avatar
John Light committed
775 776

    return CA_STATUS_OK;
777 778
}

779
void CAIPPullData(void)
780
{
781 782
    OIC_LOG_V(DEBUG, TAG, "IN %s", __func__);
    OIC_LOG_V(DEBUG, TAG, "OUT %s", __func__);
John Light's avatar
John Light committed
783
}
784

785
static CASocketFd_t CACreateSocket(int family, uint16_t *port, bool isMulticast)
John Light's avatar
John Light committed
786 787
{
    int socktype = SOCK_DGRAM;
788
#ifdef SOCK_CLOEXEC
John Light's avatar
John Light committed
789
    socktype |= SOCK_CLOEXEC;
790
#endif
791 792
    CASocketFd_t fd = socket(family, socktype, IPPROTO_UDP);
    if (OC_INVALID_SOCKET == fd)
793
    {
794
        OIC_LOG_V(ERROR, TAG, "create socket failed: %s", CAIPS_GET_ERROR);
795
        return OC_INVALID_SOCKET;
796 797
    }

798
#if !defined(SOCK_CLOEXEC) && defined(FD_CLOEXEC)
John Light's avatar
John Light committed
799 800
    int fl = fcntl(fd, F_GETFD);
    if (-1 == fl || -1 == fcntl(fd, F_SETFD, fl|FD_CLOEXEC))
801
    {
John Light's avatar
John Light committed
802 803
        OIC_LOG_V(ERROR, TAG, "set FD_CLOEXEC failed: %s", strerror(errno));
        close(fd);
804
        return OC_INVALID_SOCKET;
805
    }
806
#endif
807
    struct sockaddr_storage sa = { .ss_family = (short)family };
808
    socklen_t socklen = 0;
809

John Light's avatar
John Light committed
810
    if (family == AF_INET6)
811
    {
John Light's avatar
John Light committed
812
        int on = 1;
813

814
        if (OC_SOCKET_ERROR == setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, OPTVAL_T(&on), sizeof (on)))
John Light's avatar
John Light committed
815
        {
816
            OIC_LOG_V(ERROR, TAG, "IPV6_V6ONLY failed: %s", CAIPS_GET_ERROR);
John Light's avatar
John Light committed
817
        }
818

819
#if defined(IPV6_RECVPKTINFO)
Dave Thaler's avatar
Dave Thaler committed
820
        if (OC_SOCKET_ERROR == setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof (on)))
821
#else
Dave Thaler's avatar
Dave Thaler committed
822
        if (OC_SOCKET_ERROR == setsockopt(fd, IPPROTO_IPV6, IPV6_PKTINFO, OPTVAL_T(&on), sizeof (on)))
823
#endif
Dave Thaler's avatar
Dave Thaler committed
824 825
        {
            OIC_LOG_V(ERROR, TAG, "IPV6_RECVPKTINFO failed: %s",CAIPS_GET_ERROR);
826 827
        }

John Light's avatar
John Light committed
828
        ((struct sockaddr_in6 *)&sa)->sin6_port = htons(*port);
829
        socklen = sizeof (struct sockaddr_in6);
John Light's avatar
John Light committed
830 831 832
    }
    else
    {
Dave Thaler's avatar
Dave Thaler committed
833 834
        int on = 1;
        if (OC_SOCKET_ERROR == setsockopt(fd, IPPROTO_IP, IP_PKTINFO, OPTVAL_T(&on), sizeof (on)))
835
        {
Dave Thaler's avatar
Dave Thaler committed
836
            OIC_LOG_V(ERROR, TAG, "IP_PKTINFO failed: %s", CAIPS_GET_ERROR);
837 838
        }

John Light's avatar
John Light committed
839
        ((struct sockaddr_in *)&sa)->sin_port = htons(*port);
840
        socklen = sizeof (struct sockaddr_in);
841 842
    }

843
    if (isMulticast && *port) // use the given port
844
    {
John Light's avatar
John Light committed
845
        int on = 1;
Dave Thaler's avatar
Dave Thaler committed
846
        if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, OPTVAL_T(&on), sizeof (on)))
847
        {
848
            OIC_LOG_V(ERROR, TAG, "SO_REUSEADDR failed: %s", CAIPS_GET_ERROR);
Dave Thaler's avatar
Dave Thaler committed
849
            OC_CLOSE_SOCKET(fd);
850
            return OC_INVALID_SOCKET;
851 852 853
        }
    }

854
    if (OC_SOCKET_ERROR == bind(fd, (struct sockaddr *)&sa, socklen))
855
    {
856
        OIC_LOG_V(ERROR, TAG, "bind socket failed: %s", CAIPS_GET_ERROR);
Dave Thaler's avatar
Dave Thaler committed
857
        OC_CLOSE_SOCKET(fd);
858
        return OC_INVALID_SOCKET;
859 860
    }

861
    if (!*port) // return the assigned port
862
    {
863
        if (OC_SOCKET_ERROR == getsockname(fd, (struct sockaddr *)&sa, &socklen))
864
        {
865
            OIC_LOG_V(ERROR, TAG, "getsockname failed: %s", CAIPS_GET_ERROR);
Dave Thaler's avatar
Dave Thaler committed
866
            OC_CLOSE_SOCKET(fd);
867
            return OC_INVALID_SOCKET;
868
        }
John Light's avatar
John Light committed
869 870 871
        *port = ntohs(family == AF_INET6 ?
                      ((struct sockaddr_in6 *)&sa)->sin6_port :
                      ((struct sockaddr_in *)&sa)->sin_port);
872 873
    }

John Light's avatar
John Light committed
874 875 876
    return fd;
}

Dave Thaler's avatar
Dave Thaler committed
877 878 879
#ifdef _WIN32
#define CHECKFD(FD)
#else
John Light's avatar
John Light committed
880
#define CHECKFD(FD) \
881 882
do \
{ \
John Light's avatar
John Light committed
883
    if (FD > caglobals.ip.maxfd) \
884 885 886 887
    { \
        caglobals.ip.maxfd = FD; \
    } \
} while (0)
Dave Thaler's avatar
Dave Thaler committed
888
#endif
889
#define NEWSOCKET(FAMILY, NAME, MULTICAST) \
890 891
do \
{ \
892
    caglobals.ip.NAME.fd = CACreateSocket(FAMILY, &caglobals.ip.NAME.port, MULTICAST); \
893
    if (caglobals.ip.NAME.fd == OC_INVALID_SOCKET) \
894 895 896 897
    {   \
        caglobals.ip.NAME.port = 0; \
        caglobals.ip.NAME.fd = CACreateSocket(FAMILY, &caglobals.ip.NAME.port, MULTICAST); \
    }   \
898 899
    CHECKFD(caglobals.ip.NAME.fd); \
} while(0)
John Light's avatar
John Light committed
900

901
static void CARegisterForAddressChanges(void)