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