Replace glib threadpool usage with a 'dumb' thread implementation.
[platform/upstream/iotivity.git] / resource / csdk / connectivity / src / ethernet_adapter / linux / caethernetserver.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 // Defining _POSIX_C_SOURCE macro with 200809L (or greater) as value
22 // causes header files to expose definitions
23 // corresponding to the POSIX.1-2008 base
24 // specification (excluding the XSI extension).
25 // For POSIX.1-2008 base specification,
26 // Refer http://pubs.opengroup.org/stage7tc1/
27 //
28 // For this specific file, see use of strndup,
29 // Refer http://man7.org/linux/man-pages/man3/strdup.3.html
30 #ifndef _POSIX_C_SOURCE
31 #define _POSIX_C_SOURCE 200809L
32 #endif
33
34 // Defining _BSD_SOURCE or _DEFAULT_SOURCE causes header files to expose
35 // definitions that may otherwise be skipped. Skipping can cause implicit
36 // declaration warnings and/or bugs and subtle problems in code execution.
37 // For glibc information on feature test macros,
38 // Refer http://www.gnu.org/software/libc/manual/html_node/Feature-Test-Macros.html
39 //
40 // This file requires #define use due to struct ip_mreq
41 #define _DEFAULT_SOURCE
42 #define _BSD_SOURCE
43 #include <netinet/in.h>
44
45 #include "caethernetinterface.h"
46
47 #include <sys/types.h>
48 #include <sys/socket.h>
49 #include <unistd.h>
50 #include <fcntl.h>
51 #include <sys/select.h>
52 #include <arpa/inet.h>
53 #include <string.h>
54
55 #include <errno.h>
56
57 #include "pdu.h"
58 #include "caadapterutils.h"
59 #ifdef __WITH_DTLS__
60 #include "caadapternetdtls.h"
61 #endif
62 #include "camutex.h"
63 #include "oic_malloc.h"
64
65 // TODO g_stopSecureUnicast is set but never used. The three groups of
66 // globals should be combined into three instances of a common struct.
67
68 #define PIPE_READ_FD 0
69
70 #define PIPE_WRITE_FD 1
71
72 /**
73  * @def ETHERNET_SERVER_TAG
74  * @brief Logging tag for module name
75  */
76 #define ETHERNET_SERVER_TAG "ETHERNET_SERVER"
77
78 /**
79  * @def CA_UDP_BIND_RETRY_COUNT
80  * @brief Retry count in case of socket bind failure.
81  */
82 #define CA_UDP_BIND_RETRY_COUNT 10
83
84 /**
85  * @def IPNAMESIZE
86  * @brief max length for ip
87  */
88 #define IPNAMESIZE 16
89
90 /**
91  * @var g_unicastServerSocketFD
92  * @brief Unicast server socket descriptor
93  */
94 static int32_t g_unicastServerSocketFD = -1;
95
96 /**
97  * @var g_mutexUnicastServer
98  * @brief Mutex to synchronize unicast server
99  */
100 static ca_mutex g_mutexUnicastServer = NULL;
101
102 /**
103  * @var g_stopUnicast
104  * @brief Flag to control the Receive Unicast Data Thread
105  */
106 static bool g_stopUnicast = false;
107
108 /**
109  * Handle to interrupt unicast server for stopping, etc.
110  */
111 static int g_unicastTriggerFD = -1;
112
113 /**
114  * @var g_multicastServerSocketFD
115  * @brief socket descriptor for multicast server
116  */
117 static int32_t g_multicastServerSocketFD = -1;
118
119 /**
120  * @var g_mutexMulticastServer
121  * @brief Mutex to synchronize secure multicast server
122  */
123 static ca_mutex g_mutexMulticastServer = NULL;
124
125 /**
126  * @var g_stopMulticast
127  * @brief Flag to control the Receive Multicast Data Thread
128  */
129 static bool g_stopMulticast = false;
130
131 /**
132  * Handle to interrupt multicast server for stopping, etc.
133  */
134 static int g_multicastTriggerFD = -1;
135
136 #ifdef __WITH_DTLS__
137 /**
138  * @var g_secureUnicastServerSocketFD
139  * @brief Secure unicast server socket descriptor
140  */
141 static int32_t g_secureUnicastServerSocketFD = -1;
142
143 /**
144  * @var g_mutexSecureUnicastServer
145  * @brief Mutex to synchronize secure unicast server
146  */
147 static ca_mutex g_mutexSecureUnicastServer = NULL;
148
149 /**
150  * @var g_stopSecureUnicast
151  * @brief Flag to control the unicast secure data receive thread
152  */
153 static bool g_stopSecureUnicast = false;
154 #endif
155
156 /**
157  * @var g_threadPool
158  * @brief ThreadPool for storing ca_thread_pool_t handle passed from adapter
159  */
160 static ca_thread_pool_t g_threadPool = NULL;
161
162 /**
163  * @var g_multicastServerInterface
164  * @brief Local interface on which multicast server is running
165  */
166 static char g_multicastServerInterface[IPNAMESIZE];
167
168 /**
169  * @var g_multicastMemberReq
170  * @brief ip_mreq structure passed to join a multicast group
171  */
172 static struct ip_mreq g_multicastMemberReq;
173
174 /**
175  * @var g_packetReceivedCallback
176  * @brief Callback for notifying the upper layer on receival data from remote OIC device
177  */
178 static CAEthernetPacketReceivedCallback g_packetReceivedCallback = NULL;
179
180 /**
181  * @var g_exceptionCallback
182  * @brief Callback for notifying the upper layer when unicast/multicast server encounters exception
183  */
184 static CAEthernetExceptionCallback g_exceptionCallback = NULL;
185
186 /**
187  @brief Thread context information for unicast, multicast and secured unicast server
188  */
189 typedef struct
190 {
191     bool *stopFlag;
192     int stopFd;
193     int32_t socket_fd;
194     CAAdapterServerType_t type;
195 } CAAdapterReceiveThreadContext_t;
196
197 /**
198  * Creates a non-blocking pipe.
199  *
200  * Creates a pipe with two file descriptors then sets both to be
201  * non-blocking. If an error occurs setting flags, any created handles
202  * will be closed and set to -1.
203  *
204  * @param pipefd array of two ints to store the pipe handles in.
205  *
206  * @return 0 on success, -1 otherwise.
207  */
208 static int createNonblockingPipe(int pipefd[2]);
209
210 /**
211  * Sets the given file descriptor to be non-blocking.
212  *
213  * @param fd the file descriptor to make non-blocking.
214  *
215  * @return 0 on success, -1 otherwise.
216  */
217 static int setNonblocking(int fd);
218
219 static void CAReceiveHandler(void *data)
220 {
221     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "IN");
222
223     // Input validation
224     VERIFY_NON_NULL_VOID(data, ETHERNET_SERVER_TAG, "Invalid thread context");
225
226     CAAdapterReceiveThreadContext_t *ctx = (CAAdapterReceiveThreadContext_t *)data;
227     fd_set reads;
228     struct timeval timeout;
229     char recvBuffer[COAP_MAX_PDU_SIZE] = {0};
230
231     while (true != *(ctx->stopFlag))
232     {
233         // safe to set longer value as select can be interrupted.
234         timeout.tv_sec = 10;
235         timeout.tv_usec = 0;
236
237         FD_ZERO(&reads);
238         FD_SET(ctx->socket_fd, &reads);
239         int highest = (ctx->stopFd > ctx->socket_fd) ? ctx->stopFd : ctx->socket_fd;
240         if (ctx->stopFd != -1)
241         {
242             FD_SET(ctx->stopFd, &reads);
243         }
244
245         int32_t ret = select(highest + 1, &reads, NULL, NULL, &timeout);
246         if (*(ctx->stopFlag) == true)
247         {
248             OIC_LOG_V(DEBUG, ETHERNET_SERVER_TAG,
249                 "Stop request received for [%d] server", ctx->type);
250             break;
251         }
252
253         if (ret < 0)
254         {
255             OIC_LOG_V(FATAL, ETHERNET_SERVER_TAG, "select returned error %s", strerror(errno));
256             continue;
257         }
258
259         if ((ctx->stopFd != -1) && FD_ISSET(ctx->stopFd, &reads))
260         {
261             // Doesn't matter at this point what happens (errors can be
262             // ignored). Just drain some data if this code ever gets hit.
263             recv(ctx->stopFd, recvBuffer, sizeof(recvBuffer), MSG_DONTWAIT);
264         }
265
266         if (!FD_ISSET(ctx->socket_fd, &reads))
267         {
268             continue;
269         }
270
271         memset(recvBuffer, 0, sizeof(recvBuffer));
272
273         // Read data from socket
274         struct sockaddr_in srcSockAddress;
275         int32_t recvLen;
276         socklen_t srcAddressLen = sizeof(srcSockAddress);
277
278         recvLen = recvfrom(ctx->socket_fd, recvBuffer,
279                                       sizeof(recvBuffer), 0, (struct sockaddr *) &srcSockAddress,
280                                       &srcAddressLen);
281
282         if (-1 == recvLen)
283         {
284             OIC_LOG_V(DEBUG, ETHERNET_SERVER_TAG, "%s", strerror(errno));
285             continue;
286         }
287         else if (0 == recvLen)
288         {
289             OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Server socket shutdown [%d]!", ctx->type);
290
291             // Notify upper layer this exception
292             if (g_exceptionCallback)
293             {
294                 g_exceptionCallback(ctx->type);
295             }
296             if (ctx->stopFd != -1)
297             {
298                 close(ctx->stopFd);
299             }
300             OICFree(ctx);
301             ctx = NULL;
302             return;
303         }
304
305         char srcIPAddress[CA_IPADDR_SIZE] = {0};
306         inet_ntop(AF_INET, &srcSockAddress.sin_addr.s_addr, srcIPAddress, sizeof(srcIPAddress));
307         uint16_t srcPort = 0;
308         srcPort = ntohs(srcSockAddress.sin_port);
309
310         OIC_LOG_V(DEBUG, ETHERNET_SERVER_TAG, "Received packet from %s:%d\n",
311                   srcIPAddress, srcPort);
312         OIC_LOG_V(DEBUG, ETHERNET_SERVER_TAG, "Data: %s\t, DataLength: %d\n",
313                   recvBuffer, recvLen);
314
315         char *netMask = NULL;
316         if (CA_STATUS_OK != CAEthernetGetInterfaceSubnetMask(&netMask))
317         {
318             OIC_LOG(ERROR, ETHERNET_SERVER_TAG, "Failed to get ethernet subnet");
319             continue;
320         }
321
322         if (!CAAdapterIsSameSubnet(g_multicastServerInterface, srcIPAddress, netMask))
323         {
324             OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "Packet received from different subnet, Ignore!");
325             if (NULL != netMask)
326             {
327                 OICFree(netMask);
328             }
329             netMask = NULL;
330             continue;
331         }
332
333         OICFree(netMask);
334         switch (ctx->type)
335         {
336             case CA_UNICAST_SERVER:
337             case CA_MULTICAST_SERVER:
338                 // Notify data to upper layer
339                 if (g_packetReceivedCallback)
340                 {
341                     g_packetReceivedCallback(srcIPAddress, srcPort, recvBuffer, recvLen, false);
342                 }
343                 break;
344 #ifdef __WITH_DTLS__
345             case CA_SECURED_UNICAST_SERVER:
346                 {
347                     CAResult_t ret = CAAdapterNetDtlsDecrypt(srcIPAddress,
348                                      srcPort,
349                                      (uint8_t *)recvBuffer,
350                                      recvLen, DTLS_ETHERNET);
351                     OIC_LOG_V(DEBUG, ETHERNET_SERVER_TAG,
352                         "CAAdapterNetDtlsDecrypt returns [%d]", ret);
353                 }
354                 break;
355 #endif //__WITH_DTLS__
356             default:
357                 // Should never occur
358                 OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "Invalid server type");
359                 if (ctx->stopFd != -1)
360                 {
361                     close(ctx->stopFd);
362                 }
363                 OICFree(ctx);
364                 ctx = NULL;
365                 return;
366         }
367     }
368
369     if (ctx->stopFd != -1)
370     {
371         close(ctx->stopFd);
372     }
373     OICFree(ctx);
374     ctx = NULL;
375
376
377     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "OUT");
378 }
379
380 static CAResult_t CACreateSocket(int32_t *socketFD, const char *localIp, uint16_t *port,
381                                  bool forceStart)
382 {
383     int32_t sock = -1;
384     // Create a UDP socket
385     sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
386     if (-1 == sock)
387     {
388         OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Failed to create Socket, Error code: %s",
389                   strerror(errno));
390         return CA_STATUS_FAILED;
391     }
392
393     // Make the socket non-blocking
394     if (-1 == setNonblocking(sock))
395     {
396         close(sock);
397         return CA_STATUS_FAILED;
398     }
399
400     if (true == forceStart)
401     {
402         int32_t setOptionOn = 1;
403         if (-1 == setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
404                              (char *) &setOptionOn,
405                              sizeof(setOptionOn)))
406         {
407             OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Failed to set SO_REUSEADDR! Error code: %s",
408                       strerror(errno));
409
410             close(sock);
411             return CA_STATUS_FAILED;
412         }
413     }
414
415     struct sockaddr_in sockAddr;
416     bool isBound = false;
417     uint16_t serverPort = *port;
418
419     memset(&sockAddr, 0, sizeof(sockAddr));
420     sockAddr.sin_family = AF_INET;
421     sockAddr.sin_port = htons(serverPort);
422     if (localIp)
423     {
424         sockAddr.sin_addr.s_addr = inet_addr(localIp);
425     }
426     else
427     {
428         sockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
429     }
430
431     int16_t i;
432     for (i = 0; i < CA_UDP_BIND_RETRY_COUNT; i++)
433     {
434         if (-1 == bind(sock, (struct sockaddr *) &sockAddr,
435                        sizeof(sockAddr)))
436         {
437             if (false == forceStart)
438             {
439                 OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Failed to bind socket[%s]. Trying again..",
440                           strerror(errno));
441
442                 //Set the port to next one
443                 serverPort += 1;
444                 sockAddr.sin_port = htons(serverPort);
445                 continue;
446             }
447             else
448             {
449                 OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Failed to bind socket[%s]!",
450                           strerror(errno));
451                 break;
452             }
453         }
454
455         isBound = true;
456         break;
457     }
458
459     if (false == isBound)
460     {
461         close(sock);
462         return CA_STATUS_FAILED;
463     }
464
465     *port = serverPort;
466     *socketFD = sock;
467     return CA_STATUS_OK;
468 }
469
470 static CAResult_t CACloseSocket(int32_t *socketFD)
471 {
472     if (socketFD == NULL)
473     {
474         return CA_STATUS_INVALID_PARAM;
475     }
476
477     if (-1 == *socketFD)
478     {
479         OIC_LOG(INFO, ETHERNET_SERVER_TAG, "Server not running");
480         return CA_SERVER_NOT_STARTED;
481     }
482
483     // close the socket
484     if (-1 == close(*socketFD))
485     {
486         OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Failed to close the socket, Error code: %s\n",
487                   strerror(errno));
488         return CA_STATUS_FAILED;
489     }
490
491     *socketFD = -1;
492     return CA_STATUS_OK;
493 }
494
495 static CAResult_t CAStartUnicastServer(const char *localAddress, uint16_t *port,
496                                        const bool forceStart, bool isSecured, int32_t *serverFD)
497 {
498     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "IN");
499
500     if (serverFD == NULL)
501     {
502         return CA_STATUS_INVALID_PARAM;
503     }
504
505     CAResult_t ret = CACreateSocket(serverFD, localAddress, port, forceStart);
506     if (CA_STATUS_OK != ret)
507     {
508         OIC_LOG(ERROR, ETHERNET_SERVER_TAG, "Failed to create unicast socket");
509         return ret;
510     }
511
512     /**
513       * The task to listen for data from unicast socket is added to the thread pool.
514       * This is a blocking call is made where we try to receive some data..
515       * We will keep waiting until some data is received.
516       * This task will be terminated when thread pool is freed on stopping the adapters.
517       * Thread context will be freed by thread on exit.
518       */
519     CAAdapterReceiveThreadContext_t *ctx = (CAAdapterReceiveThreadContext_t *)
520                                            OICMalloc(sizeof(CAAdapterReceiveThreadContext_t));
521     if (!ctx)
522     {
523         OIC_LOG(ERROR, ETHERNET_SERVER_TAG, "Out of memory!");
524         close(*serverFD);
525         return CA_MEMORY_ALLOC_FAILED;
526     }
527
528     int pipefd[2] = {-1, -1};
529     if (createNonblockingPipe(pipefd) != 0)
530     {
531         OIC_LOG(ERROR, ETHERNET_SERVER_TAG, "Failed to create pipe");
532         OICFree(ctx);
533         close(*serverFD);
534         *serverFD = -1;
535         return CA_STATUS_FAILED;
536     }
537
538     g_unicastTriggerFD = pipefd[PIPE_WRITE_FD]; // The write end of the pipe
539
540     ctx->stopFlag = &g_stopUnicast;
541     ctx->stopFd = pipefd[PIPE_READ_FD]; // The read end of the pipe
542     ctx->socket_fd = *serverFD;
543     ctx->type = isSecured ? CA_SECURED_UNICAST_SERVER : CA_UNICAST_SERVER;
544     if (CA_STATUS_OK != ca_thread_pool_add_task(g_threadPool, CAReceiveHandler, (void *)ctx))
545     {
546         OIC_LOG(ERROR, ETHERNET_SERVER_TAG, "Failed to create read thread!");
547
548         close(g_unicastTriggerFD);
549         g_unicastTriggerFD = -1;
550         close(ctx->stopFd);
551         ctx->stopFd = -1;
552
553         OICFree(ctx);
554         close(*serverFD);
555         *serverFD = -1;
556         return CA_STATUS_FAILED;
557     }
558
559     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "OUT");
560     return CA_STATUS_OK;
561 }
562
563 static void CAEthernetServerDestroyMutex(void)
564 {
565     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "IN");
566
567     if (g_mutexUnicastServer)
568     {
569         ca_mutex_free(g_mutexUnicastServer);
570         g_mutexUnicastServer = NULL;
571     }
572
573 #ifdef __WITH_DTLS__
574     if (g_mutexSecureUnicastServer)
575     {
576         ca_mutex_free(g_mutexSecureUnicastServer);
577         g_mutexSecureUnicastServer = NULL;
578     }
579 #endif
580
581     if (g_mutexMulticastServer)
582     {
583         ca_mutex_free(g_mutexMulticastServer);
584         g_mutexMulticastServer = NULL;
585     }
586
587     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "OUT");
588 }
589
590 static CAResult_t CAEthernetServerCreateMutex(void)
591 {
592     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "IN");
593
594     if(g_mutexUnicastServer) {
595         OIC_LOG(ERROR, ETHERNET_SERVER_TAG, "mutex is already created!");
596
597         OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "OUT");
598         return CA_STATUS_FAILED;
599     }
600
601     g_mutexUnicastServer = ca_mutex_new();
602     if (!g_mutexUnicastServer)
603     {
604         OIC_LOG(ERROR, ETHERNET_SERVER_TAG, "Failed to created mutex!");
605         return CA_STATUS_FAILED;
606     }
607
608 #ifdef __WITH_DTLS__
609     g_mutexSecureUnicastServer = ca_mutex_new();
610     if (!g_mutexSecureUnicastServer)
611     {
612         OIC_LOG(ERROR, ETHERNET_SERVER_TAG, "Failed to created mutex!");
613
614         CAEthernetServerDestroyMutex();
615         return CA_STATUS_FAILED;
616     }
617 #endif
618
619     g_mutexMulticastServer = ca_mutex_new();
620     if (!g_mutexMulticastServer)
621     {
622         OIC_LOG(ERROR, ETHERNET_SERVER_TAG, "Failed to created mutex!");
623
624         CAEthernetServerDestroyMutex();
625         return CA_STATUS_FAILED;
626     }
627
628     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "OUT");
629     return CA_STATUS_OK;
630 }
631
632 CAResult_t CAEthernetInitializeServer(const ca_thread_pool_t threadPool)
633 {
634     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "IN");
635
636     // Input validation
637     VERIFY_NON_NULL(threadPool, ETHERNET_SERVER_TAG, "Thread pool handle is NULL");
638
639     // Initialize mutex
640     if (CA_STATUS_OK != CAEthernetServerCreateMutex())
641     {
642         OIC_LOG(ERROR, ETHERNET_SERVER_TAG, "Failed to create mutex!");
643         return CA_STATUS_FAILED;
644     }
645
646     g_threadPool = threadPool;
647
648     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "OUT");
649     return CA_STATUS_OK;
650 }
651
652 void CAEthernetTerminateServer(void)
653 {
654     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "IN");
655
656     g_threadPool = NULL;
657
658     // Destroy mutex
659     CAEthernetServerDestroyMutex();
660
661     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "OUT");
662 }
663
664 CAResult_t CAEthernetStartUnicastServer(const char *localAddress, uint16_t *port,
665                                         bool forceStart, bool isSecured, int32_t *serverFD)
666 {
667     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "IN");
668
669     // Input validation
670     VERIFY_NON_NULL(localAddress, ETHERNET_SERVER_TAG, "localAddress");
671     VERIFY_NON_NULL(port, ETHERNET_SERVER_TAG, "port");
672     VERIFY_NON_NULL(serverFD, ETHERNET_SERVER_TAG, "server socket FD");
673
674     if (0 >= *port)
675     {
676         OIC_LOG(ERROR, ETHERNET_SERVER_TAG, "Invalid input: port is invalid!");
677         return CA_STATUS_INVALID_PARAM;
678     }
679
680     *serverFD = -1;
681     if (false == isSecured)
682     {
683         ca_mutex_lock(g_mutexUnicastServer);
684         if (-1 != g_unicastServerSocketFD)
685         {
686             OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Unicast Server is Started Already!",
687                       CA_SERVER_STARTED_ALREADY);
688
689             *serverFD = g_unicastServerSocketFD;
690             ca_mutex_unlock(g_mutexUnicastServer);
691             return CA_SERVER_STARTED_ALREADY;
692         }
693
694         g_stopUnicast = false;
695         if (CA_STATUS_OK != CAStartUnicastServer(localAddress, port, forceStart, isSecured,
696                 &g_unicastServerSocketFD))
697         {
698             OIC_LOG(ERROR, ETHERNET_SERVER_TAG, "Failed to start unicast server!");
699             g_unicastServerSocketFD = -1;
700             ca_mutex_unlock(g_mutexUnicastServer);
701             return CA_STATUS_FAILED;
702         }
703
704         *serverFD = g_unicastServerSocketFD;
705         ca_mutex_unlock(g_mutexUnicastServer);
706     }
707 #ifdef __WITH_DTLS__
708     else // Start unicast server for secured communication
709     {
710         ca_mutex_lock(g_mutexSecureUnicastServer);
711         if (-1 != g_secureUnicastServerSocketFD)
712         {
713             OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Unicast Server is Started Already!",
714                       CA_SERVER_STARTED_ALREADY);
715
716             *serverFD = g_secureUnicastServerSocketFD;
717             ca_mutex_unlock(g_mutexSecureUnicastServer);
718             return CA_SERVER_STARTED_ALREADY;
719         }
720
721         g_stopSecureUnicast = false;
722         if (CA_STATUS_OK != CAStartUnicastServer(localAddress, port, forceStart, isSecured,
723                 &g_secureUnicastServerSocketFD))
724         {
725             OIC_LOG(ERROR, ETHERNET_SERVER_TAG, "Failed to start unicast server!");
726             g_secureUnicastServerSocketFD = -1;
727             ca_mutex_unlock(g_mutexSecureUnicastServer);
728             return CA_STATUS_FAILED;
729         }
730
731         *serverFD = g_secureUnicastServerSocketFD;
732         ca_mutex_unlock(g_mutexSecureUnicastServer);
733     }
734 #endif
735     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "OUT");
736     return CA_STATUS_OK;
737 }
738
739 CAResult_t CAEthernetStartMulticastServer(const char *localAddress,
740     const char *multicastAddress, const uint16_t multicastPort, int32_t *serverFD)
741 {
742     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "IN");
743
744     // Input validation
745     VERIFY_NON_NULL(localAddress, ETHERNET_SERVER_TAG, "localAddress");
746     VERIFY_NON_NULL(multicastAddress, ETHERNET_SERVER_TAG, "port");
747     VERIFY_NON_NULL(serverFD, ETHERNET_SERVER_TAG, "server socket FD");
748
749     uint16_t port = multicastPort;
750     if (0 >= port)
751     {
752         OIC_LOG(ERROR, ETHERNET_SERVER_TAG, "Invalid input: Multicast port is invalid!");
753         return CA_STATUS_INVALID_PARAM;
754     }
755
756     ca_mutex_lock(g_mutexMulticastServer);
757
758     if (g_multicastServerSocketFD != -1)
759     {
760         OIC_LOG(ERROR, ETHERNET_SERVER_TAG, "Multicast Server is already running!");
761         ca_mutex_unlock(g_mutexMulticastServer);
762         return CA_SERVER_STARTED_ALREADY;
763     }
764
765     CAResult_t ret = CACreateSocket(&g_multicastServerSocketFD, multicastAddress, &port, true);
766     if (ret != CA_STATUS_OK)
767     {
768         OIC_LOG(ERROR, ETHERNET_SERVER_TAG, "Failed to create multicast socket");
769         ca_mutex_unlock(g_mutexMulticastServer);
770         return ret;
771     }
772
773     // Add membership to receiving socket (join group)
774     memset(&g_multicastMemberReq, 0, sizeof(struct ip_mreq));
775     g_multicastMemberReq.imr_interface.s_addr = inet_addr(localAddress);
776     inet_aton(multicastAddress, &g_multicastMemberReq.imr_multiaddr);
777
778     if (-1 == setsockopt(g_multicastServerSocketFD, IPPROTO_IP, IP_ADD_MEMBERSHIP,
779                          (char *) &g_multicastMemberReq,
780                          sizeof(struct ip_mreq)))
781     {
782         OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Failed to add to multicast group, Error code: %s\n",
783                   strerror(errno));
784         close(g_multicastServerSocketFD);
785         g_multicastServerSocketFD = -1;
786         ca_mutex_unlock(g_mutexMulticastServer);
787         return CA_STATUS_FAILED;
788     }
789
790     /**
791       * The task to listen to data from multicastcast socket is added to the thread pool.
792       * This is a blocking call is made where we try to receive some data.
793       * We will keep waiting until some data is received.
794       * This task will be terminated when thread pool is freed on stopping the adapters.
795       * Thread context will be freed by thread on exit.
796       */
797     CAAdapterReceiveThreadContext_t *ctx = (CAAdapterReceiveThreadContext_t *)
798                                            OICMalloc(sizeof(CAAdapterReceiveThreadContext_t));
799     if (!ctx)
800     {
801         OIC_LOG(ERROR, ETHERNET_SERVER_TAG, "Out of memory!");
802         close(g_multicastServerSocketFD);
803         g_multicastServerSocketFD = -1;
804         return CA_MEMORY_ALLOC_FAILED;
805     }
806
807     int pipefd[2] = {-1, -1};
808     if (createNonblockingPipe(pipefd) != 0)
809     {
810         OIC_LOG(ERROR, ETHERNET_SERVER_TAG, "Failed to create pipe");
811         OICFree(ctx);
812         close(g_multicastServerSocketFD);
813         g_multicastServerSocketFD = -1;
814         return CA_STATUS_FAILED;
815     }
816
817     g_multicastTriggerFD = pipefd[PIPE_WRITE_FD]; // The write end of the pipe
818
819     ctx->stopFlag = &g_stopMulticast;
820     ctx->stopFd = pipefd[PIPE_READ_FD]; // The read end of the pipe
821     ctx->socket_fd = g_multicastServerSocketFD;
822     ctx->type = CA_MULTICAST_SERVER;
823
824     g_stopMulticast = false;
825     if (CA_STATUS_OK != ca_thread_pool_add_task(g_threadPool, CAReceiveHandler, (void *)ctx))
826     {
827         OIC_LOG(ERROR, ETHERNET_SERVER_TAG, "thread_pool_add_task failed!");
828
829         close(g_multicastTriggerFD);
830         g_multicastTriggerFD = -1;
831         close(ctx->stopFd);
832         ctx->stopFd = -1;
833
834         close(g_multicastServerSocketFD);
835         g_multicastServerSocketFD = -1;
836         g_stopMulticast = true;
837         ca_mutex_unlock(g_mutexMulticastServer);
838         return CA_STATUS_FAILED;
839     }
840
841     *serverFD = g_multicastServerSocketFD;
842     strncpy(g_multicastServerInterface, localAddress, IPNAMESIZE);
843     ca_mutex_unlock(g_mutexMulticastServer);
844
845     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "OUT");
846     return CA_STATUS_OK;
847 }
848
849 CAResult_t CAEthernetStopUnicastServer()
850 {
851     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "IN");
852
853     ca_mutex_lock(g_mutexUnicastServer);
854     g_stopUnicast = true;
855     if (g_unicastTriggerFD != -1)
856     {
857         if (write(g_unicastTriggerFD, "X", 1) == -1)
858         {
859             OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG,
860                       "Failed to write to trigger, Error code: %s",
861                       strerror(errno));
862         }
863         close(g_unicastTriggerFD);
864         g_unicastTriggerFD = -1;
865     }
866     CAResult_t ret = CACloseSocket(&g_unicastServerSocketFD);
867     g_unicastServerSocketFD = -1;
868     ca_mutex_unlock(g_mutexUnicastServer);
869
870     OIC_LOG_V(INFO, ETHERNET_SERVER_TAG, "Unicast server stopped [%d]", ret);
871     return ret;
872 }
873
874 #ifdef __WITH_DTLS__
875 CAResult_t CAEthernetStopSecureUnicastServer()
876 {
877     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "IN");
878
879     ca_mutex_lock(g_mutexSecureUnicastServer);
880     g_stopSecureUnicast = true;
881     if (g_unicastTriggerFD != -1)
882     {
883         if (write(g_unicastTriggerFD, "X", 1) == -1)
884         {
885             OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG,
886                       "Failed to write to trigger, Error code: %s",
887                       strerror(errno));
888         }
889         close(g_unicastTriggerFD);
890         g_unicastTriggerFD = -1;
891     }
892     CAResult_t ret = CACloseSocket(&g_secureUnicastServerSocketFD);
893     ca_mutex_unlock(g_mutexSecureUnicastServer);
894
895     OIC_LOG_V(INFO, ETHERNET_SERVER_TAG, "Secured unicast server stopped [%d]", ret);
896     return ret;
897 }
898 #endif
899
900 CAResult_t CAEthernetStopMulticastServer(void)
901 {
902     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "IN");
903
904     ca_mutex_lock(g_mutexMulticastServer);
905
906     if (g_multicastServerSocketFD == -1)
907     {
908         OIC_LOG(INFO, ETHERNET_SERVER_TAG, "Multicast server is not yet started");
909         ca_mutex_unlock(g_mutexMulticastServer);
910         return CA_SERVER_NOT_STARTED;
911     }
912
913     g_stopMulticast = true;
914     if (g_multicastTriggerFD != -1)
915     {
916         if (write(g_multicastTriggerFD, "X", 1) == -1)
917         {
918             OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG,
919                       "Failed to write to trigger, Error code: %s",
920                       strerror(errno));
921         }
922         close(g_multicastTriggerFD);
923         g_multicastTriggerFD = -1;
924     }
925
926     // leave the group after you are done
927     if (-1 == setsockopt(g_multicastServerSocketFD, IPPROTO_IP, IP_DROP_MEMBERSHIP,
928                          (char *)&g_multicastMemberReq,
929                          sizeof(struct ip_mreq)))
930     {
931         OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Failed to leave multicast group, Error code: %s\n",
932                   strerror(errno));
933     }
934
935     CAResult_t ret = CACloseSocket(&g_multicastServerSocketFD);
936     ca_mutex_unlock(g_mutexMulticastServer);
937
938     OIC_LOG_V(INFO, ETHERNET_SERVER_TAG, "Multicast server stopped [%d]", ret);
939     return ret;
940 }
941
942 CAResult_t CAEthernetGetUnicastServerInfo(bool isSecured,
943     char **ipAddress, uint16_t *port, int32_t *serverFD)
944 {
945     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "IN");
946
947     // Input validation
948     VERIFY_NON_NULL(ipAddress, ETHERNET_SERVER_TAG, "IP address");
949     VERIFY_NON_NULL(port, ETHERNET_SERVER_TAG, "Port");
950     VERIFY_NON_NULL(serverFD, ETHERNET_SERVER_TAG, "Server ID");
951
952     struct sockaddr_in sockAddr;
953     socklen_t len = sizeof(struct sockaddr_in);
954     if (-1 == getsockname(g_unicastServerSocketFD, (struct sockaddr *)&sockAddr, &len))
955     {
956         OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Failed in getsockname [%s]!", strerror(errno));
957         return CA_STATUS_FAILED;
958     }
959
960
961     const char *serverAddress = inet_ntoa(sockAddr.sin_addr);
962     *ipAddress = (serverAddress) ? strndup(serverAddress, strlen(serverAddress)) : NULL;
963     *port = ntohs(sockAddr.sin_port);
964 #ifdef __WITH_DTLS__
965     *serverFD = (true == isSecured) ? g_secureUnicastServerSocketFD : g_unicastServerSocketFD;
966 #else
967     *serverFD = g_unicastServerSocketFD;
968 #endif
969
970     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "OUT");
971     return CA_STATUS_OK;
972 }
973
974 void CAEthernetSetPacketReceiveCallback(CAEthernetPacketReceivedCallback callback)
975 {
976     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "IN");
977     g_packetReceivedCallback = callback;
978     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "OUT");
979 }
980
981 void CAEthernetSetExceptionCallback(CAEthernetExceptionCallback callback)
982 {
983     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "IN");
984     g_exceptionCallback = callback;
985     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "OUT");
986 }
987
988 int setNonblocking(int fd)
989 {
990     int rc = fcntl(fd, F_GETFL);
991     if (rc == -1)
992     {
993         OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG,
994                   "Failed to get existing flags, Error code: %s",
995                   strerror(errno));
996     }
997     else
998     {
999         rc = fcntl(fd, F_SETFL, rc | O_NONBLOCK);
1000         if (rc == -1)
1001         {
1002             OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG,
1003                       "Failed to set non-blocking mode, Error code: %s",
1004                       strerror(errno));
1005         }
1006     }
1007
1008     return rc;
1009 }
1010
1011 int createNonblockingPipe(int pipefd[2])
1012 {
1013     int rc = -1;
1014     if (pipefd)
1015     {
1016         pipefd[PIPE_READ_FD] = -1;
1017         pipefd[PIPE_WRITE_FD] = -1;
1018         rc = pipe(pipefd);
1019
1020         if (rc != -1)
1021         {
1022             rc = setNonblocking(pipefd[PIPE_READ_FD]);
1023         }
1024
1025         if (rc != -1)
1026         {
1027             rc = setNonblocking(pipefd[PIPE_WRITE_FD]);
1028         }
1029
1030         if (rc == -1)
1031         {
1032             if (pipefd[PIPE_READ_FD] != -1)
1033             {
1034                 close(pipefd[PIPE_READ_FD]);
1035                 pipefd[PIPE_READ_FD] = -1;
1036             }
1037             if (pipefd[PIPE_WRITE_FD] != -1)
1038             {
1039                 close(pipefd[PIPE_WRITE_FD]);
1040                 pipefd[PIPE_WRITE_FD]= -1;
1041             }
1042         }
1043     }
1044     return rc;
1045 }