catcpserver.c 44.9 KB
Newer Older
1
/* ****************************************************************
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
 *
 * Copyright 2015 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.
 *
 ******************************************************************/

Dave Thaler's avatar
Dave Thaler committed
21 22
#include "iotivity_config.h"
#include "iotivity_debug.h"
23
#include <sys/types.h>
Dave Thaler's avatar
Dave Thaler committed
24
#ifdef HAVE_SYS_SOCKET_H
25
#include <sys/socket.h>
Dave Thaler's avatar
Dave Thaler committed
26 27 28 29 30
#endif
#ifdef HAVE_WS2TCPIP_H
#include <ws2tcpip.h>
#endif
#ifdef HAVE_SYS_SELECT_H
31
#include <sys/select.h>
Dave Thaler's avatar
Dave Thaler committed
32 33
#endif
#ifdef HAVE_SYS_IOCTL_H
34
#include <sys/ioctl.h>
Dave Thaler's avatar
Dave Thaler committed
35 36
#endif
#ifdef HAVE_SYS_POLL_H
37
#include <sys/poll.h>
Dave Thaler's avatar
Dave Thaler committed
38
#endif
39
#include <stdio.h>
Dave Thaler's avatar
Dave Thaler committed
40
#ifdef HAVE_UNISTD_H
41
#include <unistd.h>
Dave Thaler's avatar
Dave Thaler committed
42
#endif
43
#include <fcntl.h>
Dave Thaler's avatar
Dave Thaler committed
44
#ifdef HAVE_ARPA_INET_H
45
#include <arpa/inet.h>
Dave Thaler's avatar
Dave Thaler committed
46 47
#endif
#ifdef HAVE_NETINET_IN_H
48
#include <netinet/in.h>
Dave Thaler's avatar
Dave Thaler committed
49 50
#endif
#ifdef HAVE_NET_IF_H
51
#include <net/if.h>
Dave Thaler's avatar
Dave Thaler committed
52
#endif
53
#include <errno.h>
Dave Thaler's avatar
Dave Thaler committed
54
#include <assert.h>
55

Dave Thaler's avatar
Dave Thaler committed
56
#ifdef HAVE_NETDB_H
57 58 59 60
#include <netdb.h>
#endif

#include "catcpinterface.h"
61
#include "caipnwmonitor.h"
62
#include "caadapterutils.h"
63
#include "octhread.h"
64
#include "oic_malloc.h"
65
#include "oic_string.h"
Andrii Shtompel's avatar
Andrii Shtompel committed
66

67 68 69
#include <coap/pdu.h>
#include <coap/utlist.h>

Andrii Shtompel's avatar
Andrii Shtompel committed
70
#ifdef __WITH_TLS__
71
#include "ca_adapter_net_ssl.h"
Andrii Shtompel's avatar
Andrii Shtompel committed
72
#endif
73 74 75 76

/**
 * Logging tag for module name.
 */
77
#define TAG "OIC_CA_TCP_SERVER"
78 79 80 81 82

/**
 * Maximum CoAP over TCP header length
 * to know the total data length.
 */
Andrii Shtompel's avatar
Andrii Shtompel committed
83 84 85 86 87 88
#define COAP_MAX_HEADER_SIZE  6

/**
 * TLS header size
 */
#define TLS_HEADER_SIZE 5
89 90 91 92

/**
 * Mutex to synchronize device object list.
 */
93
static oc_mutex g_mutexObjectList = NULL;
94 95 96 97

/**
 * Conditional mutex to synchronize.
 */
98
static oc_cond g_condObjectList = NULL;
99 100 101 102

/**
 * Maintains the callback to be notified when data received from remote device.
 */
103
static CATCPPacketReceivedCallback g_packetReceivedCallback = NULL;
104 105 106 107

/**
 * Error callback to update error in TCP.
 */
108
static CATCPErrorHandleCallback g_tcpErrorHandler = NULL;
109

hyuna0213.jo's avatar
hyuna0213.jo committed
110 111 112
/**
 * Connected Callback to pass the connection information to RI.
 */
113
static CATCPConnectionHandleCallback g_connectionCallback = NULL;
hyuna0213.jo's avatar
hyuna0213.jo committed
114

115 116 117 118 119
/**
 * Store the connected TCP session information.
 */
static CATCPSessionInfo_t *g_sessionList = NULL;

120 121 122 123
static CAResult_t CATCPCreateMutex();
static void CATCPDestroyMutex();
static CAResult_t CATCPCreateCond();
static void CATCPDestroyCond();
124
static CASocketFd_t CACreateAcceptSocket(int family, CASocket_t *sock);
125
static void CAAcceptConnection(CATransportFlags_t flag, CASocket_t *sock);
126
static void CAFindReadyMessage();
Dave Thaler's avatar
Dave Thaler committed
127
#if !defined(WSA_WAIT_EVENT_0)
hyuna0213.jo's avatar
hyuna0213.jo committed
128
static void CASelectReturned(fd_set *readFds);
Dave Thaler's avatar
Dave Thaler committed
129
#else
130
static void CASocketEventReturned(CASocketFd_t socket, long networkEvents);
Dave Thaler's avatar
Dave Thaler committed
131
#endif
132
static CAResult_t CAReceiveMessage(CATCPSessionInfo_t *svritem);
133
static void CAReceiveHandler(void *data);
134
static CAResult_t CATCPCreateSocket(int family, CATCPSessionInfo_t *svritem);
135

Dave Thaler's avatar
Dave Thaler committed
136 137 138
#if defined(WSA_WAIT_EVENT_0)
#define CHECKFD(FD)
#else
139
#define CHECKFD(FD) \
140 141
do \
{ \
142
    if (FD > caglobals.tcp.maxfd) \
143 144 145 146
    { \
        caglobals.tcp.maxfd = FD; \
    } \
} while (0)
Dave Thaler's avatar
Dave Thaler committed
147
#endif
148

149 150 151
#define CLOSE_SOCKET(TYPE) \
    if (caglobals.tcp.TYPE.fd != OC_INVALID_SOCKET) \
    { \
Dave Thaler's avatar
Dave Thaler committed
152
        OC_CLOSE_SOCKET(caglobals.tcp.TYPE.fd); \
153 154 155 156 157 158 159 160 161
        caglobals.tcp.TYPE.fd = OC_INVALID_SOCKET; \
    }

#define CA_FD_SET(TYPE, FDS) \
    if (caglobals.tcp.TYPE.fd != OC_INVALID_SOCKET) \
    { \
        FD_SET(caglobals.tcp.TYPE.fd, FDS); \
    }

162 163 164 165
static void CATCPDestroyMutex()
{
    if (g_mutexObjectList)
    {
166
        oc_mutex_free(g_mutexObjectList);
167 168 169 170 171 172 173 174
        g_mutexObjectList = NULL;
    }
}

static CAResult_t CATCPCreateMutex()
{
    if (!g_mutexObjectList)
    {
175
        g_mutexObjectList = oc_mutex_new();
176 177 178 179 180 181 182 183 184 185 186 187 188 189
        if (!g_mutexObjectList)
        {
            OIC_LOG(ERROR, TAG, "Failed to created mutex!");
            return CA_STATUS_FAILED;
        }
    }

    return CA_STATUS_OK;
}

static void CATCPDestroyCond()
{
    if (g_condObjectList)
    {
190
        oc_cond_free(g_condObjectList);
191 192 193 194 195 196 197 198
        g_condObjectList = NULL;
    }
}

static CAResult_t CATCPCreateCond()
{
    if (!g_condObjectList)
    {
199
        g_condObjectList = oc_cond_new();
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215
        if (!g_condObjectList)
        {
            OIC_LOG(ERROR, TAG, "Failed to created cond!");
            return CA_STATUS_FAILED;
        }
    }
    return CA_STATUS_OK;
}

static void CAReceiveHandler(void *data)
{
    (void)data;
    OIC_LOG(DEBUG, TAG, "IN - CAReceiveHandler");

    while (!caglobals.tcp.terminate)
    {
216
        CAFindReadyMessage();
217 218
    }

219 220 221
    oc_mutex_lock(g_mutexObjectList);
    oc_cond_signal(g_condObjectList);
    oc_mutex_unlock(g_mutexObjectList);
222 223 224 225

    OIC_LOG(DEBUG, TAG, "OUT - CAReceiveHandler");
}

Dave Thaler's avatar
Dave Thaler committed
226 227
#if !defined(WSA_WAIT_EVENT_0)

228
static void CAFindReadyMessage()
229
{
230 231
    fd_set readFds;
    struct timeval timeout = { .tv_sec = caglobals.tcp.selectTimeout };
232

233
    FD_ZERO(&readFds);
234
    CA_FD_SET(ipv4, &readFds);
235
    CA_FD_SET(ipv4s, &readFds);
236
    CA_FD_SET(ipv6, &readFds);
237
    CA_FD_SET(ipv6s, &readFds);
238

239
    if (OC_INVALID_SOCKET != caglobals.tcp.shutdownFds[0])
240 241 242
    {
        FD_SET(caglobals.tcp.shutdownFds[0], &readFds);
    }
243
    if (OC_INVALID_SOCKET != caglobals.tcp.connectionFds[0])
244 245 246
    {
        FD_SET(caglobals.tcp.connectionFds[0], &readFds);
    }
247

248 249
    CATCPSessionInfo_t *session = NULL;
    LL_FOREACH(g_sessionList, session)
250
    {
251
        if (session && session->fd != OC_INVALID_SOCKET && session->state == CONNECTED)
252
        {
253
            FD_SET(session->fd, &readFds);
254
        }
255
    }
256

257 258 259 260 261 262 263
    int ret = select(caglobals.tcp.maxfd + 1, &readFds, NULL, NULL, &timeout);

    if (caglobals.tcp.terminate)
    {
        OIC_LOG_V(DEBUG, TAG, "Packet receiver Stop request received.");
        return;
    }
264 265

    if (0 == ret)
266 267 268
    {
        return;
    }
269 270 271 272 273 274 275 276 277
    else if (0 < ret)
    {
        CASelectReturned(&readFds);
    }
    else // if (0 > ret)
    {
        OIC_LOG_V(FATAL, TAG, "select error %s", strerror(errno));
        return;
    }
278
}
279

hyuna0213.jo's avatar
hyuna0213.jo committed
280
static void CASelectReturned(fd_set *readFds)
281
{
282
    VERIFY_NON_NULL_VOID(readFds, TAG, "readFds is NULL");
283

284 285 286 287 288
    if (caglobals.tcp.ipv4.fd != -1 && FD_ISSET(caglobals.tcp.ipv4.fd, readFds))
    {
        CAAcceptConnection(CA_IPV4, &caglobals.tcp.ipv4);
        return;
    }
289 290 291 292 293
    else if (caglobals.tcp.ipv4s.fd != -1 && FD_ISSET(caglobals.tcp.ipv4s.fd, readFds))
    {
        CAAcceptConnection(CA_IPV4 | CA_SECURE, &caglobals.tcp.ipv4s);
        return;
    }
294
    else if (caglobals.tcp.ipv6.fd != -1 && FD_ISSET(caglobals.tcp.ipv6.fd, readFds))
295
    {
296
        CAAcceptConnection(CA_IPV6, &caglobals.tcp.ipv6);
297 298
        return;
    }
299 300 301 302 303
    else if (caglobals.tcp.ipv6s.fd != -1 && FD_ISSET(caglobals.tcp.ipv6s.fd, readFds))
    {
        CAAcceptConnection(CA_IPV6 | CA_SECURE, &caglobals.tcp.ipv6s);
        return;
    }
304 305 306 307 308 309 310 311 312 313 314 315
    else if (-1 != caglobals.tcp.connectionFds[0] &&
            FD_ISSET(caglobals.tcp.connectionFds[0], readFds))
    {
        // new connection was created from remote device.
        // exit the function to update read file descriptor.
        char buf[MAX_ADDR_STR_SIZE_CA] = {0};
        ssize_t len = read(caglobals.tcp.connectionFds[0], buf, sizeof (buf));
        if (-1 == len)
        {
            return;
        }
        OIC_LOG_V(DEBUG, TAG, "Received new connection event with [%s]", buf);
316 317
        return;
    }
318 319
    else
    {
320
        oc_mutex_lock(g_mutexObjectList);
321
        CATCPSessionInfo_t *session = NULL;
322 323
        CATCPSessionInfo_t *tmp = NULL;
        LL_FOREACH_SAFE(g_sessionList, session, tmp)
324
        {
325
            if (session && session->fd != OC_INVALID_SOCKET)
326
            {
327
                if (FD_ISSET(session->fd, readFds))
328
                {
329 330 331 332 333 334 335 336 337 338 339 340 341 342 343
                    CAResult_t res = CAReceiveMessage(session);
                    //disconnect session and clean-up data if any error occurs
                    if (res != CA_STATUS_OK)
                    {
#ifdef __WITH_TLS__
                        if (CA_STATUS_OK != CAcloseSslConnection(&session->sep.endpoint))
                        {
                            OIC_LOG(ERROR, TAG, "Failed to close TLS session");
                        }
#endif
                        LL_DELETE(g_sessionList, session);
                        CADisconnectTCPSession(session);
                        oc_mutex_unlock(g_mutexObjectList);
                        return;
                    }
344 345
                }
            }
346
        }
347
        oc_mutex_unlock(g_mutexObjectList);
348 349
    }
}
350

Dave Thaler's avatar
Dave Thaler committed
351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403
#else // if defined(WSA_WAIT_EVENT_0)

/**
 * Push an exiting socket event to listen on
 *
 * @param[in] s              Socket to push
 * @param[in] socketArray    Array in which to add socket
 * @param[in] event          Event to push
 * @param[in] eventArray     Array in which to add event
 * @param[in/out] eventIndex Current length of arrays
 * @param[in] arraySize      Maximum length of arrays
 * @return true on success, false on failure
 */
static bool CAPushEvent(CASocketFd_t s, CASocketFd_t* socketArray,
                        HANDLE event, HANDLE* eventArray, int* eventIndex, int arraySize)
{
    if (*eventIndex == arraySize)
    {
        return false;
    }

    assert(*eventIndex >= 0);
    socketArray[*eventIndex] = s;
    eventArray[(*eventIndex)++] = event;
    return true;
}

/**
 * Push a new socket event to listen on
 *
 * @param[in] s              Socket to push
 * @param[in] socketArray    Array in which to add socket
 * @param[in] eventArray     Array in which to add event
 * @param[in/out] eventIndex Current length of arrays
 * @param[in] arraySize      Maximum length of arrays
 * @return true on success, false on failure
 */
static bool CAPushSocket(CASocketFd_t s, CASocketFd_t* socketArray,
                         HANDLE *eventArray, int *eventIndex, int arraySize)
{
    if (s == OC_INVALID_SOCKET)
    {
        // Nothing to push.
        return true;
    }

    WSAEVENT newEvent = WSACreateEvent();
    if (WSA_INVALID_EVENT == newEvent)
    {
        OIC_LOG_V(ERROR, TAG, "WSACreateEvent(NewEvent) failed %u", WSAGetLastError());
        return false;
    }

404
    if (0 != WSAEventSelect(s, newEvent, FD_READ | FD_ACCEPT))
Dave Thaler's avatar
Dave Thaler committed
405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430
    {
        OIC_LOG_V(ERROR, TAG, "WSAEventSelect failed %u", WSAGetLastError());
        OC_VERIFY(WSACloseEvent(newEvent));
        return false;
    }

    if (!CAPushEvent(s, socketArray, newEvent, eventArray, eventIndex, arraySize))
    {
        OIC_LOG_V(ERROR, TAG, "CAPushEvent failed");
        OC_VERIFY(WSACloseEvent(newEvent));
        return false;
    }

    return true;
}

#define EVENT_ARRAY_SIZE 64

/**
 * Process any message that is ready
 */
static void CAFindReadyMessage()
{
    CASocketFd_t socketArray[EVENT_ARRAY_SIZE] = {0};
    HANDLE eventArray[_countof(socketArray)];
    int arraySize = 0;
431

Dave Thaler's avatar
Dave Thaler committed
432 433 434 435 436 437 438 439
    if (OC_INVALID_SOCKET != caglobals.tcp.ipv4.fd)
    {
        CAPushSocket(caglobals.tcp.ipv4.fd, socketArray, eventArray, &arraySize, _countof(socketArray));
    }
    if (OC_INVALID_SOCKET != caglobals.tcp.ipv6.fd)
    {
        CAPushSocket(caglobals.tcp.ipv6.fd, socketArray, eventArray, &arraySize, _countof(socketArray));
    }
440
    if (WSA_INVALID_EVENT != caglobals.tcp.updateEvent)
Dave Thaler's avatar
Dave Thaler committed
441 442
    {
        CAPushEvent(OC_INVALID_SOCKET, socketArray,
443
                    caglobals.tcp.updateEvent, eventArray, &arraySize, _countof(socketArray));
Dave Thaler's avatar
Dave Thaler committed
444
    }
445

446 447 448
    int svrlistBeginIndex = arraySize;

    while (!caglobals.tcp.terminate)
Dave Thaler's avatar
Dave Thaler committed
449
    {
450
        CATCPSessionInfo_t *session = NULL;
451
        LL_FOREACH(g_sessionList, session)
Dave Thaler's avatar
Dave Thaler committed
452
        {
453
            if (session && OC_INVALID_SOCKET != session->fd && (arraySize < EVENT_ARRAY_SIZE))
454
            {
455
                 CAPushSocket(session->fd, socketArray, eventArray, &arraySize, _countof(socketArray));
456
            }
Dave Thaler's avatar
Dave Thaler committed
457 458
        }

459 460
        // Should not have overflowed buffer
        assert(arraySize <= (_countof(socketArray)));
Dave Thaler's avatar
Dave Thaler committed
461 462

        DWORD ret = WSAWaitForMultipleEvents(arraySize, eventArray, FALSE, WSA_INFINITE, FALSE);
463 464
        assert(ret < (WSA_WAIT_EVENT_0 + arraySize));
        DWORD eventIndex = ret - WSA_WAIT_EVENT_0;
Dave Thaler's avatar
Dave Thaler committed
465

466
        if (caglobals.tcp.updateEvent == eventArray[eventIndex])
Dave Thaler's avatar
Dave Thaler committed
467
        {
468
            OC_VERIFY(WSAResetEvent(caglobals.tcp.updateEvent));
Dave Thaler's avatar
Dave Thaler committed
469
        }
470
        else
Dave Thaler's avatar
Dave Thaler committed
471
        {
472 473 474 475 476 477 478 479 480 481 482 483
            // WSAEnumNetworkEvents also resets the event
            WSANETWORKEVENTS networkEvents;
            int enumResult = WSAEnumNetworkEvents(socketArray[eventIndex], eventArray[eventIndex], &networkEvents);
            if (SOCKET_ERROR != enumResult)
            {
                CASocketEventReturned(socketArray[eventIndex], networkEvents.lNetworkEvents);
            }
            else
            {
                OIC_LOG_V(ERROR, TAG, "WSAEnumNetworkEvents failed %u", WSAGetLastError());
                break;
            }
Dave Thaler's avatar
Dave Thaler committed
484 485
        }

486 487 488 489 490 491 492
        // Close events associated with svrlist
        while (arraySize > svrlistBeginIndex)
        {
            arraySize--;
            OC_VERIFY(WSACloseEvent(eventArray[arraySize]));
            eventArray[arraySize] = NULL;
        }
Dave Thaler's avatar
Dave Thaler committed
493 494
    }

495
    // Close events
Dave Thaler's avatar
Dave Thaler committed
496 497 498 499 500 501 502 503
    while (arraySize > 0)
    {
        arraySize--;
        OC_VERIFY(WSACloseEvent(eventArray[arraySize]));
    }

    if (caglobals.tcp.terminate)
    {
504
        caglobals.tcp.updateEvent = WSA_INVALID_EVENT;
Dave Thaler's avatar
Dave Thaler committed
505 506 507 508 509 510 511 512 513
        WSACleanup();
    }
}

/**
 * Process an event (accept or receive) that is ready on a socket
 *
 * @param[in] s Socket to process
 */
514
static void CASocketEventReturned(CASocketFd_t s, long networkEvents)
Dave Thaler's avatar
Dave Thaler committed
515 516 517 518 519 520
{
    if (caglobals.tcp.terminate)
    {
        return;
    }

521 522
    assert(s != OC_INVALID_SOCKET);

523
    if (FD_ACCEPT & networkEvents)
Dave Thaler's avatar
Dave Thaler committed
524
    {
525 526 527 528 529 530 531 532
        if ((caglobals.tcp.ipv4.fd != OC_INVALID_SOCKET) && (caglobals.tcp.ipv4.fd == s))
        {
            CAAcceptConnection(CA_IPV4, &caglobals.tcp.ipv4);
        }
        else if ((caglobals.tcp.ipv6.fd != OC_INVALID_SOCKET) && (caglobals.tcp.ipv6.fd == s))
        {
            CAAcceptConnection(CA_IPV6, &caglobals.tcp.ipv6);
        }
Dave Thaler's avatar
Dave Thaler committed
533
    }
534 535

    if (FD_READ & networkEvents)
Dave Thaler's avatar
Dave Thaler committed
536
    {
537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561
        oc_mutex_lock(g_mutexObjectList);
        CATCPSessionInfo_t *session = NULL;
        CATCPSessionInfo_t *tmp = NULL;
        LL_FOREACH_SAFE(g_sessionList, session, tmp)
        {
            if (session && (session->fd == s))
            {
                CAResult_t res = CAReceiveMessage(session);
                //disconnect session and clean-up data if any error occurs
                if (res != CA_STATUS_OK)
                {
#ifdef __WITH_TLS__
                    if (CA_STATUS_OK != CAcloseSslConnection(&session->sep.endpoint))
                    {
                        OIC_LOG(ERROR, TAG, "Failed to close TLS session");
                    }
#endif
                    LL_DELETE(g_sessionList, session);
                    CADisconnectTCPSession(session);
                    oc_mutex_unlock(g_mutexObjectList);
                    return;
                }
            }
        }
        oc_mutex_unlock(g_mutexObjectList);
Dave Thaler's avatar
Dave Thaler committed
562 563 564 565 566
    }
}

#endif // WSA_WAIT_EVENT_0

567
static void CAAcceptConnection(CATransportFlags_t flag, CASocket_t *sock)
568
{
569 570
    VERIFY_NON_NULL_VOID(sock, TAG, "sock is NULL");

571 572
    struct sockaddr_storage clientaddr;
    socklen_t clientlen = sizeof (struct sockaddr_in);
573 574 575 576
    if (flag & CA_IPV6)
    {
        clientlen = sizeof(struct sockaddr_in6);
    }
577

578 579
    CASocketFd_t sockfd = accept(sock->fd, (struct sockaddr *)&clientaddr, &clientlen);
    if (OC_INVALID_SOCKET != sockfd)
580 581 582 583 584 585
    {
        CATCPSessionInfo_t *svritem =
                (CATCPSessionInfo_t *) OICCalloc(1, sizeof (*svritem));
        if (!svritem)
        {
            OIC_LOG(ERROR, TAG, "Out of memory");
Dave Thaler's avatar
Dave Thaler committed
586
            OC_CLOSE_SOCKET(sockfd);
587 588
            return;
        }
589

590
        svritem->fd = sockfd;
591
        svritem->sep.endpoint.flags = flag;
592
        svritem->sep.endpoint.adapter = CA_ADAPTER_TCP;
593
        svritem->state = CONNECTED;
594
        svritem->isClient = false;
595
        CAConvertAddrToName((struct sockaddr_storage *)&clientaddr, clientlen,
596
                            svritem->sep.endpoint.addr, &svritem->sep.endpoint.port);
597

598
        oc_mutex_lock(g_mutexObjectList);
599
        LL_APPEND(g_sessionList, svritem);
600
        oc_mutex_unlock(g_mutexObjectList);
601

602
        CHECKFD(sockfd);
603 604 605 606

        // pass the connection information to CA Common Layer.
        if (g_connectionCallback)
        {
607
            g_connectionCallback(&(svritem->sep.endpoint), true, svritem->isClient);
608
        }
609
    }
610 611
}

612 613 614 615 616
/**
 * Clean socket state data
 *
 * @param[in/out] item - socket state data
 */
617
void CACleanData(CATCPSessionInfo_t *svritem)
618
{
619
    if (svritem)
620
    {
621 622 623
        OICFree(svritem->data);
        svritem->data = NULL;
        svritem->len = 0;
624
        svritem->tlsLen = 0;
625 626
        svritem->totalLen = 0;
        svritem->protocol = UNKNOWN;
627
    }
628
}
629

630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745
/**
 * Construct CoAP header and payload from buffer
 *
 * @param[in] svritem - used socket, buffer, current received message length and protocol
 * @param[in/out]  data  - data buffer, this value is updated as data is copied to svritem
 * @param[in/out]  dataLength  - length of data, this value decreased as data is copied to svritem
 * @return             - CA_STATUS_OK or appropriate error code
 */
CAResult_t CAConstructCoAP(CATCPSessionInfo_t *svritem, unsigned char **data,
                          size_t *dataLength)
{
    OIC_LOG_V(DEBUG, TAG, "In %s", __func__);

    if (NULL == svritem || NULL == data || NULL == dataLength)
    {
        OIC_LOG(ERROR, TAG, "Invalid input parameter(NULL)");
        return CA_STATUS_INVALID_PARAM;
    }

    unsigned char *inBuffer = *data;
    size_t inLen = *dataLength;
    OIC_LOG_V(DEBUG, TAG, "before-datalength : %u", *dataLength);

    if (NULL == svritem->data && inLen > 0)
    {
        // allocate memory for message header (CoAP header size because it is bigger)
        svritem->data = (unsigned char *) OICCalloc(1, COAP_MAX_HEADER_SIZE);
        if (NULL == svritem->data)
        {
            OIC_LOG(ERROR, TAG, "OICCalloc - out of memory");
            return CA_MEMORY_ALLOC_FAILED;
        }

        // copy 1 byte to parse coap header length
        memcpy(svritem->data, inBuffer, 1);
        svritem->len = 1;
        inBuffer++;
        inLen--;
    }

    //if not enough data received - read them on next CAFillHeader() call
    if (0 == inLen)
    {
        return CA_STATUS_OK;
    }

    //if enough data received - parse header
    svritem->protocol = COAP;

    //seems CoAP data received. read full coap header.
    coap_transport_t transport = coap_get_tcp_header_type_from_initbyte(svritem->data[0] >> 4);
    size_t headerLen = coap_get_tcp_header_length_for_transport(transport);
    size_t copyLen = 0;

    // HEADER
    if (svritem->len < headerLen)
    {
        copyLen = headerLen - svritem->len;
        if (inLen < copyLen)
        {
            copyLen = inLen;
        }

        //read required bytes to have full CoAP header
        memcpy(svritem->data + svritem->len, inBuffer, copyLen);
        svritem->len += copyLen;
        inBuffer += copyLen;
        inLen -= copyLen;

        //if not enough data received - read them on next CAFillHeader() call
        if (svritem->len < headerLen)
        {
            *data = inBuffer;
            *dataLength = inLen;
            OIC_LOG(DEBUG, TAG, "CoAP header received partially. Wait for rest header data");
            return CA_STATUS_OK;
        }

        //calculate CoAP message length
        svritem->totalLen = CAGetTotalLengthFromHeader(svritem->data);

        // allocate required memory
        unsigned char *buffer = OICRealloc(svritem->data, svritem->totalLen);
        if (NULL == buffer)
        {
            OIC_LOG(ERROR, TAG, "OICRealloc - out of memory");
            return CA_MEMORY_ALLOC_FAILED;
        }
        svritem->data = buffer;
    }

    // PAYLOAD
    if (inLen > 0)
    {
        // read required bytes to have full CoAP payload
        copyLen = svritem->totalLen - svritem->len;
        if (inLen < copyLen)
        {
            copyLen = inLen;
        }

        //read required bytes to have full CoAP header
        memcpy(svritem->data + svritem->len, inBuffer, copyLen);
        svritem->len += copyLen;
        inBuffer += copyLen;
        inLen -= copyLen;
    }

    *data = inBuffer;
    *dataLength = inLen;

    OIC_LOG_V(DEBUG, TAG, "after-datalength : %u", *dataLength);
    OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
    return CA_STATUS_OK;
}

746
static CAResult_t CAReceiveMessage(CATCPSessionInfo_t *svritem)
747
{
748
    VERIFY_NON_NULL(svritem, TAG, "svritem is NULL");
749

750 751
    // read data
    int len = 0;
752
    CAResult_t res = CA_STATUS_OK;
753
    if (svritem->sep.endpoint.flags & CA_SECURE)
754
    {
755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774
        svritem->protocol = TLS;

#ifdef __WITH_TLS__
        size_t nbRead = 0;
        size_t tlsLength = 0;

        if (TLS_HEADER_SIZE > svritem->tlsLen)
        {
            nbRead = TLS_HEADER_SIZE - svritem->tlsLen;
        }
        else
        {
            //[3][4] bytes in tls header are tls payload length
            tlsLength = TLS_HEADER_SIZE +
                            (size_t)((svritem->tlsdata[3] << 8) | svritem->tlsdata[4]);
            OIC_LOG_V(DEBUG, TAG, "toal tls length = %u", tlsLength);
            if (tlsLength > sizeof(svritem->tlsdata))
            {
                OIC_LOG_V(ERROR, TAG, "toal tls length is too big (buffer size : %u)",
                                    sizeof(svritem->tlsdata));
775
                return CA_RECEIVE_FAILED;
776 777 778 779
            }
            nbRead = tlsLength - svritem->tlsLen;
        }

780
        len = recv(svritem->fd, (char*)svritem->tlsdata + svritem->tlsLen, (int)nbRead, 0);
781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798
        if (len < 0)
        {
            OIC_LOG_V(ERROR, TAG, "recv failed %s", strerror(errno));
            res = CA_RECEIVE_FAILED;
        }
        else if (0 == len)
        {
            OIC_LOG(INFO, TAG, "Received disconnect from peer. Close connection");
            res = CA_DESTINATION_DISCONNECTED;
        }
        else
        {
            svritem->tlsLen += len;
            OIC_LOG_V(DEBUG, TAG, "nb_read : %u bytes , recv() : %d bytes, svritem->tlsLen : %u bytes",
                                nbRead, len, svritem->tlsLen);
            if (tlsLength > 0 && tlsLength == svritem->tlsLen)
            {
                //when successfully read data - pass them to callback.
799
                res = CAdecryptSsl(&svritem->sep, (uint8_t *)svritem->tlsdata, (int)svritem->tlsLen);
800 801 802 803 804 805
                svritem->tlsLen = 0;
                OIC_LOG_V(DEBUG, TAG, "%s: CAdecryptSsl returned %d", __func__, res);
            }
        }
#endif

806 807 808
    }
    else
    {
809
        svritem->protocol = COAP;
Andrii Shtompel's avatar
Andrii Shtompel committed
810

811
        // svritem->tlsdata can also be used as receiving buffer in case of raw tcp
812
        len = recv(svritem->fd, (char*)svritem->tlsdata, sizeof(svritem->tlsdata), 0);
813 814 815 816 817 818
        if (len < 0)
        {
            OIC_LOG_V(ERROR, TAG, "recv failed %s", strerror(errno));
            res = CA_RECEIVE_FAILED;
        }
        else if (0 == len)
819
        {
820 821 822 823 824 825 826 827 828
            OIC_LOG(INFO, TAG, "Received disconnect from peer. Close connection");
            res = CA_DESTINATION_DISCONNECTED;
        }
        else
        {
            OIC_LOG_V(DEBUG, TAG, "recv() : %d bytes", len);
            //when successfully read data - pass them to callback.
            if (g_packetReceivedCallback)
            {
829
                g_packetReceivedCallback(&svritem->sep, svritem->tlsdata, len);
830
            }
831 832
        }
    }
Andrii Shtompel's avatar
Andrii Shtompel committed
833

834
    return res;
835 836
}

Dave Thaler's avatar
Dave Thaler committed
837
#if !defined(WSA_WAIT_EVENT_0)
838
static ssize_t CAWakeUpForReadFdsUpdate(const char *host)
839 840 841 842 843 844 845 846 847 848 849 850 851
{
    if (caglobals.tcp.connectionFds[1] != -1)
    {
        ssize_t len = 0;
        do
        {
            len = write(caglobals.tcp.connectionFds[1], host, strlen(host));
        } while ((len == -1) && (errno == EINTR));

        if ((len == -1) && (errno != EINTR) && (errno != EPIPE))
        {
            OIC_LOG_V(DEBUG, TAG, "write failed: %s", strerror(errno));
        }
852
        return len;
853
    }
854
    return -1;
855
}
856 857 858 859 860 861 862 863 864 865 866
#else
static void CAWakeUpForReadFdsUpdate()
{
    if (WSA_INVALID_EVENT != caglobals.tcp.updateEvent)
    {
        if (!WSASetEvent(caglobals.tcp.updateEvent))
        {
            OIC_LOG_V(DEBUG, TAG, "CAWakeUpForReadFdsUpdate: set shutdown event failed: %u", GetLastError());
        }
    }
}
Dave Thaler's avatar
Dave Thaler committed
867
#endif
868

869
static CAResult_t CATCPCreateSocket(int family, CATCPSessionInfo_t *svritem)
870
{
871
    VERIFY_NON_NULL(svritem, TAG, "svritem is NULL");
872 873 874 875

    OIC_LOG_V(DEBUG, TAG, "try to connect with [%s:%u]",
              svritem->sep.endpoint.addr, svritem->sep.endpoint.port);

876
    // #1. create tcp socket.
Dave Thaler's avatar
Dave Thaler committed
877 878
    CASocketFd_t fd = socket(family, SOCK_STREAM, IPPROTO_TCP);
    if (OC_INVALID_SOCKET == fd)
879 880
    {
        OIC_LOG_V(ERROR, TAG, "create socket failed: %s", strerror(errno));
881
        return CA_SOCKET_OPERATION_FAILED;
882
    }
883
    svritem->fd = fd;
884

885
    // #2. convert address from string to binary.
886
    struct sockaddr_storage sa = { .ss_family = (short)family };
Dave Thaler's avatar
Dave Thaler committed
887 888
    CAResult_t res = CAConvertNameToAddr(svritem->sep.endpoint.addr,
                                         svritem->sep.endpoint.port, &sa);
889 890
    if (CA_STATUS_OK != res)
    {
891
        OIC_LOG(ERROR, TAG, "convert name to sockaddr failed");
892
        return CA_SOCKET_OPERATION_FAILED;
893
    }
894

895
    // #3. set socket length.
896
    socklen_t socklen = 0;
897
    if (sa.ss_family == AF_INET6)
898
    {
899
        socklen = sizeof(struct sockaddr_in6);
900 901 902
    }
    else
    {
903
        socklen = sizeof(struct sockaddr_in);
904 905
    }

906 907
    // #4. connect to remote server device.
    if (connect(fd, (struct sockaddr *)&sa, socklen) < 0)
908
    {
909
        OIC_LOG_V(ERROR, TAG, "failed to connect socket, %s", strerror(errno));
910 911
        CALogSendStateInfo(svritem->sep.endpoint.adapter, svritem->sep.endpoint.addr,
                           svritem->sep.endpoint.port, 0, false, strerror(errno));
912
        return CA_SOCKET_OPERATION_FAILED;
913
    }
914 915

    OIC_LOG(DEBUG, TAG, "connect socket success");
916 917
    svritem->state = CONNECTED;
    CHECKFD(svritem->fd);
Dave Thaler's avatar
Dave Thaler committed
918
#if !defined(WSA_WAIT_EVENT_0)
919 920 921
    ssize_t len = CAWakeUpForReadFdsUpdate(svritem->sep.endpoint.addr);
    if (-1 == len)
    {
922
        OIC_LOG(ERROR, TAG, "wakeup receive thread failed");
923 924
        return CA_SOCKET_OPERATION_FAILED;
    }
925 926
#else
    CAWakeUpForReadFdsUpdate();
Dave Thaler's avatar
Dave Thaler committed
927
#endif
928
    return CA_STATUS_OK;
929 930
}

931
static CASocketFd_t CACreateAcceptSocket(int family, CASocket_t *sock)
932
{
Dave Thaler's avatar
Dave Thaler committed
933
    VERIFY_NON_NULL_RET(sock, TAG, "sock", OC_INVALID_SOCKET);
934

935
    if (OC_INVALID_SOCKET != sock->fd)
936 937
    {
        OIC_LOG(DEBUG, TAG, "accept socket created already");
938
        return sock->fd;
939 940
    }

941
    socklen_t socklen = 0;
942
    struct sockaddr_storage server = { .ss_family = (short)family };
943

Dave Thaler's avatar
Dave Thaler committed
944
    CASocketFd_t fd = socket(family, SOCK_STREAM, IPPROTO_TCP);
945
    if (OC_INVALID_SOCKET == fd)
946 947 948 949 950
    {
        OIC_LOG(ERROR, TAG, "Failed to create socket");
        goto exit;
    }

951 952
    if (family == AF_INET6)
    {
953
        // the socket is restricted to sending and receiving IPv6 packets only.
954
        int on = 1;
Dave Thaler's avatar
Dave Thaler committed
955
        if (OC_SOCKET_ERROR == setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, OPTVAL_T(&on), sizeof (on)))
956 957 958 959 960 961 962 963 964 965 966 967 968 969
        {
            OIC_LOG_V(ERROR, TAG, "IPV6_V6ONLY failed: %s", strerror(errno));
            goto exit;
        }
        ((struct sockaddr_in6 *)&server)->sin6_port = htons(sock->port);
        socklen = sizeof (struct sockaddr_in6);
    }
    else
    {
        ((struct sockaddr_in *)&server)->sin_port = htons(sock->port);
        socklen = sizeof (struct sockaddr_in);
    }

    int reuse = 1;
Dave Thaler's avatar
Dave Thaler committed
970
    if (OC_SOCKET_ERROR == setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, OPTVAL_T(&reuse), sizeof(reuse)))
971 972 973 974 975
    {
        OIC_LOG(ERROR, TAG, "setsockopt SO_REUSEADDR");
        goto exit;
    }

Dave Thaler's avatar
Dave Thaler committed
976
    if (OC_SOCKET_ERROR == bind(fd, (struct sockaddr *)&server, socklen))
977
    {
978
        OIC_LOG_V(ERROR, TAG, "bind socket failed: %s", strerror(errno));
979 980 981
        goto exit;
    }

982
    if (listen(fd, caglobals.tcp.listenBacklog) != 0)
983 984 985 986 987
    {
        OIC_LOG(ERROR, TAG, "listen() error");
        goto exit;
    }

988 989
    if (!sock->port)  // return the assigned port
    {
Dave Thaler's avatar
Dave Thaler committed
990
        if (OC_SOCKET_ERROR == getsockname(fd, (struct sockaddr *)&server, &socklen))
991 992 993 994 995 996 997 998
        {
            OIC_LOG_V(ERROR, TAG, "getsockname failed: %s", strerror(errno));
            goto exit;
        }
        sock->port = ntohs(family == AF_INET6 ?
                      ((struct sockaddr_in6 *)&server)->sin6_port :
                      ((struct sockaddr_in *)&server)->sin_port);
    }
999

1000
    return fd;
1001 1002

exit:
Dave Thaler's avatar
Dave Thaler committed
1003
    if (fd != OC_INVALID_SOCKET)
1004
    {
Dave Thaler's avatar
Dave Thaler committed
1005
        OC_CLOSE_SOCKET(fd);
1006
    }
1007
    return OC_INVALID_SOCKET;
1008 1009
}

Dave Thaler's avatar
Dave Thaler committed
1010
#if !defined(WSA_WAIT_EVENT_0)
1011
static void CAInitializePipe(int *fds)
1012
{
1013
    int ret = pipe(fds);
1014
    if (-1 != ret)
1015
    {
1016
        ret = fcntl(fds[0], F_GETFD);
1017
        if (-1 != ret)
1018
        {
1019
            ret = fcntl(fds[0], F_SETFD, ret|FD_CLOEXEC);
1020
        }
1021
        if (-1 != ret)
1022
        {
1023
            ret = fcntl(fds[1], F_GETFD);
1024
        }
1025
        if (-1 != ret)
1026
        {
1027
            ret = fcntl(fds[1], F_SETFD, ret|FD_CLOEXEC);