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