Resolved compilation issues related to pthread changes
[platform/upstream/iotivity.git] / resource / csdk / connectivity / src / ip_adapter / caipserver.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 #include "caipinterface.h"
22
23 #include <sys/types.h>
24 #include <sys/socket.h>
25 #include <unistd.h>
26 #include <fcntl.h>
27 #include <sys/select.h>
28 #include <arpa/inet.h>
29 #include <netinet/in.h>
30 #include <errno.h>
31
32 #include "pdu.h"
33 #include "caadapterutils.h"
34 #ifdef __WITH_DTLS__
35 #include "caadapternetdtls.h"
36 #endif
37 #include "camutex.h"
38 #include "oic_malloc.h"
39
40 /**
41  * @def IP_SERVER_TAG
42  * @brief Logging tag for module name
43  */
44 #define IP_SERVER_TAG "IP_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 address.
55  */
56 #define IPNAMESIZE 16
57
58 /**
59  * @def SOCKETOPTION
60  * @brief Socket option.
61  */
62 #define SOCKETOPTION 1
63
64 /**
65  * @var g_packetHandlerStopFlag
66  * @brief Flag for stopping packet handler thread.
67  */
68 static bool g_packetHandlerStopFlag = false;
69
70 /**
71  * @var CAAdapterIPServerContext_t
72  * @brief Thread context information for callbacks and threadpool.
73  */
74 typedef struct
75 {
76     ca_thread_pool_t threadPool;
77     CAIPPacketReceivedCallback packetReceivedCallback;
78     CAIPExceptionCallback exceptionCallback;
79 } CAAdapterIPServerContext_t;
80
81 /**
82  * @var g_serverInfoList
83  * @brief Mutex to synchronize ethenet adapter context.
84  */
85 static u_arraylist_t *g_serverInfoList = NULL;
86
87 /**
88  * @var g_mutexServerInfoList
89  * @brief Mutex to synchronize Server Information.
90  */
91 static ca_mutex g_mutexServerInfoList = NULL;
92
93 /**
94  * @var g_adapterEthServerContext
95  * @brief Mutex to synchronize ethenet adapter context.
96  */
97 static CAAdapterIPServerContext_t *g_adapterEthServerContext = NULL;
98
99 /**
100  * @var g_mutexAdapterServerContext
101  * @brief Mutex to synchronize unicast server
102  */
103 static ca_mutex g_mutexAdapterServerContext = NULL;
104
105 static void CAReceiveHandler(void *data)
106 {
107     OIC_LOG(DEBUG, IP_SERVER_TAG, "IN");
108
109     fd_set readFds;
110     int maxSd = 0;
111     struct timeval timeout;
112     char recvBuffer[COAP_MAX_PDU_SIZE] = { 0 };
113
114     while (true != g_packetHandlerStopFlag)
115     {
116         timeout.tv_sec = 1;
117         timeout.tv_usec = 0;
118         FD_ZERO(&readFds);
119
120         ca_mutex_lock(g_mutexServerInfoList);
121         uint32_t listIndex = 0;
122         uint32_t listLength = u_arraylist_length(g_serverInfoList);
123
124         u_arraylist_t *tempServerInfoList = u_arraylist_create();
125         if (!tempServerInfoList)
126         {
127             OIC_LOG(ERROR, IP_SERVER_TAG, "u_arraylist_create failed");
128             ca_mutex_unlock(g_mutexServerInfoList);
129             return;
130         }
131
132         for (listIndex = 0; listIndex < listLength; listIndex++)
133         {
134             CAServerInfo_t *info = (CAServerInfo_t *) u_arraylist_get(g_serverInfoList, listIndex);
135             if (!info)
136             {
137                 listIndex++;
138                 continue;
139             }
140
141             int sd = info->socketFd;
142             //if valid socket descriptor then add to read list
143             if (sd > 0)
144             {
145                 FD_SET(sd, &readFds);
146             }
147
148             //highest file descriptor number, need it for the select function
149             if (sd > maxSd)
150             {
151                 maxSd = sd;
152             }
153
154             CAServerInfo_t *newInfo = (CAServerInfo_t *) OICMalloc(sizeof(CAServerInfo_t));
155             if (!newInfo)
156             {
157                 OIC_LOG(ERROR, IP_SERVER_TAG, "Malloc failed");
158                 CAClearServerInfoList(tempServerInfoList);
159                 ca_mutex_unlock(g_mutexServerInfoList);
160                 return;
161             }
162
163             memcpy(newInfo, info, sizeof(CAServerInfo_t));
164
165             CAResult_t result = u_arraylist_add(tempServerInfoList, (void *) newInfo);
166             if (CA_STATUS_OK != result)
167             {
168                 OIC_LOG(ERROR, IP_SERVER_TAG, "u_arraylist_add failed!Thread exit");
169                 CAClearServerInfoList(tempServerInfoList);
170                 ca_mutex_unlock(g_mutexServerInfoList);
171                 return;
172             }
173         }
174
175         ca_mutex_unlock(g_mutexServerInfoList);
176
177         int ret = select(maxSd + 1, &readFds, NULL, NULL, &timeout);
178         if (g_packetHandlerStopFlag)
179         {
180             OIC_LOG_V(DEBUG, IP_SERVER_TAG,
181                       "Packet receiver handler Stop request received. Thread exited");
182             CAClearServerInfoList(tempServerInfoList);
183             break;
184         }
185         if (ret < 0)
186         {
187             OIC_LOG_V(FATAL, IP_SERVER_TAG, "select returned error %s", strerror(errno));
188             CAClearServerInfoList(tempServerInfoList);
189             continue;
190         }
191
192         listLength = u_arraylist_length(tempServerInfoList);
193         for (listIndex = 0; listIndex < listLength; listIndex++)
194         {
195             CAServerInfo_t *info = (CAServerInfo_t *) u_arraylist_get(tempServerInfoList,
196                                                                       listIndex);
197             if (!info)
198             {
199                 continue;
200             }
201
202             int sd = info->socketFd;
203             if (FD_ISSET(sd , &readFds))
204             {
205                 OIC_LOG_V(ERROR, IP_SERVER_TAG,
206                           "data Received server information ip %s, port %d socket %d",
207                           info->ipAddress, info->port, sd);
208                 memset(recvBuffer, 0, sizeof(recvBuffer));
209
210                 struct sockaddr_in srcSockAddress = { 0 };
211                 socklen_t srcAddressLen = sizeof(srcSockAddress);
212
213                 //Reading from socket
214                 ssize_t recvLen = recvfrom(sd, recvBuffer, sizeof(recvBuffer), 0,
215                                            (struct sockaddr *) &srcSockAddress, &srcAddressLen);
216                 if (-1 == recvLen)
217                 {
218                     OIC_LOG_V(ERROR, IP_SERVER_TAG, "Recvfrom failed %s", strerror(errno));
219                     continue;
220                 }
221                 else if (0 == recvLen)
222                 {
223                     OIC_LOG_V(ERROR, IP_SERVER_TAG, "Server socket shutdown sock fd[%d]", sd);
224                     ca_mutex_lock(g_mutexAdapterServerContext);
225                     // Notify upper layer this exception
226                     if (g_adapterEthServerContext->exceptionCallback)
227                     {
228                         // need to make proper exception callback.
229                         //g_adapterEthServerContext->exceptionCallback(ctx->type);
230                     }
231                     ca_mutex_unlock(g_mutexAdapterServerContext);
232                 }
233
234                 char srcIPAddress[CA_IPADDR_SIZE] = { 0 };
235                 if (!inet_ntop(AF_INET, &srcSockAddress.sin_addr.s_addr, srcIPAddress,
236                                sizeof(srcIPAddress)))
237                 {
238
239                     OIC_LOG(ERROR, IP_SERVER_TAG, "inet_ntop is failed!");
240                     continue;
241                 }
242
243                 uint16_t srcPort = ntohs(srcSockAddress.sin_port);
244
245                 OIC_LOG_V(DEBUG, IP_SERVER_TAG, "Received packet from %s:%d len %d",
246                           srcIPAddress, srcPort, recvLen);
247
248                 char *netMask = NULL;
249                 if (CA_STATUS_OK != CAIPGetInterfaceSubnetMask(info->ifAddr, &netMask))
250                 {
251                     OIC_LOG(ERROR, IP_SERVER_TAG, "Failed to get IP subnet");
252                     continue;
253                 }
254
255                 if (!CAAdapterIsSameSubnet(info->ifAddr, srcIPAddress, netMask))
256                 {
257                     OIC_LOG(DEBUG, IP_SERVER_TAG,
258                             "Packet received from different subnet, Ignore!");
259                     OICFree(netMask);
260                     continue;
261                 }
262                 OICFree(netMask);
263
264                 if (info->isSecured)
265                 {
266 #ifdef __WITH_DTLS__
267                     CAResult_t ret = CAAdapterNetDtlsDecrypt(srcIPAddress, srcPort,
268                                                              (uint8_t *)recvBuffer, recvLen,
269                                                              DTLS_IP);
270                     OIC_LOG_V(DEBUG, IP_SERVER_TAG,
271                               "CAAdapterNetDtlsDecrypt returns [%d]", ret);
272 #endif
273                 }
274                 else //both multicast and unicast
275                 {
276                     ca_mutex_lock(g_mutexAdapterServerContext);
277
278                     if (g_adapterEthServerContext->packetReceivedCallback)
279                     {
280                         g_adapterEthServerContext->packetReceivedCallback(srcIPAddress, srcPort,
281                                                                           recvBuffer, recvLen,
282                                                                           false);
283                     }
284
285                     ca_mutex_unlock(g_mutexAdapterServerContext);
286                 }
287             }
288         }
289         CAClearServerInfoList(tempServerInfoList);
290     }
291     OIC_LOG(DEBUG, IP_SERVER_TAG, "OUT");
292 }
293
294 static CAResult_t CACreateSocket(int *socketFD, const char *localIp, uint16_t *port,
295                                  bool forceBindStart)
296 {
297     VERIFY_NON_NULL(socketFD, IP_SERVER_TAG, "socketFD is NULL");
298     VERIFY_NON_NULL(localIp, IP_SERVER_TAG, "localIp is NULL");
299     VERIFY_NON_NULL(port, IP_SERVER_TAG, "port is NULL");
300     // Create a UDP socket
301     int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
302     if (-1 == sock)
303     {
304         OIC_LOG_V(ERROR, IP_SERVER_TAG, "Failed to create Socket, Error code: %s",
305                   strerror(errno));
306         return CA_STATUS_FAILED;
307     }
308
309     // Make the socket non-blocking
310     if (-1 == fcntl(sock, F_SETFL, O_NONBLOCK))
311     {
312         OIC_LOG_V(ERROR, IP_SERVER_TAG, "Failed to set non-block mode, Error code: %s",
313                   strerror(errno));
314
315         close(sock);
316         return CA_STATUS_FAILED;
317     }
318
319     if (true == forceBindStart)
320     {
321         int setOptionOn = SOCKETOPTION;
322         if (-1 == setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &setOptionOn,
323                              sizeof(setOptionOn)))
324         {
325             OIC_LOG_V(ERROR, IP_SERVER_TAG, "Failed to set SO_REUSEADDR! Error code: %s",
326                       strerror(errno));
327             close(sock);
328             return CA_STATUS_FAILED;
329         }
330     }
331
332     struct sockaddr_in sockAddr = { 0 };
333     uint16_t serverPort = *port;
334     sockAddr.sin_family = AF_INET;
335     sockAddr.sin_port = htons(serverPort);
336     if (localIp)
337     {
338         sockAddr.sin_addr.s_addr = inet_addr(localIp);
339     }
340     else
341     {
342         sockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
343     }
344
345     int16_t i = 0;
346     bool isBound = false;
347     for (i = 0; i < CA_UDP_BIND_RETRY_COUNT; i++)
348     {
349         if (-1 == bind(sock, (struct sockaddr *) &sockAddr, sizeof(sockAddr)))
350         {
351             if (false == forceBindStart)
352             {
353                 OIC_LOG_V(ERROR, IP_SERVER_TAG, "Failed to bind socket[%s]. Trying again..",
354                           strerror(errno));
355
356                 //Set the port to next one
357                 serverPort += 1;
358                 sockAddr.sin_port = htons(serverPort);
359                 continue;
360             }
361             else
362             {
363                 OIC_LOG_V(ERROR, IP_SERVER_TAG, "Failed to bind socket[%s]!",
364                           strerror(errno));
365                 break;
366             }
367         }
368
369         isBound = true;
370         break;
371     }
372
373     if (false == isBound)
374     {
375         close(sock);
376         return CA_STATUS_FAILED;
377     }
378
379     *port = serverPort;
380     *socketFD = sock;
381     return CA_STATUS_OK;
382 }
383
384 static void CACloseSocket(int socketFD)
385 {
386     if (-1 == socketFD)
387     {
388         OIC_LOG(ERROR, IP_SERVER_TAG, "Invalid Socket Fd");
389         return;
390     }
391
392     // close the socket
393     if (-1 == close(socketFD))
394     {
395         OIC_LOG_V(ERROR, IP_SERVER_TAG, "Failed to close the socket, Error code: %s\n",
396                   strerror(errno));
397     }
398 }
399
400 static CAResult_t CAStartUnicastServer(const char *localAddress, uint16_t *port,
401                                        bool forceBindStart, bool isSecured, int *serverFD)
402 {
403     OIC_LOG(DEBUG, IP_SERVER_TAG, "IN");
404
405     VERIFY_NON_NULL(serverFD, IP_SERVER_TAG, "serverFD");
406     VERIFY_NON_NULL(localAddress, IP_SERVER_TAG, "localAddress");
407     VERIFY_NON_NULL(port, IP_SERVER_TAG, "port");
408
409     CAResult_t ret = CACreateSocket(serverFD, localAddress, port, forceBindStart);
410     if (CA_STATUS_OK != ret)
411     {
412         OIC_LOG(ERROR, IP_SERVER_TAG, "Failed to create unicast socket");
413     }
414
415     OIC_LOG(DEBUG, IP_SERVER_TAG, "OUT");
416     return ret;
417 }
418
419 static CAResult_t CAIPStartPacketReceiverHandler()
420 {
421     OIC_LOG(DEBUG, IP_SERVER_TAG, "IN");
422
423     ca_mutex_lock(g_mutexServerInfoList);
424
425     uint32_t listLength = u_arraylist_length(g_serverInfoList);
426
427     ca_mutex_unlock(g_mutexServerInfoList);
428
429     ca_mutex_lock(g_mutexAdapterServerContext);
430
431     if (!g_adapterEthServerContext)
432     {
433         OIC_LOG(ERROR, IP_SERVER_TAG, "g_adapterEthServerContext NULL");
434         ca_mutex_unlock(g_mutexAdapterServerContext);
435         return CA_STATUS_FAILED;
436     }
437
438     if (1 == listLength) //Its first time.
439     {
440         if (CA_STATUS_OK != ca_thread_pool_add_task(g_adapterEthServerContext->threadPool,
441                                                    CAReceiveHandler, NULL ))
442         {
443             OIC_LOG(ERROR, IP_SERVER_TAG, "thread_pool_add_task failed!");
444             ca_mutex_unlock(g_mutexAdapterServerContext);
445             return CA_STATUS_FAILED;
446         }
447         OIC_LOG(DEBUG, IP_SERVER_TAG, "CAReceiveHandler thread started successfully.");
448     }
449     else
450     {
451         OIC_LOG(DEBUG, IP_SERVER_TAG, "CAReceiveHandler thread already is running");
452     }
453     ca_mutex_unlock(g_mutexAdapterServerContext);
454
455     OIC_LOG(DEBUG, IP_SERVER_TAG, "OUT");
456
457     return CA_STATUS_OK;
458 }
459
460 static void CAIPServerDestroyMutex(void)
461 {
462     OIC_LOG(DEBUG, IP_SERVER_TAG, "IN");
463
464     if (g_mutexServerInfoList)
465     {
466         ca_mutex_free(g_mutexServerInfoList);
467         g_mutexServerInfoList = NULL;
468     }
469
470     if (g_mutexAdapterServerContext)
471     {
472         ca_mutex_free(g_mutexAdapterServerContext);
473         g_mutexAdapterServerContext = NULL;
474     }
475
476     OIC_LOG(DEBUG, IP_SERVER_TAG, "OUT");
477 }
478
479 static CAResult_t CAIPServerCreateMutex(void)
480 {
481     OIC_LOG(DEBUG, IP_SERVER_TAG, "IN");
482
483     g_mutexServerInfoList = ca_mutex_new();
484     if (!g_mutexServerInfoList)
485     {
486         OIC_LOG(DEBUG, IP_SERVER_TAG, "OUT");
487         return CA_MEMORY_ALLOC_FAILED;
488     }
489
490     g_mutexAdapterServerContext = ca_mutex_new();
491     if (!g_mutexAdapterServerContext)
492     {
493         OIC_LOG(ERROR, IP_SERVER_TAG, "Failed to created mutex!");
494         ca_mutex_free(g_mutexServerInfoList);
495         g_mutexServerInfoList = NULL;
496         return CA_MEMORY_ALLOC_FAILED;
497     }
498
499     OIC_LOG(DEBUG, IP_SERVER_TAG, "OUT");
500     return CA_STATUS_OK;
501 }
502
503 CAResult_t CAIPInitializeServer(const ca_thread_pool_t threadPool)
504 {
505     OIC_LOG(DEBUG, IP_SERVER_TAG, "IN");
506
507     // Input validation
508     VERIFY_NON_NULL(threadPool, IP_SERVER_TAG, "Thread pool handle is NULL");
509
510     // Initialize mutex
511     if (CA_STATUS_OK != CAIPServerCreateMutex())
512     {
513         OIC_LOG(ERROR, IP_SERVER_TAG, "Failed to create mutex!");
514         return CA_STATUS_FAILED;
515     }
516
517     ca_mutex_lock(g_mutexAdapterServerContext);
518     g_adapterEthServerContext = (CAAdapterIPServerContext_t *) OICCalloc(1,
519                                  sizeof(CAAdapterIPServerContext_t));
520
521     if (!g_adapterEthServerContext)
522     {
523         OIC_LOG(ERROR, IP_SERVER_TAG, "Malloc failed");
524         ca_mutex_unlock(g_mutexAdapterServerContext);
525         return CA_MEMORY_ALLOC_FAILED;
526     }
527
528     g_adapterEthServerContext->threadPool = threadPool;
529
530     ca_mutex_unlock(g_mutexAdapterServerContext);
531
532     ca_mutex_lock(g_mutexServerInfoList);
533
534     g_serverInfoList = u_arraylist_create();
535     if (!g_serverInfoList)
536     {
537         OIC_LOG(ERROR, IP_SERVER_TAG, "u_arraylist_create failed");
538         ca_mutex_unlock(g_mutexServerInfoList);
539         return CA_MEMORY_ALLOC_FAILED;
540     }
541     ca_mutex_unlock(g_mutexServerInfoList);
542     OIC_LOG(DEBUG, IP_SERVER_TAG, "OUT");
543     return CA_STATUS_OK;
544 }
545
546 void CAIPTerminateServer()
547 {
548     OIC_LOG(DEBUG, IP_SERVER_TAG, "IN");
549     ca_mutex_lock(g_mutexAdapterServerContext);
550     if (!g_adapterEthServerContext)
551     {
552         OIC_LOG(ERROR, IP_SERVER_TAG, "g_adapterEthServerContext NULL");
553         ca_mutex_unlock(g_mutexAdapterServerContext);
554         return;
555     }
556
557     OICFree(g_adapterEthServerContext);
558     g_adapterEthServerContext = NULL;
559
560     ca_mutex_unlock(g_mutexAdapterServerContext);
561
562     ca_mutex_lock(g_mutexServerInfoList);
563
564     CAClearServerInfoList(g_serverInfoList);
565     g_serverInfoList = NULL;
566
567     ca_mutex_unlock(g_mutexServerInfoList);
568     // Destroy mutex
569     CAIPServerDestroyMutex();
570
571     OIC_LOG(DEBUG, IP_SERVER_TAG, "OUT");
572
573 }
574
575 CAResult_t CAIPStartUnicastServer(const char *localAddress, uint16_t *port,
576                                         bool forceBindStart, bool isSecured)
577 {
578     OIC_LOG(DEBUG, IP_SERVER_TAG, "IN");
579
580     // Input validation
581     VERIFY_NON_NULL(localAddress, IP_SERVER_TAG, "localAddress");
582     VERIFY_NON_NULL(port, IP_SERVER_TAG, "port");
583
584     if (0 >= *port)
585     {
586         OIC_LOG(ERROR, IP_SERVER_TAG, "Invalid input: port is invalid!");
587         return CA_STATUS_INVALID_PARAM;
588     }
589
590     ca_mutex_lock(g_mutexServerInfoList);
591     bool isUnicastServerStarted = CAIsUnicastServerStarted(g_serverInfoList, localAddress, *port);
592     if (!isUnicastServerStarted)
593     {
594         int unicastServerFd = -1;
595         if (CA_STATUS_OK != CAStartUnicastServer(localAddress, port, forceBindStart, isSecured,
596                                                  &unicastServerFd))
597         {
598             OIC_LOG(ERROR, IP_SERVER_TAG, "Failed to start unicast server!");
599             ca_mutex_unlock(g_mutexServerInfoList);
600             return CA_STATUS_FAILED;
601         }
602
603         CAServerInfo_t *info = (CAServerInfo_t *) OICCalloc(1, sizeof(CAServerInfo_t));
604         if (!info)
605         {
606             OIC_LOG(ERROR, IP_SERVER_TAG, "Malloc failed");
607             close(unicastServerFd);
608             ca_mutex_unlock(g_mutexServerInfoList);
609             return CA_MEMORY_ALLOC_FAILED;
610         }
611
612         char *netMask = NULL;
613         if (CA_STATUS_OK != CAIPGetInterfaceSubnetMask(localAddress, &netMask))
614         {
615             OIC_LOG(ERROR, IP_SERVER_TAG, "Failed to get IP subnet");
616         }
617         if (netMask)
618         {
619             strncpy(info->subNetMask, netMask, strlen(netMask));
620             OICFree(netMask);
621         }
622         strncpy(info->ipAddress, localAddress, strlen(localAddress));
623         info->port = *port;
624         info->socketFd = unicastServerFd;
625         info->isSecured = isSecured;
626         info->isServerStarted = true;
627         info->isMulticastServer = false;
628         strncpy(info->ifAddr, localAddress, strlen(localAddress));
629
630         CAResult_t res = CAAddServerInfo(g_serverInfoList, info);
631         if (CA_STATUS_OK != res)
632         {
633             OIC_LOG(ERROR, IP_SERVER_TAG, "CAAddServerInfo failed!");
634             close(unicastServerFd);
635             ca_mutex_unlock(g_mutexServerInfoList);
636             return res;
637         }
638         ca_mutex_unlock(g_mutexServerInfoList);
639
640         res = CAIPStartPacketReceiverHandler();
641         if (CA_STATUS_OK != res)
642         {
643             OIC_LOG(ERROR, IP_SERVER_TAG, "CAIPStartPacketReceiverHandler failed!");
644             close(unicastServerFd);
645             return res;
646         }
647     }
648     else
649     {
650         OIC_LOG_V(DEBUG, IP_SERVER_TAG, "Already Unicast Server Started ip [%s] port [%d]",
651                   localAddress, *port);
652         ca_mutex_unlock(g_mutexServerInfoList);
653     }
654
655     OIC_LOG(DEBUG, IP_SERVER_TAG, "OUT");
656     return CA_STATUS_OK;
657 }
658
659 CAResult_t CAIPStartMulticastServer(const char *localAddress, const char *multicastAddress,
660                                           uint16_t multicastPort)
661 {
662     OIC_LOG(DEBUG, IP_SERVER_TAG, "IN");
663
664     // Input validation
665     VERIFY_NON_NULL(localAddress, IP_SERVER_TAG, "localAddress");
666     VERIFY_NON_NULL(multicastAddress, IP_SERVER_TAG, "port");
667
668     uint16_t port = multicastPort;
669     if (0 >= port)
670     {
671         OIC_LOG(ERROR, IP_SERVER_TAG, "Invalid input: Multicast port is invalid!");
672         return CA_STATUS_INVALID_PARAM;
673     }
674
675     ca_mutex_lock(g_mutexServerInfoList);
676     bool isMulticastServerStarted = CAIsMulticastServerStarted(g_serverInfoList, localAddress,
677                                                                multicastAddress, port);
678     if (!isMulticastServerStarted)
679     {
680         int mulicastServerFd = -1;
681         CAResult_t ret = CACreateSocket(&mulicastServerFd, multicastAddress, &port, true);
682         if (ret != CA_STATUS_OK)
683         {
684             OIC_LOG(ERROR, IP_SERVER_TAG, "Failed to create multicast socket");
685             ca_mutex_unlock(g_mutexServerInfoList);
686             return ret;
687         }
688
689         struct ip_mreq multicastMemberReq = {.imr_interface.s_addr = inet_addr(localAddress)};
690         inet_aton(multicastAddress, &multicastMemberReq.imr_multiaddr);
691
692         if (-1 == setsockopt(mulicastServerFd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
693                              (char *) &multicastMemberReq, sizeof(struct ip_mreq)))
694         {
695             OIC_LOG_V(ERROR, IP_SERVER_TAG,
696                       "Failed to add to multicast group, Error code: %s\n", strerror(errno));
697             close(mulicastServerFd);
698             ca_mutex_unlock(g_mutexServerInfoList);
699             return CA_STATUS_FAILED;
700         }
701
702         CAServerInfo_t *info = (CAServerInfo_t *) OICCalloc(1, sizeof(CAServerInfo_t));
703         if (!info)
704         {
705             OIC_LOG(ERROR, IP_SERVER_TAG, "Malloc failed");
706             close(mulicastServerFd);
707             ca_mutex_unlock(g_mutexServerInfoList);
708             return CA_MEMORY_ALLOC_FAILED;
709         }
710
711         char *netMask = NULL;
712         if (CA_STATUS_OK != CAIPGetInterfaceSubnetMask(localAddress, &netMask))
713         {
714             OIC_LOG(ERROR, IP_SERVER_TAG, "Failed to get IP subnet");
715         }
716         if (netMask)
717         {
718             strncpy(info->subNetMask, netMask, strlen(netMask));
719             OICFree(netMask);
720         }
721
722         strncpy(info->ipAddress, multicastAddress, strlen(multicastAddress));
723         info->port = multicastPort;
724         info->socketFd = mulicastServerFd;
725         info->isSecured = false;
726         info->isServerStarted = true;
727         info->isMulticastServer = true;
728         strncpy(info->ifAddr, localAddress, strlen(localAddress));
729
730         ret = CAAddServerInfo(g_serverInfoList, info);
731
732         if (CA_STATUS_OK != ret)
733         {
734             OIC_LOG(ERROR, IP_SERVER_TAG, "CAAddServerInfo failed!");
735             close(mulicastServerFd);
736             ca_mutex_unlock(g_mutexServerInfoList);
737             return ret;
738         }
739         ca_mutex_unlock(g_mutexServerInfoList);
740
741         ret = CAIPStartPacketReceiverHandler();
742         if (CA_STATUS_OK != ret)
743         {
744             OIC_LOG(ERROR, IP_SERVER_TAG, "CAIPStartPacketReceiverHandler failed!");
745             close(mulicastServerFd);
746             return ret;
747         }
748     }
749     else
750     {
751         OIC_LOG_V(DEBUG, IP_SERVER_TAG,
752                   "Multicast Server is already started on interface addr[%s]", localAddress);
753         ca_mutex_unlock(g_mutexServerInfoList);
754     }
755
756     OIC_LOG(DEBUG, IP_SERVER_TAG, "OUT");
757     return CA_STATUS_OK;
758 }
759
760 CAResult_t CAIPStopServer(const char *interfaceAddress)
761 {
762     OIC_LOG(DEBUG, IP_SERVER_TAG, "IN");
763
764     VERIFY_NON_NULL(interfaceAddress, IP_SERVER_TAG, "interfaceAddress is NULL");
765
766     ca_mutex_lock(g_mutexServerInfoList);
767     uint32_t listIndex = 0;
768     uint32_t listLength = u_arraylist_length(g_serverInfoList);
769
770     for (listIndex = 0; listIndex < listLength;)
771     {
772         CAServerInfo_t *info = (CAServerInfo_t *) u_arraylist_get(g_serverInfoList, listIndex);
773         if (!info)
774         {
775             listIndex++;
776             continue;
777         }
778
779         if (info->isMulticastServer && strncmp(interfaceAddress, info->ifAddr, strlen(info->ifAddr))
780                 == 0)
781         {
782             if (u_arraylist_remove(g_serverInfoList, listIndex))
783             {
784                 struct ip_mreq multicastMemberReq = { { 0 }, { 0 } };
785
786                 multicastMemberReq.imr_interface.s_addr = inet_addr(info->ifAddr);
787                 inet_aton(info->ipAddress, &multicastMemberReq.imr_multiaddr);
788                 if (-1 == setsockopt(info->socketFd, IPPROTO_IP, IP_DROP_MEMBERSHIP,
789                                      (char *) &multicastMemberReq, sizeof(struct ip_mreq)))
790                 {
791                     OIC_LOG_V(ERROR, IP_SERVER_TAG,
792                               "Failed to leave multicast group, Error code: %s", strerror(errno));
793                 }
794                 CACloseSocket(info->socketFd);
795                 OICFree(info);
796                 OIC_LOG_V(DEBUG, IP_SERVER_TAG,
797                           "Multicast server is stopped successfully on IF [%s]", info->ifAddr);
798                 // Reduce list length by 1 as we removed one element.
799                 listLength--;
800             }
801             else
802             {
803                 OIC_LOG(ERROR, IP_SERVER_TAG, "u_arraylist_remove failed.");
804                 ca_mutex_unlock(g_mutexServerInfoList);
805                 return CA_STATUS_FAILED;
806             }
807         }
808         else if (strncmp(interfaceAddress, info->ipAddress, strlen(info->ipAddress)) == 0)
809         {
810             if (u_arraylist_remove(g_serverInfoList, listIndex))
811             {
812                 CACloseSocket(info->socketFd);
813                 OICFree(info);
814                 OIC_LOG_V(DEBUG, IP_SERVER_TAG,
815                           "Unicast server is stopped successfully on IF [%s]", info->ifAddr);
816                 // Reduce list length by 1 as we removed one element.
817                 listLength--;
818             }
819             else
820             {
821                 OIC_LOG(ERROR, IP_SERVER_TAG, "u_arraylist_remove failed.");
822                 ca_mutex_unlock(g_mutexServerInfoList);
823                 return CA_STATUS_FAILED;
824             }
825         }
826         else
827         {
828             listIndex++;
829         }
830     }
831
832     OIC_LOG(DEBUG, IP_SERVER_TAG, "OUT");
833     ca_mutex_unlock(g_mutexServerInfoList);
834     return CA_STATUS_OK;
835 }
836
837 CAResult_t CAIPStopAllServers()
838 {
839     OIC_LOG(DEBUG, IP_SERVER_TAG, "IN");
840
841     g_packetHandlerStopFlag = true;
842
843     ca_mutex_lock(g_mutexServerInfoList);
844
845     uint32_t listIndex = 0;
846     uint32_t listLength = u_arraylist_length(g_serverInfoList);
847     for (listIndex = 0; listIndex < listLength;)
848     {
849         CAServerInfo_t *info = (CAServerInfo_t *) u_arraylist_get(g_serverInfoList, listIndex);
850         if (!info)
851         {
852             listIndex++;
853             continue;
854         }
855         if (u_arraylist_remove(g_serverInfoList, listIndex))
856         {
857             if (info->isMulticastServer)
858             {
859                 struct ip_mreq multicastMemberReq = { { 0 }, { 0 } };
860
861                 multicastMemberReq.imr_interface.s_addr = inet_addr(info->ifAddr);
862                 inet_aton(info->ipAddress, &multicastMemberReq.imr_multiaddr);
863                 if (-1 == setsockopt(info->socketFd, IPPROTO_IP, IP_DROP_MEMBERSHIP,
864                                      (char *) &multicastMemberReq, sizeof(struct ip_mreq)))
865                 {
866                     OIC_LOG_V(ERROR, IP_SERVER_TAG,
867                               "Failed to leave multicast group, Error code: %s", strerror(errno));
868                 }
869             }
870             CACloseSocket(info->socketFd);
871             //Freeing server info.
872             OICFree(info);
873             // Reduce list length by 1 as we removed one element.
874             listLength--;
875         }
876         else
877         {
878             OIC_LOG(ERROR, IP_SERVER_TAG, "u_arraylist_remove failed.");
879             ca_mutex_unlock(g_mutexServerInfoList);
880             return CA_STATUS_FAILED;
881         }
882     }
883
884     ca_mutex_unlock(g_mutexServerInfoList);
885
886     OIC_LOG(DEBUG, IP_SERVER_TAG, "All Server stopped successfully. OUT");
887     return CA_STATUS_OK;
888 }
889
890 uint16_t CAGetServerPortNum(const char *ipAddress, bool isSecured)
891 {
892     ca_mutex_lock(g_mutexServerInfoList);
893
894     uint16_t port = CAGetServerPort(g_serverInfoList, ipAddress, isSecured);
895
896     ca_mutex_unlock(g_mutexServerInfoList);
897
898     return port;
899 }
900
901 CAResult_t CAGetIPServerInfoList(u_arraylist_t **serverInfoList)
902 {
903     OIC_LOG(DEBUG, IP_SERVER_TAG, "IN");
904     ca_mutex_lock(g_mutexServerInfoList);
905
906     uint32_t list_index = 0;
907     uint32_t list_length = u_arraylist_length(g_serverInfoList);
908     for (list_index = 0; list_index < list_length; list_index++)
909     {
910         CAServerInfo_t *info = (CAServerInfo_t *) u_arraylist_get(g_serverInfoList, list_index);
911         if (!info)
912         {
913             continue;
914         }
915
916         CAServerInfo_t *newNetinfo = (CAServerInfo_t *) OICMalloc(sizeof(CAServerInfo_t));
917         if (!newNetinfo)
918         {
919             OIC_LOG(ERROR, IP_SERVER_TAG, "Malloc failed!");
920             ca_mutex_unlock(g_mutexServerInfoList);
921             return CA_MEMORY_ALLOC_FAILED;
922         }
923
924         memcpy(newNetinfo, info, sizeof(*info));
925
926         CAResult_t result = u_arraylist_add(*serverInfoList, (void *) newNetinfo);
927         if (CA_STATUS_OK != result)
928         {
929             OIC_LOG(ERROR, IP_SERVER_TAG, "u_arraylist_add failed!");
930             ca_mutex_unlock(g_mutexServerInfoList);
931             return CA_STATUS_FAILED;
932         }
933     }
934     ca_mutex_unlock(g_mutexServerInfoList);
935     OIC_LOG(DEBUG, IP_SERVER_TAG, "OUT");
936     return CA_STATUS_OK;
937 }
938
939 void CAIPSetPacketReceiveCallback(CAIPPacketReceivedCallback callback)
940 {
941     OIC_LOG(DEBUG, IP_SERVER_TAG, "IN");
942
943     ca_mutex_lock(g_mutexAdapterServerContext);
944
945     if (!g_adapterEthServerContext)
946     {
947         OIC_LOG(ERROR, IP_SERVER_TAG, "g_adapterEthServerContext NULL");
948         ca_mutex_unlock(g_mutexAdapterServerContext);
949         return;
950     }
951     g_adapterEthServerContext->packetReceivedCallback = callback;
952
953     ca_mutex_unlock(g_mutexAdapterServerContext);
954
955     OIC_LOG(DEBUG, IP_SERVER_TAG, "OUT");
956 }
957
958 void CAIPSetExceptionCallback(CAIPExceptionCallback callback)
959 {
960     OIC_LOG(DEBUG, IP_SERVER_TAG, "IN");
961     ca_mutex_lock(g_mutexAdapterServerContext);
962
963     if (!g_adapterEthServerContext)
964     {
965         OIC_LOG(ERROR, IP_SERVER_TAG, "g_adapterEthServerContext NULL");
966         ca_mutex_unlock(g_mutexAdapterServerContext);
967         return;
968     }
969     g_adapterEthServerContext->exceptionCallback = callback;
970
971     ca_mutex_unlock(g_mutexAdapterServerContext);
972
973     OIC_LOG(DEBUG, IP_SERVER_TAG, "OUT");
974 }
975