Merge branch 'master' into resource-manipulation
[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     if (0 > *port)
586     {
587         OIC_LOG(ERROR, IP_SERVER_TAG, "Invalid input: port is invalid!");
588         return CA_STATUS_INVALID_PARAM;
589     }
590
591     ca_mutex_lock(g_mutexServerInfoList);
592     bool isUnicastServerStarted = CAIsUnicastServerStarted(g_serverInfoList, localAddress, *port);
593     if (!isUnicastServerStarted)
594     {
595         int unicastServerFd = -1;
596         if (CA_STATUS_OK != CAStartUnicastServer(localAddress, port, isSecured,
597                                                  &unicastServerFd))
598         {
599             OIC_LOG(ERROR, IP_SERVER_TAG, "Failed to start unicast server!");
600             ca_mutex_unlock(g_mutexServerInfoList);
601             return CA_STATUS_FAILED;
602         }
603
604         CAServerInfo_t *info = (CAServerInfo_t *) OICCalloc(1, sizeof(CAServerInfo_t));
605         if (!info)
606         {
607             OIC_LOG(ERROR, IP_SERVER_TAG, "Malloc failed");
608             close(unicastServerFd);
609             ca_mutex_unlock(g_mutexServerInfoList);
610             return CA_MEMORY_ALLOC_FAILED;
611         }
612
613         char *netMask = NULL;
614         if (CA_STATUS_OK != CAIPGetInterfaceSubnetMask(localAddress, &netMask))
615         {
616             OIC_LOG(ERROR, IP_SERVER_TAG, "Failed to get IP subnet");
617         }
618         if (netMask)
619         {
620             OICStrcpy(info->subNetMask, sizeof(info->subNetMask), netMask);
621             OICFree(netMask);
622         }
623         OICStrcpy(info->endpoint.addr, sizeof(info->endpoint.addr), localAddress);
624         info->endpoint.port = *port;
625         info->endpoint.flags = isSecured ? CA_SECURE : 0;
626         info->endpoint.adapter = CA_ADAPTER_IP;
627         info->socketFd = unicastServerFd;
628         info->isServerStarted = true;
629         info->isMulticastServer = false;
630         OICStrcpy(info->ifAddr, sizeof(info->ifAddr), localAddress);
631
632         CAResult_t res = CAAddServerInfo(g_serverInfoList, info);
633         if (CA_STATUS_OK != res)
634         {
635             OIC_LOG(ERROR, IP_SERVER_TAG, "CAAddServerInfo failed!");
636             close(unicastServerFd);
637             ca_mutex_unlock(g_mutexServerInfoList);
638             return res;
639         }
640         ca_mutex_unlock(g_mutexServerInfoList);
641
642         res = CAIPStartPacketReceiverHandler();
643         if (CA_STATUS_OK != res)
644         {
645             OIC_LOG(ERROR, IP_SERVER_TAG, "CAIPStartPacketReceiverHandler failed!");
646             close(unicastServerFd);
647             return res;
648         }
649     }
650     else
651     {
652         OIC_LOG_V(DEBUG, IP_SERVER_TAG, "Already Unicast Server Started ip [%s] port [%d]",
653                   localAddress, *port);
654         ca_mutex_unlock(g_mutexServerInfoList);
655     }
656
657     OIC_LOG(DEBUG, IP_SERVER_TAG, "OUT");
658     return CA_STATUS_OK;
659 }
660
661 CAResult_t CAIPStartMulticastServer(const char *localAddress, const char *multicastAddress,
662                                           uint16_t multicastPort)
663 {
664     OIC_LOG(DEBUG, IP_SERVER_TAG, "IN");
665
666     // Input validation
667     VERIFY_NON_NULL(localAddress, IP_SERVER_TAG, "localAddress");
668     VERIFY_NON_NULL(multicastAddress, IP_SERVER_TAG, "port");
669
670     uint16_t port = multicastPort;
671     if (0 >= port)
672     {
673         OIC_LOG(ERROR, IP_SERVER_TAG, "Invalid input: Multicast port is invalid!");
674         return CA_STATUS_INVALID_PARAM;
675     }
676
677     ca_mutex_lock(g_mutexServerInfoList);
678     bool isMulticastServerStarted = CAIsMulticastServerStarted(g_serverInfoList, localAddress,
679                                                                multicastAddress, port);
680     if (!isMulticastServerStarted)
681     {
682         int mulicastServerFd = -1;
683         CAResult_t ret = CACreateSocket(&mulicastServerFd, multicastAddress, &port);
684         if (ret != CA_STATUS_OK)
685         {
686             OIC_LOG(ERROR, IP_SERVER_TAG, "Failed to create multicast socket");
687             ca_mutex_unlock(g_mutexServerInfoList);
688             return ret;
689         }
690
691         struct ip_mreq multicastMemberReq = {.imr_interface.s_addr = inet_addr(localAddress)};
692         inet_aton(multicastAddress, &multicastMemberReq.imr_multiaddr);
693
694         if (-1 == setsockopt(mulicastServerFd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
695                              (char *) &multicastMemberReq, sizeof(struct ip_mreq)))
696         {
697             OIC_LOG_V(ERROR, IP_SERVER_TAG,
698                       "Failed to add to multicast group, Error code: %s\n", strerror(errno));
699             close(mulicastServerFd);
700             ca_mutex_unlock(g_mutexServerInfoList);
701             return CA_STATUS_FAILED;
702         }
703
704         CAServerInfo_t *info = (CAServerInfo_t *) OICCalloc(1, sizeof(CAServerInfo_t));
705         if (!info)
706         {
707             OIC_LOG(ERROR, IP_SERVER_TAG, "Malloc failed");
708             close(mulicastServerFd);
709             ca_mutex_unlock(g_mutexServerInfoList);
710             return CA_MEMORY_ALLOC_FAILED;
711         }
712
713         char *netMask = NULL;
714         if (CA_STATUS_OK != CAIPGetInterfaceSubnetMask(localAddress, &netMask))
715         {
716             OIC_LOG(ERROR, IP_SERVER_TAG, "Failed to get IP subnet");
717         }
718         if (netMask)
719         {
720             OICStrcpy(info->subNetMask, sizeof(info->subNetMask), netMask);
721             OICFree(netMask);
722         }
723
724         OICStrcpy(info->endpoint.addr, sizeof(info->endpoint.addr), multicastAddress);
725         info->endpoint.port = multicastPort;
726         info->endpoint.flags = 0;
727         info->socketFd = mulicastServerFd;
728         info->isServerStarted = true;
729         info->isMulticastServer = true;
730         OICStrcpy(info->ifAddr, sizeof(info->ifAddr), localAddress);
731
732         ret = CAAddServerInfo(g_serverInfoList, info);
733
734         if (CA_STATUS_OK != ret)
735         {
736             OIC_LOG(ERROR, IP_SERVER_TAG, "CAAddServerInfo failed!");
737             close(mulicastServerFd);
738             ca_mutex_unlock(g_mutexServerInfoList);
739             return ret;
740         }
741         ca_mutex_unlock(g_mutexServerInfoList);
742
743         ret = CAIPStartPacketReceiverHandler();
744         if (CA_STATUS_OK != ret)
745         {
746             OIC_LOG(ERROR, IP_SERVER_TAG, "CAIPStartPacketReceiverHandler failed!");
747             close(mulicastServerFd);
748             return ret;
749         }
750     }
751     else
752     {
753         OIC_LOG_V(DEBUG, IP_SERVER_TAG,
754                   "Multicast Server is already started on interface addr[%s]", localAddress);
755         ca_mutex_unlock(g_mutexServerInfoList);
756     }
757
758     OIC_LOG(DEBUG, IP_SERVER_TAG, "OUT");
759     return CA_STATUS_OK;
760 }
761
762 CAResult_t CAIPStopServer(const char *interfaceAddress)
763 {
764     OIC_LOG(DEBUG, IP_SERVER_TAG, "IN");
765
766     VERIFY_NON_NULL(interfaceAddress, IP_SERVER_TAG, "interfaceAddress is NULL");
767
768     ca_mutex_lock(g_mutexServerInfoList);
769     uint32_t listIndex = 0;
770     uint32_t listLength = u_arraylist_length(g_serverInfoList);
771
772     for (listIndex = 0; listIndex < listLength;)
773     {
774         CAServerInfo_t *info = (CAServerInfo_t *) u_arraylist_get(g_serverInfoList, listIndex);
775         if (!info)
776         {
777             listIndex++;
778             continue;
779         }
780
781         if (info->isMulticastServer && strncmp(interfaceAddress, info->ifAddr, strlen(info->ifAddr))
782                 == 0)
783         {
784             if (u_arraylist_remove(g_serverInfoList, listIndex))
785             {
786                 struct ip_mreq multicastMemberReq = { { 0 }, { 0 } };
787
788                 multicastMemberReq.imr_interface.s_addr = inet_addr(info->ifAddr);
789                 inet_aton(info->endpoint.addr, &multicastMemberReq.imr_multiaddr);
790                 if (-1 == setsockopt(info->socketFd, IPPROTO_IP, IP_DROP_MEMBERSHIP,
791                                      (char *) &multicastMemberReq, sizeof(struct ip_mreq)))
792                 {
793                     OIC_LOG_V(ERROR, IP_SERVER_TAG,
794                               "Failed to leave multicast group, Error code: %s", strerror(errno));
795                 }
796                 CACloseSocket(info->socketFd);
797                 OICFree(info);
798                 OIC_LOG(DEBUG, IP_SERVER_TAG, "Multicast server is stopped successfully.");
799                 // Reduce list length by 1 as we removed one element.
800                 listLength--;
801             }
802             else
803             {
804                 OIC_LOG(ERROR, IP_SERVER_TAG, "u_arraylist_remove failed.");
805                 ca_mutex_unlock(g_mutexServerInfoList);
806                 return CA_STATUS_FAILED;
807             }
808         }
809         else if (strncmp(interfaceAddress, info->endpoint.addr, strlen(info->endpoint.addr)) == 0)
810         {
811             if (u_arraylist_remove(g_serverInfoList, listIndex))
812             {
813                 CACloseSocket(info->socketFd);
814                 OICFree(info);
815                 OIC_LOG(DEBUG, IP_SERVER_TAG, "Unicast server is stopped successfully.");
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->endpoint.addr, &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         *newNetinfo = *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