Added connectivity files for full code review
[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 #include "caethernetinterface.h"
21
22 #include <sys/types.h>
23 #include <sys/socket.h>
24 #include <unistd.h>
25 #include <fcntl.h>
26 #include <sys/select.h>
27 #include <arpa/inet.h>
28 #include <netinet/in.h>
29 #include <errno.h>
30
31 #include "pdu.h"
32 #include "caadapterutils.h"
33 #ifdef __WITH_DTLS__
34 #include "caadapternetdtls.h"
35 #endif
36 #include "umutex.h"
37 #include "oic_malloc.h"
38
39 /**
40  * @def ETHERNET_SERVER_TAG
41  * @brief Logging tag for module name
42  */
43 #define ETHERNET_SERVER_TAG "ETHERNET_SERVER"
44
45 /**
46  * @def CA_UDP_BIND_RETRY_COUNT
47  * @brief Retry count in case of socket bind failure.
48  */
49 #define CA_UDP_BIND_RETRY_COUNT 10
50
51 /**
52  * @def IPNAMESIZE
53  * @brief max length for ip
54  */
55 #define IPNAMESIZE 16
56
57 /**
58  * @var g_unicastServerSocketFD
59  * @brief Unicast server socket descriptor
60  */
61 static int32_t g_unicastServerSocketFD = -1;
62
63 /**
64  * @var g_mutexUnicastServer
65  * @brief Mutex to synchronize unicast server
66  */
67 static u_mutex g_mutexUnicastServer = NULL;
68
69 /**
70  * @var g_stopUnicast
71  * @brief Flag to control the Receive Unicast Data Thread
72  */
73 static bool g_stopUnicast = false;
74
75 /**
76  * @var g_multicastServerSocketFD
77  * @brief socket descriptor for multicast server
78  */
79 static int32_t g_multicastServerSocketFD = -1;
80
81 /**
82  * @var g_mutexMulticastServer
83  * @brief Mutex to synchronize secure multicast server
84  */
85 static u_mutex g_mutexMulticastServer = NULL;
86
87 /**
88  * @var g_stopMulticast
89  * @brief Flag to control the Receive Multicast Data Thread
90  */
91 static bool g_stopMulticast = false;
92
93 #ifdef __WITH_DTLS__
94 /**
95  * @var g_secureUnicastServerSocketFD
96  * @brief Secure unicast server socket descriptor
97  */
98 static int32_t g_secureUnicastServerSocketFD = -1;
99
100 /**
101  * @var g_mutexSecureUnicastServer
102  * @brief Mutex to synchronize secure unicast server
103  */
104 static u_mutex g_mutexSecureUnicastServer = NULL;
105
106 /**
107  * @var g_stopSecureUnicast
108  * @brief Flag to control the unicast secure data receive thread
109  */
110 static bool g_stopSecureUnicast = false;
111 #endif
112
113 /**
114  * @var g_threadPool
115  * @brief ThreadPool for storing u_thread_pool_t handle passed from adapter
116  */
117 static u_thread_pool_t g_threadPool = NULL;
118
119 /**
120  * @var g_multicastServerInterface
121  * @brief Local interface on which multicast server is running
122  */
123 static char g_multicastServerInterface[IPNAMESIZE];
124
125 /**
126  * @var g_multicastMemberReq
127  * @brief ip_mreq structure passed to join a multicast group
128  */
129 static struct ip_mreq g_multicastMemberReq;
130
131 /**
132  * @var g_packetReceivedCallback
133  * @brief Callback for notifying the upper layer on receival data from remote OIC device
134  */
135 static CAEthernetPacketReceivedCallback g_packetReceivedCallback = NULL;
136
137 /**
138  * @var g_exceptionCallback
139  * @brief Callback for notifying the upper layer when unicast/multicast server encounters exception
140  */
141 static CAEthernetExceptionCallback g_exceptionCallback = NULL;
142
143 /**
144  @brief Thread context information for unicast, multicast and secured unicast server
145  */
146 typedef struct
147 {
148     bool *stopFlag;
149     int32_t socket_fd;
150     CAAdapterServerType_t type;
151 } CAAdapterReceiveThreadContext_t;
152
153 static void CAReceiveHandler(void *data)
154 {
155     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "IN");
156
157     // Input validation
158     VERIFY_NON_NULL_VOID(data, ETHERNET_SERVER_TAG, "Invalid thread context");
159
160     CAAdapterReceiveThreadContext_t *ctx = (CAAdapterReceiveThreadContext_t *)data;
161     fd_set reads;
162     struct timeval timeout;
163     char recvBuffer[COAP_MAX_PDU_SIZE] = {0};
164
165     while (true != *(ctx->stopFlag))
166     {
167         timeout.tv_sec = 1;
168         timeout.tv_usec = 0;
169
170         FD_ZERO(&reads);
171         FD_SET(ctx->socket_fd, &reads);
172
173         int32_t ret = select(ctx->socket_fd + 1, &reads, NULL, NULL, &timeout);
174         if (*(ctx->stopFlag) == true)
175         {
176             OIC_LOG_V(DEBUG, ETHERNET_SERVER_TAG,
177                 "Stop request received for [%d] server", ctx->type);
178             break;
179         }
180
181         if (ret < 0)
182         {
183             OIC_LOG_V(FATAL, ETHERNET_SERVER_TAG, "select returned error %s", strerror(errno));
184             continue;
185         }
186
187         if (!FD_ISSET(ctx->socket_fd, &reads))
188         {
189             continue;
190         }
191
192         memset(recvBuffer, 0, sizeof(recvBuffer));
193
194         // Read data from socket
195         struct sockaddr_in srcSockAddress;
196         int32_t recvLen;
197         socklen_t srcAddressLen = sizeof(srcSockAddress);
198
199         recvLen = recvfrom(ctx->socket_fd, recvBuffer,
200                                       sizeof(recvBuffer), 0, (struct sockaddr *) &srcSockAddress,
201                                       &srcAddressLen);
202
203         if (-1 == recvLen)
204         {
205             OIC_LOG_V(DEBUG, ETHERNET_SERVER_TAG, "%s", strerror(errno));
206             continue;
207         }
208         else if (0 == recvLen)
209         {
210             OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Server socket shutdown [%d]!", ctx->type);
211
212             // Notify upper layer this exception
213             if (g_exceptionCallback)
214             {
215                 g_exceptionCallback(ctx->type);
216             }
217             OICFree(ctx);
218             ctx = NULL;
219             return;
220         }
221
222         char srcIPAddress[CA_IPADDR_SIZE] = {0};
223         inet_ntop(AF_INET, &srcSockAddress.sin_addr.s_addr, srcIPAddress, sizeof(srcIPAddress));
224         uint16_t srcPort = 0;
225         srcPort = ntohs(srcSockAddress.sin_port);
226
227         OIC_LOG_V(DEBUG, ETHERNET_SERVER_TAG, "Received packet from %s:%d\n",
228                   srcIPAddress, srcPort);
229         OIC_LOG_V(DEBUG, ETHERNET_SERVER_TAG, "Data: %s\t, DataLength: %d\n",
230                   recvBuffer, recvLen);
231
232         char *netMask = NULL;
233         if (CA_STATUS_OK != CAEthernetGetInterfaceSubnetMask(&netMask))
234         {
235             OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Failed to get ethernet subnet");
236             continue;
237         }
238
239         if (!CAAdapterIsSameSubnet(g_multicastServerInterface, srcIPAddress, netMask))
240         {
241             OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "Packet received from different subnet, Ignore!");
242             if (NULL != netMask)
243             {
244                 OICFree(netMask);
245             }
246             netMask = NULL;
247             continue;
248         }
249
250         OICFree(netMask);
251         switch (ctx->type)
252         {
253             case CA_UNICAST_SERVER:
254             case CA_MULTICAST_SERVER:
255                 // Notify data to upper layer
256                 if (g_packetReceivedCallback)
257                 {
258                     g_packetReceivedCallback(srcIPAddress, srcPort, recvBuffer, recvLen, false);
259                 }
260                 break;
261 #ifdef __WITH_DTLS__
262             case CA_SECURED_UNICAST_SERVER:
263                 {
264                     CAResult_t ret = CAAdapterNetDtlsDecrypt(srcIPAddress,
265                                      srcPort,
266                                      (uint8_t *)recvBuffer,
267                                      recvLen, DTLS_ETHERNET);
268                     OIC_LOG_V(DEBUG, ETHERNET_SERVER_TAG,
269                         "CAAdapterNetDtlsDecrypt returns [%d]", ret);
270                 }
271                 break;
272 #endif //__WITH_DTLS__
273             default:
274                 // Should never occur
275                 OIC_LOG_V(DEBUG, ETHERNET_SERVER_TAG, "Invalid server type");
276                 OICFree(ctx);
277                 ctx = NULL;
278                 return;
279         }
280     }
281     OICFree(ctx);
282     ctx = NULL;
283
284
285     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "OUT");
286 }
287
288 static CAResult_t CACreateSocket(int32_t *socketFD, const char *localIp, uint16_t *port,
289                                  bool forceStart)
290 {
291     int32_t sock = -1;
292     // Create a UDP socket
293     sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
294     if (-1 == sock)
295     {
296         OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Failed to create Socket, Error code: %s",
297                   strerror(errno));
298         return CA_STATUS_FAILED;
299     }
300
301     // Make the socket non-blocking
302     if (-1 == fcntl(sock, F_SETFL, O_NONBLOCK))
303     {
304         OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Failed to set non-block mode, Error code: %s",
305                   strerror(errno));
306
307         close(sock);
308         return CA_STATUS_FAILED;
309     }
310
311     if (true == forceStart)
312     {
313         int32_t setOptionOn = 1;
314         if (-1 == setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
315                              (char *) &setOptionOn,
316                              sizeof(setOptionOn)))
317         {
318             OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Failed to set SO_REUSEADDR! Error code: %s",
319                       strerror(errno));
320
321             close(sock);
322             return CA_STATUS_FAILED;
323         }
324     }
325
326     struct sockaddr_in sockAddr;
327     bool isBound = false;
328     uint16_t serverPort = *port;
329
330     memset(&sockAddr, 0, sizeof(sockAddr));
331     sockAddr.sin_family = AF_INET;
332     sockAddr.sin_port = htons(serverPort);
333     if (localIp)
334     {
335         sockAddr.sin_addr.s_addr = inet_addr(localIp);
336     }
337     else
338     {
339         sockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
340     }
341
342     int16_t i;
343     for (i = 0; i < CA_UDP_BIND_RETRY_COUNT; i++)
344     {
345         if (-1 == bind(sock, (struct sockaddr *) &sockAddr,
346                        sizeof(sockAddr)))
347         {
348             if (false == forceStart)
349             {
350                 OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Failed to bind socket[%s]. Trying again..",
351                           strerror(errno));
352
353                 //Set the port to next one
354                 serverPort += 1;
355                 sockAddr.sin_port = htons(serverPort);
356                 continue;
357             }
358             else
359             {
360                 OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Failed to bind socket[%s]!",
361                           strerror(errno));
362                 break;
363             }
364         }
365
366         isBound = true;
367         break;
368     }
369
370     if (false == isBound)
371     {
372         close(sock);
373         return CA_STATUS_FAILED;
374     }
375
376     *port = serverPort;
377     *socketFD = sock;
378     return CA_STATUS_OK;
379 }
380
381 static CAResult_t CACloseSocket(int32_t *socketFD)
382 {
383     if (socketFD == NULL)
384     {
385         return CA_STATUS_INVALID_PARAM;
386     }
387
388     if (-1 == *socketFD)
389     {
390         OIC_LOG(INFO, ETHERNET_SERVER_TAG, "Server not running");
391         return CA_SERVER_NOT_STARTED;
392     }
393
394     // close the socket
395     if (-1 == close(*socketFD))
396     {
397         OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Failed to close the socket, Error code: %s\n",
398                   strerror(errno));
399         return CA_STATUS_FAILED;
400     }
401
402     *socketFD = -1;
403     return CA_STATUS_OK;
404 }
405
406 static CAResult_t CAStartUnicastServer(const char *localAddress, uint16_t *port,
407                                        const bool forceStart, bool isSecured, int32_t *serverFD)
408 {
409     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "IN");
410
411     if (serverFD == NULL)
412     {
413         return CA_STATUS_INVALID_PARAM;
414     }
415
416     CAResult_t ret = CACreateSocket(serverFD, localAddress, port, forceStart);
417     if (CA_STATUS_OK != ret)
418     {
419         OIC_LOG(ERROR, ETHERNET_SERVER_TAG, "Failed to create unicast socket");
420         return ret;
421     }
422
423     /**
424       * The task to listen for data from unicast socket is added to the thread pool.
425       * This is a blocking call is made where we try to receive some data..
426       * We will keep waiting until some data is received.
427       * This task will be terminated when thread pool is freed on stopping the adapters.
428       * Thread context will be freed by thread on exit.
429       */
430     CAAdapterReceiveThreadContext_t *ctx = (CAAdapterReceiveThreadContext_t *)
431                                            OICMalloc(sizeof(CAAdapterReceiveThreadContext_t));
432     if (!ctx)
433     {
434         OIC_LOG(ERROR, ETHERNET_SERVER_TAG, "Out of memory!");
435         close(*serverFD);
436         return CA_MEMORY_ALLOC_FAILED;
437     }
438
439     ctx->stopFlag = &g_stopUnicast;
440     ctx->socket_fd = *serverFD;
441     ctx->type = isSecured ? CA_SECURED_UNICAST_SERVER : CA_UNICAST_SERVER;
442     if (CA_STATUS_OK != u_thread_pool_add_task(g_threadPool, CAReceiveHandler, (void *)ctx))
443     {
444         OIC_LOG(ERROR, ETHERNET_SERVER_TAG, "Failed to create read thread!");
445         OICFree(ctx);
446         close(*serverFD);
447         *serverFD = -1;
448         return CA_STATUS_FAILED;
449     }
450
451     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "OUT");
452     return CA_STATUS_OK;
453 }
454
455 static void CAEthernetServerDestroyMutex(void)
456 {
457     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "IN");
458
459     if (g_mutexUnicastServer)
460     {
461         u_mutex_free(g_mutexUnicastServer);
462         g_mutexUnicastServer = NULL;
463     }
464
465 #ifdef __WITH_DTLS__
466     if (g_mutexSecureUnicastServer)
467     {
468         u_mutex_free(g_mutexSecureUnicastServer);
469         g_mutexSecureUnicastServer = NULL;
470     }
471 #endif
472
473     if (g_mutexMulticastServer)
474     {
475         u_mutex_free(g_mutexMulticastServer);
476         g_mutexMulticastServer = NULL;
477     }
478
479     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "OUT");
480 }
481
482 static CAResult_t CAEthernetServerCreateMutex(void)
483 {
484     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "IN");
485
486     if(g_mutexUnicastServer) {
487         OIC_LOG(ERROR, ETHERNET_SERVER_TAG, "mutex is already created!");
488
489         OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "OUT");
490         return CA_STATUS_FAILED;
491     }
492
493     g_mutexUnicastServer = u_mutex_new();
494     if (!g_mutexUnicastServer)
495     {
496         OIC_LOG(ERROR, ETHERNET_SERVER_TAG, "Failed to created mutex!");
497         return CA_STATUS_FAILED;
498     }
499
500 #ifdef __WITH_DTLS__
501     g_mutexSecureUnicastServer = u_mutex_new();
502     if (!g_mutexSecureUnicastServer)
503     {
504         OIC_LOG(ERROR, ETHERNET_SERVER_TAG, "Failed to created mutex!");
505
506         CAEthernetServerDestroyMutex();
507         return CA_STATUS_FAILED;
508     }
509 #endif
510
511     g_mutexMulticastServer = u_mutex_new();
512     if (!g_mutexMulticastServer)
513     {
514         OIC_LOG(ERROR, ETHERNET_SERVER_TAG, "Failed to created mutex!");
515
516         CAEthernetServerDestroyMutex();
517         return CA_STATUS_FAILED;
518     }
519
520     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "OUT");
521     return CA_STATUS_OK;
522 }
523
524 CAResult_t CAEthernetInitializeServer(const u_thread_pool_t threadPool)
525 {
526     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "IN");
527
528     // Input validation
529     VERIFY_NON_NULL(threadPool, ETHERNET_SERVER_TAG, "Thread pool handle is NULL");
530
531     // Initialize mutex
532     if (CA_STATUS_OK != CAEthernetServerCreateMutex())
533     {
534         OIC_LOG(ERROR, ETHERNET_SERVER_TAG, "Failed to create mutex!");
535         return CA_STATUS_FAILED;
536     }
537
538     g_threadPool = threadPool;
539
540     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "OUT");
541     return CA_STATUS_OK;
542 }
543
544 void CAEthernetTerminateServer(void)
545 {
546     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "IN");
547
548     g_threadPool = NULL;
549
550     // Destroy mutex
551     CAEthernetServerDestroyMutex();
552
553     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "OUT");
554 }
555
556 CAResult_t CAEthernetStartUnicastServer(const char *localAddress, uint16_t *port,
557                                         bool forceStart, bool isSecured, int32_t *serverFD)
558 {
559     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "IN");
560
561     // Input validation
562     VERIFY_NON_NULL(localAddress, ETHERNET_SERVER_TAG, "localAddress");
563     VERIFY_NON_NULL(port, ETHERNET_SERVER_TAG, "port");
564     VERIFY_NON_NULL(serverFD, ETHERNET_SERVER_TAG, "server socket FD");
565
566     if (0 >= *port)
567     {
568         OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Invalid input: port is invalid!");
569         return CA_STATUS_INVALID_PARAM;
570     }
571
572     *serverFD = -1;
573     if (false == isSecured)
574     {
575         u_mutex_lock(g_mutexUnicastServer);
576         if (-1 != g_unicastServerSocketFD)
577         {
578             OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Unicast Server is Started Already!",
579                       CA_SERVER_STARTED_ALREADY);
580
581             *serverFD = g_unicastServerSocketFD;
582             u_mutex_unlock(g_mutexUnicastServer);
583             return CA_SERVER_STARTED_ALREADY;
584         }
585
586         g_stopUnicast = false;
587         if (CA_STATUS_OK != CAStartUnicastServer(localAddress, port, forceStart, isSecured,
588                 &g_unicastServerSocketFD))
589         {
590             OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Failed to start unicast server!");
591             g_unicastServerSocketFD = -1;
592             u_mutex_unlock(g_mutexUnicastServer);
593             return CA_STATUS_FAILED;
594         }
595
596         *serverFD = g_unicastServerSocketFD;
597         u_mutex_unlock(g_mutexUnicastServer);
598     }
599 #ifdef __WITH_DTLS__
600     else // Start unicast server for secured communication
601     {
602         u_mutex_lock(g_mutexSecureUnicastServer);
603         if (-1 != g_secureUnicastServerSocketFD)
604         {
605             OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Unicast Server is Started Already!",
606                       CA_SERVER_STARTED_ALREADY);
607
608             *serverFD = g_secureUnicastServerSocketFD;
609             u_mutex_unlock(g_mutexSecureUnicastServer);
610             return CA_SERVER_STARTED_ALREADY;
611         }
612
613         g_stopSecureUnicast = false;
614         if (CA_STATUS_OK != CAStartUnicastServer(localAddress, port, forceStart, isSecured,
615                 &g_secureUnicastServerSocketFD))
616         {
617             OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Failed to start unicast server!");
618             g_secureUnicastServerSocketFD = -1;
619             u_mutex_unlock(g_mutexSecureUnicastServer);
620             return CA_STATUS_FAILED;
621         }
622
623         *serverFD = g_secureUnicastServerSocketFD;
624         u_mutex_unlock(g_mutexSecureUnicastServer);
625     }
626 #endif
627     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "OUT");
628     return CA_STATUS_OK;
629 }
630
631 CAResult_t CAEthernetStartMulticastServer(const char *localAddress,
632     const char *multicastAddress, const uint16_t multicastPort, int32_t *serverFD)
633 {
634     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "IN");
635
636     // Input validation
637     VERIFY_NON_NULL(localAddress, ETHERNET_SERVER_TAG, "localAddress");
638     VERIFY_NON_NULL(multicastAddress, ETHERNET_SERVER_TAG, "port");
639     VERIFY_NON_NULL(serverFD, ETHERNET_SERVER_TAG, "server socket FD");
640
641     uint16_t port = multicastPort;
642     if (0 >= port)
643     {
644         OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Invalid input: Multicast port is invalid!");
645         return CA_STATUS_INVALID_PARAM;
646     }
647
648     u_mutex_lock(g_mutexMulticastServer);
649
650     if (g_multicastServerSocketFD != -1)
651     {
652         OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Multicast Server is already running!");
653         u_mutex_unlock(g_mutexMulticastServer);
654         return CA_SERVER_STARTED_ALREADY;
655     }
656
657     CAResult_t ret = CACreateSocket(&g_multicastServerSocketFD, multicastAddress, &port, true);
658     if (ret != CA_STATUS_OK)
659     {
660         OIC_LOG(ERROR, ETHERNET_SERVER_TAG, "Failed to create multicast socket");
661         u_mutex_unlock(g_mutexMulticastServer);
662         return ret;
663     }
664
665     // Add membership to receiving socket (join group)
666     memset(&g_multicastMemberReq, 0, sizeof(struct ip_mreq));
667     g_multicastMemberReq.imr_interface.s_addr = inet_addr(localAddress);
668     inet_aton(multicastAddress, &g_multicastMemberReq.imr_multiaddr);
669
670     if (-1 == setsockopt(g_multicastServerSocketFD, IPPROTO_IP, IP_ADD_MEMBERSHIP,
671                          (char *) &g_multicastMemberReq,
672                          sizeof(struct ip_mreq)))
673     {
674         OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Failed to add to multicast group, Error code: %s\n",
675                   strerror(errno));
676         close(g_multicastServerSocketFD);
677         g_multicastServerSocketFD = -1;
678         u_mutex_unlock(g_mutexMulticastServer);
679         return CA_STATUS_FAILED;
680     }
681
682     /**
683       * The task to listen to data from multicastcast socket is added to the thread pool.
684       * This is a blocking call is made where we try to receive some data.
685       * We will keep waiting until some data is received.
686       * This task will be terminated when thread pool is freed on stopping the adapters.
687       * Thread context will be freed by thread on exit.
688       */
689     CAAdapterReceiveThreadContext_t *ctx = (CAAdapterReceiveThreadContext_t *)
690                                            OICMalloc(sizeof(CAAdapterReceiveThreadContext_t));
691     if (!ctx)
692     {
693         OIC_LOG(ERROR, ETHERNET_SERVER_TAG, "Out of memory!");
694         close(g_multicastServerSocketFD);
695         g_multicastServerSocketFD = -1;
696         return CA_MEMORY_ALLOC_FAILED;
697     }
698
699     ctx->stopFlag = &g_stopMulticast;
700     ctx->socket_fd = g_multicastServerSocketFD;
701     ctx->type = CA_MULTICAST_SERVER;
702
703     g_stopMulticast = false;
704     if (CA_STATUS_OK != u_thread_pool_add_task(g_threadPool, CAReceiveHandler, (void *)ctx))
705     {
706         OIC_LOG(ERROR, ETHERNET_SERVER_TAG, "thread_pool_add_task failed!");
707
708         close(g_multicastServerSocketFD);
709         g_multicastServerSocketFD = -1;
710         g_stopMulticast = true;
711         u_mutex_unlock(g_mutexMulticastServer);
712         return CA_STATUS_FAILED;
713     }
714
715     *serverFD = g_multicastServerSocketFD;
716     strncpy(g_multicastServerInterface, localAddress, IPNAMESIZE);
717     u_mutex_unlock(g_mutexMulticastServer);
718
719     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "OUT");
720     return CA_STATUS_OK;
721 }
722
723 CAResult_t CAEthernetStopUnicastServer()
724 {
725     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "IN");
726
727     u_mutex_lock(g_mutexUnicastServer);
728     g_stopUnicast = true;
729     CAResult_t ret = CACloseSocket(&g_unicastServerSocketFD);
730     u_mutex_unlock(g_mutexUnicastServer);
731
732     OIC_LOG_V(INFO, ETHERNET_SERVER_TAG, "Unicast server stopped [%d]", ret);
733     return ret;
734 }
735
736 #ifdef __WITH_DTLS__
737 CAResult_t CAEthernetStopSecureUnicastServer()
738 {
739     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "IN");
740
741     u_mutex_lock(g_mutexSecureUnicastServer);
742     g_stopSecureUnicast = true;
743     CAResult_t ret = CACloseSocket(&g_secureUnicastServerSocketFD);
744     u_mutex_unlock(g_mutexSecureUnicastServer);
745
746     OIC_LOG_V(INFO, ETHERNET_SERVER_TAG, "Secured unicast server stopped [%d]", ret);
747     return ret;
748 }
749 #endif
750
751 CAResult_t CAEthernetStopMulticastServer(void)
752 {
753     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "IN");
754
755     u_mutex_lock(g_mutexMulticastServer);
756
757     if (g_multicastServerSocketFD == -1)
758     {
759         OIC_LOG(INFO, ETHERNET_SERVER_TAG, "Multicast server is not yet started");
760         u_mutex_unlock(g_mutexMulticastServer);
761         return CA_SERVER_NOT_STARTED;
762     }
763
764     g_stopMulticast = true;
765
766     // leave the group after you are done
767     if (-1 == setsockopt(g_multicastServerSocketFD, IPPROTO_IP, IP_DROP_MEMBERSHIP,
768                          (char *)&g_multicastMemberReq,
769                          sizeof(struct ip_mreq)))
770     {
771         OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Failed to leave multicast group, Error code: %s\n",
772                   strerror(errno));
773     }
774
775     CAResult_t ret = CACloseSocket(&g_multicastServerSocketFD);
776     u_mutex_unlock(g_mutexMulticastServer);
777
778     OIC_LOG_V(INFO, ETHERNET_SERVER_TAG, "Multicast server stopped [%d]", ret);
779     return ret;
780 }
781
782 CAResult_t CAEthernetGetUnicastServerInfo(bool isSecured,
783     char **ipAddress, uint16_t *port, int32_t *serverFD)
784 {
785     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "IN");
786
787     // Input validation
788     VERIFY_NON_NULL(ipAddress, ETHERNET_SERVER_TAG, "IP address");
789     VERIFY_NON_NULL(port, ETHERNET_SERVER_TAG, "Port");
790     VERIFY_NON_NULL(serverFD, ETHERNET_SERVER_TAG, "Server ID");
791
792     struct sockaddr_in sockAddr;
793     socklen_t len = sizeof(struct sockaddr_in);
794     if (-1 == getsockname(g_unicastServerSocketFD, (struct sockaddr *)&sockAddr, &len))
795     {
796         OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Failed in getsockname [%s]!", strerror(errno));
797         return CA_STATUS_FAILED;
798     }
799
800
801     const char *serverAddress = inet_ntoa(sockAddr.sin_addr);
802     *ipAddress = (serverAddress) ? strndup(serverAddress, strlen(serverAddress)) : NULL;
803     *port = ntohs(sockAddr.sin_port);
804 #ifdef __WITH_DTLS__
805     *serverFD = (true == isSecured) ? g_secureUnicastServerSocketFD : g_unicastServerSocketFD;
806 #else
807     *serverFD = g_unicastServerSocketFD;
808 #endif
809
810     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "OUT");
811     return CA_STATUS_OK;
812 }
813
814 void CAEthernetSetPacketReceiveCallback(CAEthernetPacketReceivedCallback callback)
815 {
816     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "IN");
817     g_packetReceivedCallback = callback;
818     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "OUT");
819 }
820
821 void CAEthernetSetExceptionCallback(CAEthernetExceptionCallback callback)
822 {
823     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "IN");
824     g_exceptionCallback = callback;
825     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "OUT");
826 }
827