Implementation of following functionality
[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             return;
214         }
215
216         const char *srcIPAddress = NULL;
217         int32_t srcPort = -1;
218
219         srcIPAddress = inet_ntoa(srcSockAddress.sin_addr);
220         srcPort = ntohs(srcSockAddress.sin_port);
221
222         OIC_LOG_V(DEBUG, ETHERNET_SERVER_TAG, "Received packet from %s:%d\n",
223                   srcIPAddress, srcPort);
224         OIC_LOG_V(DEBUG, ETHERNET_SERVER_TAG, "Data: %s\t, DataLength: %d\n",
225                   recvBuffer, recvLen);
226
227         char *netMask = NULL;
228         if (CA_STATUS_OK != CAEthernetGetInterfaceSubnetMask(&netMask))
229         {
230             OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Failed to get ethernet subnet");
231             continue;
232         }
233
234         if(!CAAdapterIsSameSubnet(gMulticastServerInterface, srcIPAddress, netMask))
235         {
236             OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "Packet received from different subnet, Ignore!");
237             continue;
238         }
239
240         OICFree(netMask);
241         switch(ctx->type)
242         {
243             case CA_UNICAST_SERVER:
244             case CA_MULTICAST_SERVER:
245                 // Notify data to upper layer
246                 if (gPacketReceivedCallback)
247                 {
248                     gPacketReceivedCallback(srcIPAddress, srcPort, recvBuffer, recvLen, false);
249                 }
250                 break;
251 #ifdef __WITH_DTLS__
252             case CA_SECURED_UNICAST_SERVER:
253                 {
254                     CAResult_t ret = CAAdapterNetDtlsDecrypt(srcIPAddress,
255                                         srcPort,
256                                         (uint8_t *)recvBuffer,
257                                         recvLen, DTLS_ETHERNET);
258                     OIC_LOG_V(DEBUG, ETHERNET_SERVER_TAG, "CAAdapterNetDtlsDecrypt returns [%d]", ret);
259                 }
260                 break;
261 #endif //__WITH_DTLS__
262             default:
263                 // Should never occur
264                 OIC_LOG_V(DEBUG, ETHERNET_SERVER_TAG, "Invalid server type");
265                 OICFree(ctx);
266                 return;
267         }
268     }
269
270     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "OUT");
271 }
272
273 static CAResult_t CACreateSocket(int32_t* socketFD, const char *localIp, int16_t *port,
274                                  const bool forceStart)
275 {
276     int32_t sock = -1;
277     // Create a UDP socket
278     if (-1 == (sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)))
279     {
280         OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Failed to create Socket, Error code: %s",
281                   strerror(errno));
282         return CA_STATUS_FAILED;
283     }
284
285     // Make the socket non-blocking
286     if (-1 == fcntl(sock, F_SETFL, O_NONBLOCK))
287     {
288         OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Failed to set non-block mode, Error code: %s",
289                   strerror(errno));
290
291         close(sock);
292         return CA_STATUS_FAILED;
293     }
294
295     if (true == forceStart)
296     {
297         int32_t setOptionOn = 1;
298         if (-1 == setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
299                              (char *) &setOptionOn,
300                              sizeof(setOptionOn)))
301         {
302             OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Failed to set SO_REUSEADDR! Error code: %s",
303                       strerror(errno));
304
305             close(sock);
306             return CA_STATUS_FAILED;
307         }
308     }
309
310     struct sockaddr_in sockAddr;
311     bool isBound = false;
312     int16_t serverPort = *port;
313
314     memset((char *) &sockAddr, 0, sizeof(sockAddr));
315     sockAddr.sin_family = AF_INET;
316     sockAddr.sin_port = htons(serverPort);
317     if(localIp)
318     {
319         sockAddr.sin_addr.s_addr = inet_addr(localIp);
320     }
321     else
322     {
323         sockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
324     }
325
326     int16_t i;
327     for (i = 0; i < CA_UDP_BIND_RETRY_COUNT; i++)
328     {
329         if (-1 == bind(sock, (struct sockaddr *) &sockAddr,
330                        sizeof(sockAddr)))
331         {
332             if (false == forceStart)
333             {
334                 OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Failed to bind socket[%s]. Trying again..",
335                           strerror(errno));
336
337                 //Set the port to next one
338                 serverPort += 1;
339                 sockAddr.sin_port = htons(serverPort);
340                 continue;
341             }
342             else
343             {
344                 OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Failed to bind socket[%s]!",
345                           strerror(errno));
346                 break;
347             }
348         }
349
350         isBound = true;
351         break;
352     }
353
354     if (false == isBound)
355     {
356         close(sock);
357         return CA_STATUS_FAILED;
358     }
359
360     *port = serverPort;
361     *socketFD = sock;
362     return CA_STATUS_OK;
363 }
364
365 static CAResult_t CACloseSocket(int32_t *socketFD)
366 {
367     if (-1 == *socketFD)
368     {
369         OIC_LOG(INFO, ETHERNET_SERVER_TAG, "Server not running");
370         return CA_SERVER_NOT_STARTED;
371     }
372
373     // close the socket
374     if (-1 == close(*socketFD))
375     {
376         OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Failed to close the socket, Error code: %s\n",
377                   strerror(errno));
378         return CA_STATUS_FAILED;
379     }
380
381     *socketFD = -1;
382     return CA_STATUS_OK;
383 }
384
385 static CAResult_t CAStartUnicastServer(const char *localAddress, int16_t *port,
386                                        const bool forceStart, bool isSecured, int32_t *serverFD)
387 {
388     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "IN");
389
390     CAResult_t ret = CACreateSocket(serverFD, localAddress, port, forceStart);
391     if(CA_STATUS_OK != ret)
392     {
393         OIC_LOG(ERROR, ETHERNET_SERVER_TAG, "Failed to create unicast socket");
394         return ret;
395     }
396
397     /**
398       * The task to listen for data from unicast socket is added to the thread pool.
399       * This is a blocking call is made where we try to receive some data..
400       * We will keep waiting until some data is received.
401       * This task will be terminated when thread pool is freed on stopping the adapters.
402       * Thread context will be freed by thread on exit.
403       */
404     CAAdapterReceiveThreadContext_t *ctx = (CAAdapterReceiveThreadContext_t *)
405                                             OICMalloc(sizeof(CAAdapterReceiveThreadContext_t));
406     if(!ctx)
407     {
408         OIC_LOG(ERROR, ETHERNET_SERVER_TAG, "Out of memory!");
409         close(*serverFD);
410         return CA_MEMORY_ALLOC_FAILED;
411     }
412
413     ctx->stopFlag = &gStopUnicast;
414     ctx->socket_fd = *serverFD;
415     ctx->type = isSecured ? CA_SECURED_UNICAST_SERVER:CA_UNICAST_SERVER;
416     if (CA_STATUS_OK != u_thread_pool_add_task(gThreadPool, CAReceiveHandler, (void *)ctx))
417     {
418         OIC_LOG(ERROR, ETHERNET_SERVER_TAG, "Failed to create read thread!");
419         OICFree((void *)ctx);
420         close(*serverFD);
421         return CA_STATUS_FAILED;
422     }
423
424     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "OUT");
425     return CA_STATUS_OK;
426 }
427
428 static void CAEthernetServerDestroyMutex(void)
429 {
430     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "IN");
431
432     if (gMutexUnicastServer)
433     {
434         u_mutex_free(gMutexUnicastServer);
435         gMutexUnicastServer = NULL;
436     }
437
438 #ifdef __WITH_DTLS__
439     if (gMutexSecureUnicastServer)
440     {
441         u_mutex_free(gMutexSecureUnicastServer);
442         gMutexSecureUnicastServer = NULL;
443     }
444 #endif
445
446     if (gMutexMulticastServer)
447     {
448         u_mutex_free(gMutexMulticastServer);
449         gMutexMulticastServer = NULL;
450     }
451
452     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "OUT");
453 }
454
455 static CAResult_t CAEthernetServerCreateMutex(void)
456 {
457     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "IN");
458
459     gMutexUnicastServer = u_mutex_new();
460     if (!gMutexUnicastServer)
461     {
462         OIC_LOG(ERROR, ETHERNET_SERVER_TAG, "Failed to created mutex!");
463         return CA_STATUS_FAILED;
464     }
465
466 #ifdef __WITH_DTLS__
467     gMutexSecureUnicastServer = u_mutex_new();
468     if (!gMutexSecureUnicastServer)
469     {
470         OIC_LOG(ERROR, ETHERNET_SERVER_TAG, "Failed to created mutex!");
471
472         CAEthernetServerDestroyMutex();
473         return CA_STATUS_FAILED;
474     }
475 #endif
476
477     gMutexMulticastServer = u_mutex_new();
478     if (!gMutexMulticastServer)
479     {
480         OIC_LOG(ERROR, ETHERNET_SERVER_TAG, "Failed to created mutex!");
481
482         CAEthernetServerDestroyMutex();
483         return CA_STATUS_FAILED;
484     }
485
486     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "OUT");
487     return CA_STATUS_OK;
488 }
489
490 CAResult_t CAEthernetInitializeServer(const u_thread_pool_t threadPool)
491 {
492     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "IN");
493
494     // Input validation
495     VERIFY_NON_NULL(threadPool, ETHERNET_SERVER_TAG, "Thread pool handle is NULL");
496
497     // Initialize mutex
498     if (CA_STATUS_OK != CAEthernetServerCreateMutex())
499     {
500         OIC_LOG(ERROR, ETHERNET_SERVER_TAG, "Failed to create mutex!");
501         return CA_STATUS_FAILED;
502     }
503
504     gThreadPool = threadPool;
505
506     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "OUT");
507     return CA_STATUS_OK;
508 }
509
510 void CAEthernetTerminateServer(void)
511 {
512     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "IN");
513
514     gThreadPool = NULL;
515
516     // Destroy mutex
517     CAEthernetServerDestroyMutex();
518
519     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "OUT");
520 }
521
522 CAResult_t CAEthernetStartUnicastServer(const char *localAddress, int16_t *port,
523                                         const bool forceStart, const bool isSecured,
524                                         int32_t *serverFD)
525 {
526     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "IN");
527
528     // Input validation
529     VERIFY_NON_NULL(localAddress, ETHERNET_SERVER_TAG, "localAddress");
530     VERIFY_NON_NULL(port, ETHERNET_SERVER_TAG, "port");
531     VERIFY_NON_NULL(serverFD, ETHERNET_SERVER_TAG, "server socket FD");
532
533     if (0 >= *port)
534     {
535         OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Invalid input: port is invalid!");
536         return CA_STATUS_INVALID_PARAM;
537     }
538
539     *serverFD = -1;
540     if (CA_FALSE == isSecured)
541     {
542         u_mutex_lock(gMutexUnicastServer);
543         if (-1 != gUnicastServerSocketFD)
544         {
545             OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Unicast Server is Started Already!",
546                       CA_SERVER_STARTED_ALREADY);
547
548             *serverFD = gUnicastServerSocketFD;
549             u_mutex_unlock(gMutexUnicastServer);
550             return CA_SERVER_STARTED_ALREADY;
551         }
552
553         gStopUnicast = false;
554         if (CA_STATUS_OK != CAStartUnicastServer(localAddress, port, forceStart, isSecured,
555                                                  &gUnicastServerSocketFD))
556         {
557             OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Failed to start unicast server!");
558             gUnicastServerSocketFD = -1;
559             u_mutex_unlock(gMutexUnicastServer);
560             return CA_STATUS_FAILED;
561         }
562
563         *serverFD = gUnicastServerSocketFD;
564         u_mutex_unlock(gMutexUnicastServer);
565     }
566 #ifdef __WITH_DTLS__
567     else // Start unicast server for secured communication
568     {
569         u_mutex_lock(gMutexSecureUnicastServer);
570         if (-1 != gSecureUnicastServerSocketFD)
571         {
572             OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Unicast Server is Started Already!",
573                       CA_SERVER_STARTED_ALREADY);
574
575             *serverFD = gSecureUnicastServerSocketFD;
576             u_mutex_unlock(gMutexSecureUnicastServer);
577             return CA_SERVER_STARTED_ALREADY;
578         }
579
580         gStopSecureUnicast = false;
581         if (CA_STATUS_OK != CAStartUnicastServer(localAddress, port, forceStart, isSecured,
582                                                  &gSecureUnicastServerSocketFD))
583         {
584             OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Failed to start unicast server!");
585             gSecureUnicastServerSocketFD = -1;
586             u_mutex_unlock(gMutexSecureUnicastServer);
587             return CA_STATUS_FAILED;
588         }
589
590         *serverFD = gSecureUnicastServerSocketFD;
591         u_mutex_unlock(gMutexSecureUnicastServer);
592     }
593 #endif
594     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "OUT");
595     return CA_STATUS_OK;
596 }
597
598 CAResult_t CAEthernetStartMulticastServer(const char *localAddress, const char *multicastAddress,
599         const int16_t multicastPort, int32_t *serverFD)
600 {
601     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "IN");
602
603     // Input validation
604     VERIFY_NON_NULL(localAddress, ETHERNET_SERVER_TAG, "Local address is NULL");
605     VERIFY_NON_NULL(multicastAddress, ETHERNET_SERVER_TAG, "Multicast address is NULL");
606
607     int16_t port = multicastPort;
608     if (0 >= port)
609     {
610         OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Invalid input: Multicast port is invalid!");
611         return CA_STATUS_INVALID_PARAM;
612     }
613
614     u_mutex_lock(gMutexMulticastServer);
615
616     if (gMulticastServerSocketFD != -1)
617     {
618         OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Multicast Server is already running!");
619         u_mutex_unlock(gMutexMulticastServer);
620         return CA_SERVER_STARTED_ALREADY;
621     }
622
623     CAResult_t ret = CACreateSocket(&gMulticastServerSocketFD, multicastAddress, &port, true);
624     if(ret != CA_STATUS_OK)
625     {
626         OIC_LOG(ERROR, ETHERNET_SERVER_TAG, "Failed to create multicast socket");
627         u_mutex_unlock(gMutexMulticastServer);
628         return ret;
629     }
630
631     // Add membership to receiving socket (join group)
632     memset(&gMulticastMemberReq, 0, sizeof(struct ip_mreq));
633     gMulticastMemberReq.imr_interface.s_addr = inet_addr(localAddress);
634     inet_aton(multicastAddress, &gMulticastMemberReq.imr_multiaddr);
635
636     if (-1 == setsockopt(gMulticastServerSocketFD, IPPROTO_IP, IP_ADD_MEMBERSHIP,
637                          (char *) &gMulticastMemberReq,
638                          sizeof(struct ip_mreq)))
639     {
640         OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Failed to add to multicast group, Error code: %s\n",
641                   strerror(errno));
642         close(gMulticastServerSocketFD);
643         gMulticastServerSocketFD = -1;
644         u_mutex_unlock(gMutexMulticastServer);
645         return CA_STATUS_FAILED;
646     }
647
648     /**
649       * The task to listen to data from multicastcast socket is added to the thread pool.
650       * This is a blocking call is made where we try to receive some data.
651       * We will keep waiting until some data is received.
652       * This task will be terminated when thread pool is freed on stopping the adapters.
653       * Thread context will be freed by thread on exit.
654       */
655     CAAdapterReceiveThreadContext_t *ctx = (CAAdapterReceiveThreadContext_t *)
656                                             OICMalloc(sizeof(CAAdapterReceiveThreadContext_t));
657     if(!ctx)
658     {
659         OIC_LOG(ERROR, ETHERNET_SERVER_TAG, "Out of memory!");
660         close(gMulticastServerSocketFD);
661         gMulticastServerSocketFD = -1;
662         return CA_MEMORY_ALLOC_FAILED;
663     }
664
665     ctx->stopFlag = &gStopMulticast;
666     ctx->socket_fd = gMulticastServerSocketFD;
667     ctx->type = CA_MULTICAST_SERVER;
668
669     gStopMulticast = false;
670     if (CA_STATUS_OK != u_thread_pool_add_task(gThreadPool, CAReceiveHandler, (void *)ctx))
671     {
672         OIC_LOG(ERROR, ETHERNET_SERVER_TAG, "thread_pool_add_task failed!");
673
674         close(gMulticastServerSocketFD);
675         gMulticastServerSocketFD = -1;
676         gStopMulticast = true;
677         u_mutex_unlock(gMutexMulticastServer);
678         return CA_STATUS_FAILED;
679     }
680
681     *serverFD = gMulticastServerSocketFD;
682     strncpy(gMulticastServerInterface, localAddress, sizeof(gMulticastServerInterface));
683     u_mutex_unlock(gMutexMulticastServer);
684
685     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "OUT");
686     return CA_STATUS_OK;
687 }
688
689 CAResult_t CAEthernetStopUnicastServer()
690 {
691     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "IN");
692
693     u_mutex_lock(gMutexUnicastServer);
694     gStopUnicast = true;
695     CAResult_t ret = CACloseSocket(&gUnicastServerSocketFD);
696     u_mutex_unlock(gMutexUnicastServer);
697
698     OIC_LOG_V(INFO, ETHERNET_SERVER_TAG, "Unicast server stopped [%d]", ret);
699     return ret;
700 }
701
702 #ifdef __WITH_DTLS__
703 CAResult_t CAEthernetStopSecureUnicastServer()
704 {
705     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "IN");
706
707     u_mutex_lock(gMutexSecureUnicastServer);
708     gStopSecureUnicast = true;
709     CAResult_t ret = CACloseSocket(&gSecureUnicastServerSocketFD);
710     u_mutex_unlock(gMutexSecureUnicastServer);
711
712     OIC_LOG_V(INFO, ETHERNET_SERVER_TAG, "Secured unicast server stopped [%d]", ret);
713     return ret;
714 }
715 #endif
716
717 CAResult_t CAEthernetStopMulticastServer(void)
718 {
719     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "IN");
720
721     u_mutex_lock(gMutexMulticastServer);
722
723     if (gMulticastServerSocketFD == -1)
724     {
725         OIC_LOG(INFO, ETHERNET_SERVER_TAG, "Multicast server is not yet started");
726         u_mutex_unlock(gMutexMulticastServer);
727         return CA_SERVER_NOT_STARTED;
728     }
729
730     gStopMulticast = true;
731
732     // leave the group after you are done
733     if (-1 == setsockopt(gMulticastServerSocketFD, IPPROTO_IP, IP_DROP_MEMBERSHIP,
734                          (char *)&gMulticastMemberReq,
735                          sizeof(struct ip_mreq)))
736     {
737         OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Failed to leave multicast group, Error code: %s\n",
738                   strerror(errno));
739     }
740
741     CAResult_t ret = CACloseSocket(&gMulticastServerSocketFD);
742     u_mutex_unlock(gMutexMulticastServer);
743
744     OIC_LOG_V(INFO, ETHERNET_SERVER_TAG, "Multicast server stopped [%d]", ret);
745     return ret;
746 }
747
748 CAResult_t CAEthernetGetUnicastServerInfo(const bool isSecured, char **ipAddress, int16_t *port,
749                                           int32_t *serverFD)
750 {
751     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "IN");
752
753     // Input validation
754     VERIFY_NON_NULL(ipAddress, ETHERNET_SERVER_TAG, "IP address");
755     VERIFY_NON_NULL(port, ETHERNET_SERVER_TAG, "Port");
756     VERIFY_NON_NULL(serverFD, ETHERNET_SERVER_TAG, "Server ID");
757
758     struct sockaddr_in sockAddr;
759     socklen_t len = sizeof(struct sockaddr_in);
760     if (-1 == getsockname(gUnicastServerSocketFD, (struct sockaddr *)&sockAddr, &len))
761     {
762         OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Failed in getsockname [%s]!", strerror(errno));
763         return CA_STATUS_FAILED;
764     }
765
766
767     const char *serverAddress = inet_ntoa(sockAddr.sin_addr);
768     *ipAddress = (serverAddress) ? strndup(serverAddress, strlen(serverAddress)) : NULL;
769     *port = ntohs(sockAddr.sin_port);
770 #ifdef __WITH_DTLS__
771     *serverFD = (CA_TRUE == isSecured) ? gSecureUnicastServerSocketFD : gUnicastServerSocketFD;
772 #else
773     *serverFD = gUnicastServerSocketFD;
774 #endif
775
776     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "OUT");
777     return CA_STATUS_OK;
778 }
779
780 void CAEthernetSetPacketReceiveCallback(CAEthernetPacketReceivedCallback callback)
781 {
782     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "IN");
783     gPacketReceivedCallback = callback;
784 }
785
786 void CAEthernetSetExceptionCallback(CAEthernetExceptionCallback callback)
787 {
788     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "IN");
789     gExceptionCallback = callback;
790 }