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