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