Replace glib threadpool usage with a 'dumb' thread implementation.
[platform/upstream/iotivity.git] / resource / csdk / connectivity / src / wifi_adapter / linux / 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
21 // Defining _POSIX_C_SOURCE macro with 200809L (or greater) as value
22 // causes header files to expose definitions
23 // corresponding to the POSIX.1-2008 base
24 // specification (excluding the XSI extension).
25 // For POSIX.1-2008 base specification,
26 // Refer http://pubs.opengroup.org/stage7tc1/
27 //
28 // For this specific file, see use of strndup,
29 // Refer http://man7.org/linux/man-pages/man3/strdup.3.html
30 #ifndef _POSIX_C_SOURCE
31 #define _POSIX_C_SOURCE 200809L
32 #endif
33
34 // Defining _BSD_SOURCE or _DEFAULT_SOURCE causes header files to expose
35 // definitions that may otherwise be skipped. Skipping can cause implicit
36 // declaration warnings and/or bugs and subtle problems in code execution.
37 // For glibc information on feature test macros,
38 // Refer http://www.gnu.org/software/libc/manual/html_node/Feature-Test-Macros.html
39 //
40 // This file requires #define use due to struct ip_mreq
41 #define _DEFAULT_SOURCE
42 #define _BSD_SOURCE
43 #include <netinet/in.h>
44
45 #include "cawifiinterface.h"
46
47 #include <sys/types.h>
48 #include <sys/socket.h>
49 #include <unistd.h>
50 #include <fcntl.h>
51 #include <sys/select.h>
52 #include <arpa/inet.h>
53 #include <netinet/in.h>
54 #include <errno.h>
55
56 #include "pdu.h"
57 #include "caadapterutils.h"
58 #ifdef __WITH_DTLS__
59 #include "caadapternetdtls.h"
60 #endif
61 #include "camutex.h"
62 #include "oic_malloc.h"
63
64 // TODO g_stopSecureUnicast is set but never used. The three groups of
65 // globals should be combined into three instances of a common struct.
66
67 #define PIPE_READ_FD 0
68
69 #define PIPE_WRITE_FD 1
70
71 /**
72  * @def WIFI_SERVER_TAG
73  * @brief Logging tag for module name
74  */
75 #define WIFI_SERVER_TAG "WIFI_SERVER"
76
77 /**
78  * @def CA_UDP_BIND_RETRY_COUNT
79  * @brief Retry count in case of socket bind failure.
80  */
81 #define CA_UDP_BIND_RETRY_COUNT 10
82
83 /**
84  * @def IPNAMESIZE
85  * @brief max length for ip
86  */
87 #define IPNAMESIZE 16
88
89 /**
90  * @var g_unicastServerSocketFD
91  * @brief Unicast server socket descriptor
92  */
93 static int32_t g_unicastServerSocketFD = -1;
94
95 /**
96  * @var g_mutexUnicastServer
97  * @brief Mutex to synchronize unicast server
98  */
99 static ca_mutex g_mutexUnicastServer = NULL;
100
101 /**
102  * @var g_stopUnicast
103  * @brief Flag to control the Receive Unicast Data Thread
104  */
105 static bool g_stopUnicast = false;
106
107 /**
108  * Handle to interrupt unicast server for stopping, etc.
109  */
110 static int g_unicastTriggerFD = -1;
111
112 /**
113  * @var g_multicastServerSocketFD
114  * @brief socket descriptor for multicast server
115  */
116 static int32_t g_multicastServerSocketFD = -1;
117
118 /**
119  * @var g_mutexMulticastServer
120  * @brief Mutex to synchronize secure multicast server
121  */
122 static ca_mutex g_mutexMulticastServer = NULL;
123
124 /**
125  * @var g_stopMulticast
126  * @brief Flag to control the Receive Multicast Data Thread
127  */
128 static bool g_stopMulticast = false;
129
130 /**
131  * Handle to interrupt multicast server for stopping, etc.
132  */
133 static int g_multicastTriggerFD = -1;
134
135 #ifdef __WITH_DTLS__
136 /**
137  * @var g_secureUnicastServerSocketFD
138  * @brief Secure unicast server socket descriptor
139  */
140 static int32_t g_secureUnicastServerSocketFD = -1;
141
142 /**
143  * @var g_mutexSecureUnicastServer
144  * @brief Mutex to synchronize secure unicast server
145  */
146 static ca_mutex g_mutexSecureUnicastServer = NULL;
147
148 /**
149  * @var g_stopSecureUnicast
150  * @brief Flag to control the unicast secure data receive thread
151  */
152 static bool g_stopSecureUnicast = false;
153 #endif
154
155 /**
156  * @var g_threadPool
157  * @brief ThreadPool for storing ca_thread_pool_t handle passed from adapter
158  */
159 static ca_thread_pool_t g_threadPool = NULL;
160
161 /**
162  * @var g_multicastServerInterface
163  * @brief Local interface on which multicast server is running
164  */
165 static char g_multicastServerInterface[IPNAMESIZE];
166
167 /**
168  * @var g_multicastMemberReq
169  * @brief ip_mreq structure passed to join a multicast group
170  */
171 static struct ip_mreq g_multicastMemberReq;
172
173 /**
174  * @var g_packetReceivedCallback
175  * @brief Callback for notifying the upper layer on receival data from remote OIC device
176  */
177 static CAWiFiPacketReceivedCallback g_packetReceivedCallback = NULL;
178
179 /**
180  * @var g_exceptionCallback
181  * @brief Callback for notifying the upper layer when unicast/multicast server encounters exception
182  */
183 static CAWiFiExceptionCallback g_exceptionCallback = NULL;
184
185 /**
186  @brief Thread context information for unicast, multicast and secured unicast server
187  */
188 typedef struct
189 {
190     bool *stopFlag;
191     int stopFd;
192     int32_t socket_fd;
193     CAAdapterServerType_t type;
194 } CAAdapterReceiveThreadContext_t;
195
196 /**
197  * Creates a non-blocking pipe.
198  *
199  * Creates a pipe with two file descriptors then sets both to be
200  * non-blocking. If an error occurs setting flags, any created handles
201  * will be closed and set to -1.
202  *
203  * @param pipefd array of two ints to store the pipe handles in.
204  *
205  * @return 0 on success, -1 otherwise.
206  */
207 static int createNonblockingPipe(int pipefd[2]);
208
209 /**
210  * Sets the given file descriptor to be non-blocking.
211  *
212  * @param fd the file descriptor to make non-blocking.
213  *
214  * @return 0 on success, -1 otherwise.
215  */
216 static int setNonblocking(int fd);
217
218 static void CAReceiveHandler(void *data)
219 {
220     OIC_LOG(DEBUG, WIFI_SERVER_TAG, "IN");
221     // Input validation
222     VERIFY_NON_NULL_VOID(data, WIFI_SERVER_TAG, "Invalid thread context");
223
224     CAAdapterReceiveThreadContext_t *ctx = (CAAdapterReceiveThreadContext_t *) data;
225     fd_set reads;
226     struct timeval timeout;
227     char recvBuffer[COAP_MAX_PDU_SIZE] =
228     { 0 };
229
230     while (true != *(ctx->stopFlag))
231     {
232         // safe to set longer value as select can be interrupted.
233         timeout.tv_sec = 10;
234         timeout.tv_usec = 0;
235
236         FD_ZERO(&reads);
237         FD_SET(ctx->socket_fd, &reads);
238         int highest = (ctx->stopFd > ctx->socket_fd) ? ctx->stopFd : ctx->socket_fd;
239         if (ctx->stopFd != -1)
240         {
241             FD_SET(ctx->stopFd, &reads);
242         }
243
244         int32_t ret = select(highest + 1, &reads, NULL, NULL, &timeout);
245         if (*(ctx->stopFlag) == true)
246         {
247             OIC_LOG_V(DEBUG, WIFI_SERVER_TAG, "Stop request received for [%d] server", ctx->type);
248             break;
249         }
250         if (ret < 0)
251         {
252             OIC_LOG_V(FATAL, WIFI_SERVER_TAG, "select returned error %s", strerror(errno));
253             continue;
254         }
255
256         if ((ctx->stopFd != -1) && FD_ISSET(ctx->stopFd, &reads))
257         {
258             // Doesn't matter at this point what happens (errors can be
259             // ignored). Just drain some data if this code ever gets hit.
260             recv(ctx->stopFd, recvBuffer, sizeof(recvBuffer), MSG_DONTWAIT);
261         }
262
263         if (!FD_ISSET(ctx->socket_fd, &reads))
264         {
265             continue;
266         }
267
268         memset(recvBuffer, 0, sizeof(recvBuffer));
269
270         // Read data from socket
271         struct sockaddr_in srcSockAddress;
272         int32_t recvLen;
273         socklen_t srcAddressLen = sizeof(srcSockAddress);
274         if (-1
275                 == (recvLen = recvfrom(ctx->socket_fd, recvBuffer, sizeof(recvBuffer), 0,
276                         (struct sockaddr *) &srcSockAddress, &srcAddressLen)))
277         {
278             OIC_LOG_V(DEBUG, WIFI_SERVER_TAG, "%s", strerror(errno));
279             continue;
280         }
281         else if (0 == recvLen)
282         {
283             OIC_LOG_V(ERROR, WIFI_SERVER_TAG, "Server socket shutdown [%d]!", ctx->type);
284
285             // Notify upper layer this exception
286             if (g_exceptionCallback)
287             {
288                 g_exceptionCallback(ctx->type);
289             }
290             if (ctx->stopFd != -1)
291             {
292                 close(ctx->stopFd);
293             }
294             OICFree(ctx);
295             return;
296         }
297
298         const char *srcIPAddress = NULL;
299         uint16_t srcPort = 0;
300
301         srcIPAddress = inet_ntoa(srcSockAddress.sin_addr);
302         srcPort = ntohs(srcSockAddress.sin_port);
303
304         OIC_LOG_V(DEBUG, WIFI_SERVER_TAG, "Received packet from %s:%d\n", srcIPAddress, srcPort);
305         OIC_LOG_V(DEBUG, WIFI_SERVER_TAG, "Data: %s\t, DataLength: %d\n", recvBuffer, recvLen);
306
307         char *netMask = NULL;
308         if (CA_STATUS_OK != CAWiFiGetInterfaceSubnetMask(&netMask))
309         {
310             OIC_LOG(ERROR, WIFI_SERVER_TAG, "Failed to get ethernet subnet");
311             continue;
312         }
313
314         if (!CAAdapterIsSameSubnet(g_multicastServerInterface, srcIPAddress, netMask))
315         {
316             OIC_LOG(DEBUG, WIFI_SERVER_TAG, "Packet received from different subnet, Ignore!");
317             if (NULL != netMask)
318             {
319                 OICFree(netMask);
320             }
321             netMask = NULL;
322             continue;
323         }
324
325         OICFree(netMask);
326         switch (ctx->type)
327         {
328             case CA_UNICAST_SERVER:
329             case CA_MULTICAST_SERVER:
330                 // Notify data to upper layer
331                 if (g_packetReceivedCallback)
332                 {
333                     g_packetReceivedCallback(srcIPAddress, srcPort, recvBuffer, recvLen, false);
334                 }
335                 break;
336 #ifdef __WITH_DTLS__
337                 case CA_SECURED_UNICAST_SERVER:
338                 {
339                     CAResult_t ret = CAAdapterNetDtlsDecrypt(srcIPAddress,
340                             srcPort,
341                             (uint8_t *)recvBuffer,
342                             recvLen, DTLS_WIFI);
343                     OIC_LOG_V(DEBUG, WIFI_SERVER_TAG, "CAAdapterNetDtlsDecrypt returns [%d]", ret);
344                 }
345                 break;
346 #endif //__WITH_DTLS__
347             default:
348                 // Should never occur
349                 OIC_LOG(DEBUG, WIFI_SERVER_TAG, "Invalid server type");
350                 if (ctx->stopFd != -1)
351                 {
352                     close(ctx->stopFd);
353                 }
354                 OICFree(ctx);
355                 return;
356         }
357     }
358
359     // free context
360     if (ctx->stopFd != -1)
361     {
362         close(ctx->stopFd);
363     }
364     OICFree(ctx);
365
366     OIC_LOG(DEBUG, WIFI_SERVER_TAG, "OUT");
367 }
368
369 static CAResult_t CAWiFiCreateSocket(int32_t *socketFD, const char *localIp, uint16_t *port,
370         const bool forceStart)
371 {
372     int32_t sock = -1;
373     // Create a UDP socket
374     if (-1 == (sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)))
375     {
376         OIC_LOG_V(ERROR, WIFI_SERVER_TAG, "Failed to create Socket, Error code: %s",
377                 strerror(errno));
378         return CA_STATUS_FAILED;
379     }
380
381     // Make the socket non-blocking
382     if (-1 == setNonblocking(sock))
383     {
384         close(sock);
385         return CA_STATUS_FAILED;
386     }
387
388     if (true == forceStart)
389     {
390         int32_t setOptionOn = 1;
391         if (-1
392                 == setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &setOptionOn,
393                         sizeof(setOptionOn)))
394         {
395             OIC_LOG_V(ERROR, WIFI_SERVER_TAG, "Failed to set SO_REUSEADDR! Error code: %s",
396                     strerror(errno));
397
398             close(sock);
399             return CA_STATUS_FAILED;
400         }
401     }
402
403     struct sockaddr_in sockAddr;
404     bool isBound = false;
405     uint16_t serverPort = 0;
406     if (port)
407     {
408         serverPort = *port;
409     }
410     else
411     {
412         close(sock);
413         return CA_STATUS_INVALID_PARAM;
414     }
415
416     memset((char *) &sockAddr, 0, sizeof(sockAddr));
417     sockAddr.sin_family = AF_INET;
418     sockAddr.sin_port = htons(serverPort);
419     if (localIp)
420     {
421         sockAddr.sin_addr.s_addr = inet_addr(localIp);
422     }
423     else
424     {
425         sockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
426     }
427
428     int16_t i;
429     for (i = 0; i < CA_UDP_BIND_RETRY_COUNT; i++)
430     {
431         if (-1 == bind(sock, (struct sockaddr *) &sockAddr, sizeof(sockAddr)))
432         {
433             if (false == forceStart)
434             {
435                 OIC_LOG_V(ERROR, WIFI_SERVER_TAG, "Failed to bind socket[%s]. Trying again..",
436                         strerror(errno));
437
438                 //Set the port to next one
439                 serverPort += 1;
440                 sockAddr.sin_port = htons(serverPort);
441                 continue;
442             }
443             else
444             {
445                 OIC_LOG_V(ERROR, WIFI_SERVER_TAG, "Failed to bind socket[%s]!", strerror(errno));
446                 break;
447             }
448         }
449
450         isBound = true;
451         break;
452     }
453
454     if (false == isBound)
455     {
456         close(sock);
457         return CA_STATUS_FAILED;
458     }
459
460     *port = serverPort;
461     *socketFD = sock;
462     return CA_STATUS_OK;
463 }
464
465 static CAResult_t CAWiFiCloseSocket(int32_t *socketFD)
466 {
467     if (socketFD == NULL)
468     {
469         return CA_STATUS_INVALID_PARAM;
470     }
471
472     if (-1 == *socketFD)
473     {
474         OIC_LOG(INFO, WIFI_SERVER_TAG, "Server not running");
475         return CA_SERVER_NOT_STARTED;
476     }
477
478     // close the socket
479     if (-1 == close(*socketFD))
480     {
481         OIC_LOG_V(ERROR, WIFI_SERVER_TAG, "Failed to close the socket, Error code: %s\n",
482                 strerror(errno));
483         return CA_STATUS_FAILED;
484     }
485
486     *socketFD = -1;
487     return CA_STATUS_OK;
488 }
489
490 static CAResult_t CAStartUnicastServer(const char *localAddress, uint16_t *port,
491         const bool forceStart, bool isSecured, int32_t *serverFD)
492 {
493     OIC_LOG(DEBUG, WIFI_SERVER_TAG, "IN");
494
495     if (serverFD == NULL)
496     {
497         return CA_STATUS_INVALID_PARAM;
498     }
499
500     CAResult_t ret = CAWiFiCreateSocket(serverFD, localAddress, port, forceStart);
501     if (CA_STATUS_OK != ret)
502     {
503         OIC_LOG(ERROR, WIFI_SERVER_TAG, "Failed to create unicast socket");
504         return ret;
505     }
506
507     /**
508      * The task to listen for data from unicast socket is added to the thread pool.
509      * This is a blocking call is made where we try to receive some data..
510      * We will keep waiting until some data is received.
511      * This task will be terminated when thread pool is freed on stopping the adapters.
512      * Thread context will be freed by thread on exit.
513      */
514     CAAdapterReceiveThreadContext_t *ctx = (CAAdapterReceiveThreadContext_t *) OICMalloc(
515             sizeof(CAAdapterReceiveThreadContext_t));
516     if (!ctx)
517     {
518         OIC_LOG(ERROR, WIFI_SERVER_TAG, "Out of memory!");
519         close(*serverFD);
520         return CA_MEMORY_ALLOC_FAILED;
521     }
522
523     int pipefd[2] = {-1, -1};
524     if (createNonblockingPipe(pipefd) != 0)
525     {
526         OIC_LOG(ERROR, WIFI_SERVER_TAG, "Failed to create pipe");
527         OICFree(ctx);
528         close(*serverFD);
529         *serverFD = -1;
530         return CA_STATUS_FAILED;
531     }
532
533     g_unicastTriggerFD = pipefd[PIPE_WRITE_FD]; // The write end of the pipe
534
535     ctx->stopFlag = &g_stopUnicast;
536     ctx->stopFd = pipefd[PIPE_READ_FD]; // The read end of the pipe
537     ctx->socket_fd = *serverFD;
538     ctx->type = isSecured ? CA_SECURED_UNICAST_SERVER : CA_UNICAST_SERVER;
539     if (CA_STATUS_OK != ca_thread_pool_add_task(g_threadPool, CAReceiveHandler, (void *) ctx))
540     {
541         OIC_LOG(ERROR, WIFI_SERVER_TAG, "Failed to create read thread!");
542
543         close(g_unicastTriggerFD);
544         g_unicastTriggerFD = -1;
545         close(ctx->stopFd);
546         ctx->stopFd = -1;
547
548         OICFree((void *) ctx);
549         close(*serverFD);
550         return CA_STATUS_FAILED;
551     }
552
553     OIC_LOG(DEBUG, WIFI_SERVER_TAG, "OUT");
554     return CA_STATUS_OK;
555 }
556
557 static void CAWiFiServerDestroyMutex(void)
558 {
559     OIC_LOG(DEBUG, WIFI_SERVER_TAG, "IN");
560
561     if (g_mutexUnicastServer)
562     {
563         ca_mutex_free(g_mutexUnicastServer);
564         g_mutexUnicastServer = NULL;
565     }
566
567 #ifdef __WITH_DTLS__
568     if (g_mutexSecureUnicastServer)
569     {
570         ca_mutex_free(g_mutexSecureUnicastServer);
571         g_mutexSecureUnicastServer = NULL;
572     }
573 #endif
574
575     if (g_mutexMulticastServer)
576     {
577         ca_mutex_free(g_mutexMulticastServer);
578         g_mutexMulticastServer = NULL;
579     }
580
581     OIC_LOG(DEBUG, WIFI_SERVER_TAG, "OUT");
582 }
583
584 static CAResult_t CAWiFiServerCreateMutex(void)
585 {
586     OIC_LOG(DEBUG, WIFI_SERVER_TAG, "IN");
587
588     g_mutexUnicastServer = ca_mutex_new();
589     if (!g_mutexUnicastServer)
590     {
591         OIC_LOG(ERROR, WIFI_SERVER_TAG, "Failed to created mutex!");
592         return CA_STATUS_FAILED;
593     }
594
595 #ifdef __WITH_DTLS__
596     g_mutexSecureUnicastServer = ca_mutex_new();
597     if (!g_mutexSecureUnicastServer)
598     {
599         OIC_LOG(ERROR, WIFI_SERVER_TAG, "Failed to created mutex!");
600
601         CAWiFiServerDestroyMutex();
602         return CA_STATUS_FAILED;
603     }
604 #endif
605
606     g_mutexMulticastServer = ca_mutex_new();
607     if (!g_mutexMulticastServer)
608     {
609         OIC_LOG(ERROR, WIFI_SERVER_TAG, "Failed to created mutex!");
610
611         CAWiFiServerDestroyMutex();
612         return CA_STATUS_FAILED;
613     }
614
615     OIC_LOG(DEBUG, WIFI_SERVER_TAG, "OUT");
616     return CA_STATUS_OK;
617 }
618
619 CAResult_t CAWiFiInitializeServer(const ca_thread_pool_t threadPool)
620 {
621     OIC_LOG(DEBUG, WIFI_SERVER_TAG, "IN");
622
623     // Input validation
624     VERIFY_NON_NULL(threadPool, WIFI_SERVER_TAG, "Thread pool handle is NULL");
625
626     // Initialize mutex
627     if (CA_STATUS_OK != CAWiFiServerCreateMutex())
628     {
629         OIC_LOG(ERROR, WIFI_SERVER_TAG, "Failed to create mutex!");
630         return CA_STATUS_FAILED;
631     }
632
633     g_threadPool = threadPool;
634
635     OIC_LOG(DEBUG, WIFI_SERVER_TAG, "OUT");
636     return CA_STATUS_OK;
637 }
638
639 void CAWiFiTerminateServer(void)
640 {
641     OIC_LOG(DEBUG, WIFI_SERVER_TAG, "IN");
642
643     g_threadPool = NULL;
644
645     // Destroy mutex
646     CAWiFiServerDestroyMutex();
647
648     OIC_LOG(DEBUG, WIFI_SERVER_TAG, "OUT");
649 }
650
651 CAResult_t CAWiFiStartUnicastServer(const char *localAddress, uint16_t *port, const bool forceStart,
652         const bool isSecured, int32_t *serverFD)
653 {
654     OIC_LOG(DEBUG, WIFI_SERVER_TAG, "IN");
655
656     // Input validation
657     VERIFY_NON_NULL(localAddress, WIFI_SERVER_TAG, "localAddress");
658     VERIFY_NON_NULL(port, WIFI_SERVER_TAG, "port");
659     VERIFY_NON_NULL(serverFD, WIFI_SERVER_TAG, "server socket FD");
660
661     if (0 >= *port)
662     {
663         OIC_LOG(ERROR, WIFI_SERVER_TAG, "Invalid input: port is invalid!");
664         return CA_STATUS_INVALID_PARAM;
665     }
666
667     *serverFD = -1;
668     if (false == isSecured)
669     {
670         ca_mutex_lock(g_mutexUnicastServer);
671         if (-1 != g_unicastServerSocketFD)
672         {
673             OIC_LOG_V(ERROR, WIFI_SERVER_TAG, "Unicast Server is Started Already!",
674                     CA_SERVER_STARTED_ALREADY);
675
676             *serverFD = g_unicastServerSocketFD;
677             ca_mutex_unlock(g_mutexUnicastServer);
678             return CA_SERVER_STARTED_ALREADY;
679         }
680
681         g_stopUnicast = false;
682         if (CA_STATUS_OK
683                 != CAStartUnicastServer(localAddress, port, forceStart, isSecured,
684                         &g_unicastServerSocketFD))
685         {
686             OIC_LOG(ERROR, WIFI_SERVER_TAG, "Failed to start unicast server!");
687             g_unicastServerSocketFD = -1;
688             ca_mutex_unlock(g_mutexUnicastServer);
689             return CA_STATUS_FAILED;
690         }
691
692         *serverFD = g_unicastServerSocketFD;
693         ca_mutex_unlock(g_mutexUnicastServer);
694     }
695 #ifdef __WITH_DTLS__
696     else // Start unicast server for secured communication
697     {
698         ca_mutex_lock(g_mutexSecureUnicastServer);
699         if (-1 != g_secureUnicastServerSocketFD)
700         {
701             OIC_LOG_V(ERROR, WIFI_SERVER_TAG, "Unicast Server is Started Already!",
702                     CA_SERVER_STARTED_ALREADY);
703
704             *serverFD = g_secureUnicastServerSocketFD;
705             ca_mutex_unlock(g_mutexSecureUnicastServer);
706             return CA_SERVER_STARTED_ALREADY;
707         }
708
709         g_stopSecureUnicast = false;
710         if (CA_STATUS_OK != CAStartUnicastServer(localAddress, port, forceStart, isSecured,
711                         &g_secureUnicastServerSocketFD))
712         {
713             OIC_LOG(ERROR, WIFI_SERVER_TAG, "Failed to start unicast server!");
714             g_secureUnicastServerSocketFD = -1;
715             ca_mutex_unlock(g_mutexSecureUnicastServer);
716             return CA_STATUS_FAILED;
717         }
718
719         *serverFD = g_secureUnicastServerSocketFD;
720         ca_mutex_unlock(g_mutexSecureUnicastServer);
721     }
722 #endif
723     OIC_LOG(DEBUG, WIFI_SERVER_TAG, "OUT");
724     return CA_STATUS_OK;
725 }
726
727 CAResult_t CAWiFiStartMulticastServer(const char *localAddress, const char *multicastAddress,
728         const uint16_t multicastPort, int32_t *serverFD)
729 {
730     OIC_LOG(DEBUG, WIFI_SERVER_TAG, "IN");
731
732     // Input validation
733     VERIFY_NON_NULL(localAddress, WIFI_SERVER_TAG, "localAddress");
734     VERIFY_NON_NULL(multicastAddress, WIFI_SERVER_TAG, "port");
735     VERIFY_NON_NULL(serverFD, WIFI_SERVER_TAG, "server socket FD");
736
737     uint16_t port = multicastPort;
738     if (0 >= port)
739     {
740         OIC_LOG(ERROR, WIFI_SERVER_TAG, "Invalid input: Multicast port is invalid!");
741         return CA_STATUS_INVALID_PARAM;
742     }
743
744     ca_mutex_lock(g_mutexMulticastServer);
745
746     if (g_multicastServerSocketFD != -1)
747     {
748         OIC_LOG(ERROR, WIFI_SERVER_TAG, "Multicast Server is already running!");
749         ca_mutex_unlock(g_mutexMulticastServer);
750         return CA_SERVER_STARTED_ALREADY;
751     }
752
753     CAResult_t ret = CAWiFiCreateSocket(&g_multicastServerSocketFD, multicastAddress, &port, true);
754     if (ret != CA_STATUS_OK)
755     {
756         OIC_LOG(ERROR, WIFI_SERVER_TAG, "Failed to create multicast socket");
757         ca_mutex_unlock(g_mutexMulticastServer);
758         return ret;
759     }
760
761     // Add membership to receiving socket (join group)
762     memset(&g_multicastMemberReq, 0, sizeof(struct ip_mreq));
763     g_multicastMemberReq.imr_interface.s_addr = inet_addr(localAddress);
764     inet_aton(multicastAddress, &g_multicastMemberReq.imr_multiaddr);
765
766     if (-1
767             == setsockopt(g_multicastServerSocketFD, IPPROTO_IP, IP_ADD_MEMBERSHIP,
768                     (char *) &g_multicastMemberReq, sizeof(struct ip_mreq)))
769     {
770         OIC_LOG_V(ERROR, WIFI_SERVER_TAG, "Failed to add to multicast group, Error code: %s\n",
771                 strerror(errno));
772         close(g_multicastServerSocketFD);
773         g_multicastServerSocketFD = -1;
774         ca_mutex_unlock(g_mutexMulticastServer);
775         return CA_STATUS_FAILED;
776     }
777
778     /**
779      * The task to listen to data from multicastcast socket is added to the thread pool.
780      * This is a blocking call is made where we try to receive some data.
781      * We will keep waiting until some data is received.
782      * This task will be terminated when thread pool is freed on stopping the adapters.
783      * Thread context will be freed by thread on exit.
784      */
785     CAAdapterReceiveThreadContext_t *ctx = (CAAdapterReceiveThreadContext_t *) OICMalloc(
786             sizeof(CAAdapterReceiveThreadContext_t));
787     if (!ctx)
788     {
789         OIC_LOG(ERROR, WIFI_SERVER_TAG, "Out of memory!");
790         close(g_multicastServerSocketFD);
791         g_multicastServerSocketFD = -1;
792         return CA_MEMORY_ALLOC_FAILED;
793     }
794
795     int pipefd[2] = {-1, -1};
796     if (createNonblockingPipe(pipefd) != 0)
797     {
798         OIC_LOG(ERROR, WIFI_SERVER_TAG, "Failed to create pipe");
799         OICFree(ctx);
800         close(g_multicastServerSocketFD);
801         g_multicastServerSocketFD = -1;
802         return CA_STATUS_FAILED;
803     }
804
805     g_multicastTriggerFD = pipefd[PIPE_WRITE_FD]; // The write end of the pipe
806
807     ctx->stopFlag = &g_stopMulticast;
808     ctx->stopFd = pipefd[PIPE_READ_FD]; // The read end of the pipe
809     ctx->socket_fd = g_multicastServerSocketFD;
810     ctx->type = CA_MULTICAST_SERVER;
811
812     g_stopMulticast = false;
813     if (CA_STATUS_OK != ca_thread_pool_add_task(g_threadPool, CAReceiveHandler, (void *) ctx))
814     {
815         OIC_LOG(ERROR, WIFI_SERVER_TAG, "thread_pool_add_task failed!");
816
817         close(g_multicastTriggerFD);
818         g_multicastTriggerFD = -1;
819         close(ctx->stopFd);
820         ctx->stopFd = -1;
821
822         close(g_multicastServerSocketFD);
823         g_multicastServerSocketFD = -1;
824         g_stopMulticast = true;
825         ca_mutex_unlock(g_mutexMulticastServer);
826         return CA_STATUS_FAILED;
827     }
828
829     *serverFD = g_multicastServerSocketFD;
830     strncpy(g_multicastServerInterface, localAddress, IPNAMESIZE);
831     ca_mutex_unlock(g_mutexMulticastServer);
832
833     OIC_LOG(DEBUG, WIFI_SERVER_TAG, "OUT");
834     return CA_STATUS_OK;
835 }
836
837 CAResult_t CAWiFiStopUnicastServer()
838 {
839     OIC_LOG(DEBUG, WIFI_SERVER_TAG, "IN");
840
841     ca_mutex_lock(g_mutexUnicastServer);
842     g_stopUnicast = true;
843     if (g_unicastTriggerFD != -1)
844     {
845         if (write(g_unicastTriggerFD, "X", 1) == -1)
846         {
847             OIC_LOG_V(ERROR, WIFI_SERVER_TAG,
848                       "Failed to write to trigger, Error code: %s",
849                       strerror(errno));
850         }
851         close(g_unicastTriggerFD);
852         g_unicastTriggerFD = -1;
853     }
854     CAResult_t ret = CAWiFiCloseSocket(&g_unicastServerSocketFD);
855     ca_mutex_unlock(g_mutexUnicastServer);
856
857     OIC_LOG_V(INFO, WIFI_SERVER_TAG, "Unicast server stopped [%d]", ret);
858     return ret;
859 }
860
861 #ifdef __WITH_DTLS__
862 CAResult_t CAWiFiStopSecureUnicastServer()
863 {
864     OIC_LOG(DEBUG, WIFI_SERVER_TAG, "IN");
865
866     ca_mutex_lock(g_mutexSecureUnicastServer);
867     g_stopSecureUnicast = true;
868     if (g_unicastTriggerFD != -1)
869     {
870         if (write(g_unicastTriggerFD, "X", 1) == -1)
871         {
872             OIC_LOG_V(ERROR, WIFI_SERVER_TAG,
873                       "Failed to write to trigger, Error code: %s",
874                       strerror(errno));
875         }
876         close(g_unicastTriggerFD);
877         g_unicastTriggerFD = -1;
878     }
879     CAResult_t ret = CAWiFiCloseSocket(&g_secureUnicastServerSocketFD);
880     ca_mutex_unlock(g_mutexSecureUnicastServer);
881
882     OIC_LOG_V(INFO, WIFI_SERVER_TAG, "Secured unicast server stopped [%d]", ret);
883     return ret;
884 }
885 #endif
886
887 CAResult_t CAWiFiStopMulticastServer(void)
888 {
889     OIC_LOG(DEBUG, WIFI_SERVER_TAG, "IN");
890
891     ca_mutex_lock(g_mutexMulticastServer);
892
893     if (g_multicastServerSocketFD == -1)
894     {
895         OIC_LOG(INFO, WIFI_SERVER_TAG, "Multicast server is not yet started");
896         ca_mutex_unlock(g_mutexMulticastServer);
897         return CA_SERVER_NOT_STARTED;
898     }
899
900     g_stopMulticast = true;
901     if (g_multicastTriggerFD != -1)
902     {
903         if (write(g_multicastTriggerFD, "X", 1) == -1)
904         {
905             OIC_LOG_V(ERROR, WIFI_SERVER_TAG,
906                       "Failed to write to trigger, Error code: %s",
907                       strerror(errno));
908         }
909         close(g_multicastTriggerFD);
910         g_multicastTriggerFD = -1;
911     }
912
913     // leave the group after you are done
914     if (-1
915             == setsockopt(g_multicastServerSocketFD, IPPROTO_IP, IP_DROP_MEMBERSHIP,
916                     (char *) &g_multicastMemberReq, sizeof(struct ip_mreq)))
917     {
918         OIC_LOG_V(ERROR, WIFI_SERVER_TAG, "Failed to leave multicast group, Error code: %s\n",
919                 strerror(errno));
920     }
921
922     CAResult_t ret = CAWiFiCloseSocket(&g_multicastServerSocketFD);
923     ca_mutex_unlock(g_mutexMulticastServer);
924
925     OIC_LOG_V(INFO, WIFI_SERVER_TAG, "Multicast server stopped [%d]", ret);
926     return ret;
927 }
928
929 CAResult_t CAWiFiGetUnicastServerInfo(const bool isSecured, char **ipAddress, uint16_t *port,
930         int32_t *serverFD)
931 {
932     OIC_LOG(DEBUG, WIFI_SERVER_TAG, "IN");
933
934     // Input validation
935     VERIFY_NON_NULL(ipAddress, WIFI_SERVER_TAG, "IP address");
936     VERIFY_NON_NULL(port, WIFI_SERVER_TAG, "Port");
937     VERIFY_NON_NULL(serverFD, WIFI_SERVER_TAG, "Server ID");
938
939     struct sockaddr_in sockAddr;
940     socklen_t len = sizeof(struct sockaddr_in);
941     if (-1 == getsockname(g_unicastServerSocketFD, (struct sockaddr *) &sockAddr, &len))
942     {
943         OIC_LOG_V(ERROR, WIFI_SERVER_TAG, "Failed in getsockname [%s]!", strerror(errno));
944         return CA_STATUS_FAILED;
945     }
946
947     char serverAddress[CA_IPADDR_SIZE];
948     inet_ntop(AF_INET, &sockAddr.sin_addr.s_addr, serverAddress, sizeof(serverAddress));
949
950     *ipAddress = strndup(serverAddress, strlen(serverAddress));
951     *port = ntohs(sockAddr.sin_port);
952 #ifdef __WITH_DTLS__
953     *serverFD = (true == isSecured) ? g_secureUnicastServerSocketFD : g_unicastServerSocketFD;
954 #else
955     *serverFD = g_unicastServerSocketFD;
956 #endif
957     OIC_LOG(DEBUG, WIFI_SERVER_TAG, "OUT");
958     return CA_STATUS_OK;
959 }
960
961 void CAWiFiSetPacketReceiveCallback(CAWiFiPacketReceivedCallback callback)
962 {
963     OIC_LOG(DEBUG, WIFI_SERVER_TAG, "IN");
964
965     g_packetReceivedCallback = callback;
966 }
967
968 void CAWiFiSetExceptionCallback(CAWiFiExceptionCallback callback)
969 {
970     OIC_LOG(DEBUG, WIFI_SERVER_TAG, "IN");
971
972     g_exceptionCallback = callback;
973 }
974
975 int setNonblocking(int fd)
976 {
977     int rc = fcntl(fd, F_GETFL);
978     if (rc == -1)
979     {
980         OIC_LOG_V(ERROR, WIFI_SERVER_TAG,
981                   "Failed to get existing flags, Error code: %s",
982                   strerror(errno));
983     }
984     else
985     {
986         rc = fcntl(fd, F_SETFL, rc | O_NONBLOCK);
987         if (rc == -1)
988         {
989             OIC_LOG_V(ERROR, WIFI_SERVER_TAG,
990                       "Failed to set non-blocking mode, Error code: %s",
991                       strerror(errno));
992         }
993     }
994
995     return rc;
996 }
997
998 int createNonblockingPipe(int pipefd[2])
999 {
1000     int rc = -1;
1001     if (pipefd)
1002     {
1003         pipefd[PIPE_READ_FD] = -1;
1004         pipefd[PIPE_WRITE_FD] = -1;
1005         rc = pipe(pipefd);
1006
1007         if (rc != -1)
1008         {
1009             rc = setNonblocking(pipefd[PIPE_READ_FD]);
1010         }
1011
1012         if (rc != -1)
1013         {
1014             rc = setNonblocking(pipefd[PIPE_WRITE_FD]);
1015         }
1016
1017         if (rc == -1)
1018         {
1019             if (pipefd[PIPE_READ_FD] != -1)
1020             {
1021                 close(pipefd[PIPE_READ_FD]);
1022                 pipefd[PIPE_READ_FD] = -1;
1023             }
1024             if (pipefd[PIPE_WRITE_FD] != -1)
1025             {
1026                 close(pipefd[PIPE_WRITE_FD]);
1027                 pipefd[PIPE_WRITE_FD]= -1;
1028             }
1029         }
1030     }
1031     return rc;
1032 }