1 /******************************************************************
3 * Copyright 2014 Samsung Electronics All Rights Reserved.
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 ******************************************************************/
21 #include "caipinterface.h"
23 #include <sys/types.h>
26 #include <sys/socket.h>
32 #include "caadapterutils.h"
35 #include "oic_malloc.h"
36 #include "oic_string.h"
38 #define IP_MONITOR_TAG "IP_MONITOR"
41 * @var g_networkMonitorContextMutex
42 * @brief Mutex for synchronizing access to cached interface and IP address information.
44 static ca_mutex g_networkMonitorContextMutex = NULL;
47 * @var g_stopNetworkMonitor
48 * @brief Used to stop the network monitor thread.
50 static bool g_stopNetworkMonitor = false;
53 * @var g_stopNetworkMonitorMutex
54 * @brief Mutex for synchronizing access to g_stopNetworkMonitor flag.
56 static ca_mutex g_stopNetworkMonitorMutex = NULL;
59 * @struct CAIPNwMonitorContext
60 * @brief Used for storing network monitor context information.
64 u_arraylist_t *netInterfaceList;
65 ca_thread_pool_t threadPool;
66 CANetworkStatus_t nwConnectivityStatus;
67 CAIPConnectionStateChangeCallback networkChangeCb;
68 } CAIPNetworkMonitorContext;
71 * @var g_networkMonitorContext
72 * @brief network monitor context.
74 static CAIPNetworkMonitorContext *g_networkMonitorContext = NULL;
76 static void CAIPGetInterfaceInformation(u_arraylist_t **netInterfaceList)
79 VERIFY_NON_NULL_VOID(netInterfaceList, IP_MONITOR_TAG, "netInterfaceList is null");
81 struct ifaddrs *ifp = NULL;
82 if (-1 == getifaddrs(&ifp))
84 OIC_LOG_V(ERROR, IP_MONITOR_TAG, "Failed to get interface list!, Error code: %s",
89 struct ifaddrs *ifa = NULL;
90 for (ifa = ifp; ifa; ifa = ifa->ifa_next)
92 char interfaceAddress[CA_IPADDR_SIZE] = {0};
93 char interfaceSubnetMask[CA_IPADDR_SIZE] = {0};
94 socklen_t len = sizeof(struct sockaddr_in);
101 int type = ifa->ifa_addr->sa_family;
102 if (ifa->ifa_flags & IFF_LOOPBACK
103 || !((ifa->ifa_flags & IFF_UP) && (ifa->ifa_flags & IFF_RUNNING)))
113 // get the interface ip address
114 if (0 != getnameinfo(ifa->ifa_addr, len, interfaceAddress,
115 sizeof(interfaceAddress), NULL, 0, NI_NUMERICHOST))
117 OIC_LOG_V(ERROR, IP_MONITOR_TAG, "Failed to get IPAddress, Error code: %s",
122 // get the interface subnet mask
123 if (0 != getnameinfo(ifa->ifa_netmask, len, interfaceSubnetMask,
124 sizeof(interfaceSubnetMask), NULL, 0, NI_NUMERICHOST))
126 OIC_LOG_V(ERROR, IP_MONITOR_TAG, "Failed to get subnet mask, Error code: %s",
131 CANetInfo_t *netInfo = (CANetInfo_t *)OICCalloc(1, sizeof(CANetInfo_t));
134 OIC_LOG(ERROR, IP_MONITOR_TAG, "Malloc failed");
138 // set interface name
139 strncpy(netInfo->interfaceName, ifa->ifa_name, sizeof(netInfo->interfaceName) - 1);
140 netInfo->interfaceName[sizeof(netInfo->interfaceName)-1] = '\0';
142 // set local ip address
143 strncpy(netInfo->ipAddress, interfaceAddress, strlen(interfaceAddress));
146 strncpy(netInfo->subnetMask, interfaceSubnetMask, strlen(interfaceSubnetMask));
148 CAResult_t result = u_arraylist_add(*netInterfaceList, (void *)netInfo);
149 if (CA_STATUS_OK != result)
151 OIC_LOG(ERROR, IP_MONITOR_TAG, "u_arraylist_add failed!Thread exiting.");
160 static bool CACheckIsAnyInterfaceDown(const u_arraylist_t *netInterfaceList,
161 const CANetInfo_t *info)
163 VERIFY_NON_NULL_RET(netInterfaceList, IP_MONITOR_TAG, "netInterfaceList is null", false);
164 VERIFY_NON_NULL_RET(info, IP_MONITOR_TAG, "info is null", false);
166 uint32_t list_index = 0;
167 uint32_t list_length = u_arraylist_length(netInterfaceList);
168 for (list_index = 0; list_index < list_length; list_index++)
170 CANetInfo_t *netInfo = (CANetInfo_t *)u_arraylist_get(netInterfaceList,
176 if (strncmp(netInfo->interfaceName, info->interfaceName, strlen(info->interfaceName)) == 0)
181 OIC_LOG(DEBUG, IP_MONITOR_TAG, "Interface is down");
185 static bool CACheckIsInterfaceInfoChanged(const CANetInfo_t *info)
187 VERIFY_NON_NULL_RET(info, IP_MONITOR_TAG, "info is null", false);
189 ca_mutex_lock(g_networkMonitorContextMutex);
190 uint32_t list_index = 0;
191 uint32_t list_length = u_arraylist_length(g_networkMonitorContext->netInterfaceList);
192 for (list_index = 0; list_index < list_length; list_index++)
194 CANetInfo_t *netInfo = (CANetInfo_t *)u_arraylist_get(
195 g_networkMonitorContext->netInterfaceList, list_index);
200 if (strncmp(netInfo->interfaceName, info->interfaceName, strlen(info->interfaceName)) == 0)
202 if (strncmp(netInfo->ipAddress, info->ipAddress, strlen(info->ipAddress)) == 0)
204 ca_mutex_unlock(g_networkMonitorContextMutex);
209 OIC_LOG(DEBUG, IP_MONITOR_TAG, "Network interface info changed");
210 if (u_arraylist_remove(g_networkMonitorContext->netInterfaceList, list_index))
212 if (g_networkMonitorContext->networkChangeCb)
214 g_networkMonitorContext->networkChangeCb(netInfo->ipAddress,
221 OIC_LOG(ERROR, IP_MONITOR_TAG, "u_arraylist_remove failed");
228 CANetInfo_t *newNetInfo = (CANetInfo_t *)OICMalloc(sizeof(CANetInfo_t));
231 OIC_LOG(ERROR, IP_MONITOR_TAG, "newNetInfo malloc failed");
232 ca_mutex_unlock(g_networkMonitorContextMutex);
235 memcpy(newNetInfo, info, sizeof(*newNetInfo));
237 OIC_LOG(DEBUG, IP_MONITOR_TAG, "New Interface found");
239 CAResult_t result = u_arraylist_add(g_networkMonitorContext->netInterfaceList,
241 if (CA_STATUS_OK != result)
243 OIC_LOG(ERROR, IP_MONITOR_TAG, "u_arraylist_add failed!");
245 ca_mutex_unlock(g_networkMonitorContextMutex);
248 ca_mutex_unlock(g_networkMonitorContextMutex);
250 /*Callback will be unset only at the time of termination. By that time, all the threads will be
251 stopped gracefully. This callback is properly protected*/
252 if (g_networkMonitorContext->networkChangeCb)
254 g_networkMonitorContext->networkChangeCb(newNetInfo->ipAddress, CA_INTERFACE_UP);
260 static void CANetworkMonitorThread(void *threadData)
262 OIC_LOG(DEBUG, IP_MONITOR_TAG, "IN");
264 while (!g_stopNetworkMonitor)
266 u_arraylist_t *netInterfaceList = u_arraylist_create();
268 VERIFY_NON_NULL_VOID(netInterfaceList, IP_MONITOR_TAG, "netInterfaceList is null");
270 CAIPGetInterfaceInformation(&netInterfaceList);
272 ca_mutex_lock(g_networkMonitorContextMutex);
273 if (!g_networkMonitorContext->netInterfaceList)
275 OIC_LOG(ERROR, IP_MONITOR_TAG,
276 "u_arraylist_create failed. Network Monitor thread stopped");
277 CAClearNetInterfaceInfoList(netInterfaceList);
278 ca_mutex_unlock(g_networkMonitorContextMutex);
282 uint32_t listIndex = 0;
283 uint32_t listLength = u_arraylist_length(g_networkMonitorContext->netInterfaceList);
284 for (listIndex = 0; listIndex < listLength;)
286 CANetInfo_t *info = (CANetInfo_t *)u_arraylist_get(
287 g_networkMonitorContext->netInterfaceList, listIndex);
294 bool ret = CACheckIsAnyInterfaceDown(netInterfaceList, info);
297 OIC_LOG(DEBUG, IP_MONITOR_TAG, "Interface is down");
298 if (u_arraylist_remove(g_networkMonitorContext->netInterfaceList, listIndex))
300 OIC_LOG(DEBUG, IP_MONITOR_TAG, "u_arraylist_remove success");
301 if (g_networkMonitorContext->networkChangeCb)
303 g_networkMonitorContext->networkChangeCb(info->ipAddress,
311 OIC_LOG(ERROR, IP_MONITOR_TAG, "u_arraylist_remove failed");
320 ca_mutex_unlock(g_networkMonitorContextMutex);
322 listLength = u_arraylist_length(netInterfaceList);
323 for (listIndex = 0; listIndex < listLength; listIndex++)
325 CANetInfo_t *info = (CANetInfo_t *)u_arraylist_get(netInterfaceList, listIndex);
330 bool ret = CACheckIsInterfaceInfoChanged(info);
333 OIC_LOG(DEBUG, IP_MONITOR_TAG, "CACheckIsInterfaceInfoChanged true");
336 CAClearNetInterfaceInfoList(netInterfaceList);
337 sleep(2); // To avoid maximum cpu usage.
340 OIC_LOG(DEBUG, IP_MONITOR_TAG, "OUT");
343 static CAResult_t CAInitializeNetworkMonitorMutexes()
345 if (!g_networkMonitorContextMutex)
347 g_networkMonitorContextMutex = ca_mutex_new();
348 if (!g_networkMonitorContextMutex)
350 OIC_LOG(ERROR, IP_MONITOR_TAG, "g_networkMonitorContextMutex Malloc failed");
351 return CA_MEMORY_ALLOC_FAILED;
355 if (!g_stopNetworkMonitorMutex)
357 g_stopNetworkMonitorMutex = ca_mutex_new();
358 if (!g_stopNetworkMonitorMutex)
360 OIC_LOG(ERROR, IP_MONITOR_TAG, "g_stopNetworkMonitorMutex Malloc failed");
361 ca_mutex_free(g_networkMonitorContextMutex);
362 return CA_MEMORY_ALLOC_FAILED;
367 static void CADestroyNetworkMonitorMutexes()
369 ca_mutex_free(g_networkMonitorContextMutex);
370 g_networkMonitorContextMutex = NULL;
372 ca_mutex_free(g_stopNetworkMonitorMutex);
373 g_stopNetworkMonitorMutex = NULL;
376 CAResult_t CAIPInitializeNetworkMonitor(const ca_thread_pool_t threadPool)
378 OIC_LOG(DEBUG, IP_MONITOR_TAG, "IN");
380 VERIFY_NON_NULL(threadPool, IP_MONITOR_TAG, "threadPool is null");
382 CAResult_t ret = CAInitializeNetworkMonitorMutexes();
384 if (CA_STATUS_OK != ret)
386 OIC_LOG(ERROR, IP_MONITOR_TAG, "CAInitializeNetworkMonitorMutexes failed");
387 return CA_STATUS_FAILED;
390 ca_mutex_lock(g_networkMonitorContextMutex);
392 g_networkMonitorContext = (CAIPNetworkMonitorContext *)OICCalloc(1,
393 sizeof(*g_networkMonitorContext));
394 if (!g_networkMonitorContext)
396 OIC_LOG(ERROR, IP_MONITOR_TAG, "g_networkMonitorContext Malloc failed");
397 ca_mutex_unlock(g_networkMonitorContextMutex);
398 CADestroyNetworkMonitorMutexes();
399 return CA_MEMORY_ALLOC_FAILED;
401 g_networkMonitorContext->threadPool = threadPool;
403 g_networkMonitorContext->netInterfaceList = u_arraylist_create();
404 if (!g_networkMonitorContext->netInterfaceList)
406 OIC_LOG(ERROR, IP_MONITOR_TAG, "u_arraylist_create failed");
407 OICFree(g_networkMonitorContext);
408 ca_mutex_unlock(g_networkMonitorContextMutex);
409 CADestroyNetworkMonitorMutexes();
410 return CA_MEMORY_ALLOC_FAILED;
413 CAIPGetInterfaceInformation(&g_networkMonitorContext->netInterfaceList);
416 if (u_arraylist_length(g_networkMonitorContext->netInterfaceList))
418 g_networkMonitorContext->nwConnectivityStatus = CA_INTERFACE_UP;
422 g_networkMonitorContext->nwConnectivityStatus = CA_INTERFACE_DOWN;
425 ca_mutex_unlock(g_networkMonitorContextMutex);
427 OIC_LOG(DEBUG, IP_MONITOR_TAG, "OUT");
431 void CAIPTerminateNetworkMonitor()
433 OIC_LOG(DEBUG, IP_MONITOR_TAG, "IN");
435 ca_mutex_lock(g_networkMonitorContextMutex);
436 g_networkMonitorContext->threadPool = NULL;
438 CAClearNetInterfaceInfoList(g_networkMonitorContext->netInterfaceList);
440 g_networkMonitorContext->netInterfaceList = NULL;
441 g_networkMonitorContext->nwConnectivityStatus = CA_INTERFACE_DOWN;
442 g_networkMonitorContext->networkChangeCb = NULL;
443 g_networkMonitorContext->threadPool = NULL;
445 OICFree(g_networkMonitorContext);
446 g_networkMonitorContext = NULL;
448 ca_mutex_unlock(g_networkMonitorContextMutex);
450 ca_mutex_lock(g_stopNetworkMonitorMutex);
451 g_stopNetworkMonitor = true;
452 ca_mutex_unlock(g_stopNetworkMonitorMutex);
454 CADestroyNetworkMonitorMutexes();
456 OIC_LOG(DEBUG, IP_MONITOR_TAG, "OUT");
459 CAResult_t CAIPStartNetworkMonitor()
461 OIC_LOG(DEBUG, IP_MONITOR_TAG, "IN");
463 ca_mutex_lock(g_stopNetworkMonitorMutex);
465 g_stopNetworkMonitor = false;
467 ca_mutex_unlock(g_stopNetworkMonitorMutex);
469 ca_mutex_lock(g_networkMonitorContextMutex);
471 if (!g_networkMonitorContext)
473 OIC_LOG(ERROR, IP_MONITOR_TAG, "g_networkMonitorContext is null");
474 ca_mutex_unlock(g_networkMonitorContextMutex);
475 return CA_STATUS_FAILED;
478 if (CA_STATUS_OK != ca_thread_pool_add_task(g_networkMonitorContext->threadPool,
479 CANetworkMonitorThread, NULL))
481 OIC_LOG(ERROR, IP_MONITOR_TAG, "[ThreadPool] thread_pool_add_task failed!");
482 ca_mutex_unlock(g_networkMonitorContextMutex);
483 return CA_STATUS_FAILED;
485 ca_mutex_unlock(g_networkMonitorContextMutex);
487 OIC_LOG(DEBUG, IP_MONITOR_TAG, "OUT");
491 CAResult_t CAIPStopNetworkMonitor()
493 OIC_LOG(DEBUG, IP_MONITOR_TAG, "IN");
495 ca_mutex_lock(g_networkMonitorContextMutex);
496 if (!g_networkMonitorContext)
498 OIC_LOG(ERROR, IP_MONITOR_TAG, "g_networkMonitorContext is null");
499 ca_mutex_unlock(g_networkMonitorContextMutex);
500 return CA_STATUS_FAILED;
503 ca_mutex_unlock(g_networkMonitorContextMutex);
505 ca_mutex_lock(g_stopNetworkMonitorMutex);
506 if (!g_stopNetworkMonitor)
508 g_stopNetworkMonitor = true;
512 OIC_LOG(DEBUG, IP_MONITOR_TAG, "CAIPStopNetworkMonitor, already stopped!");
514 ca_mutex_unlock(g_stopNetworkMonitorMutex);
516 OIC_LOG(DEBUG, IP_MONITOR_TAG, "OUT");
520 CAResult_t CAIPGetInterfaceInfo(u_arraylist_t **netInterfaceList)
522 OIC_LOG(DEBUG, IP_MONITOR_TAG, "IN");
524 VERIFY_NON_NULL(netInterfaceList, IP_MONITOR_TAG, "u_array_list is null");
525 VERIFY_NON_NULL(g_networkMonitorContext, IP_MONITOR_TAG,
526 "g_networkMonitorContext is null");
527 VERIFY_NON_NULL(g_networkMonitorContextMutex, IP_MONITOR_TAG,
528 "g_networkMonitorContextMutex is null");
530 // Get the interface and ipaddress information from cache
531 ca_mutex_lock(g_networkMonitorContextMutex);
532 if (!g_networkMonitorContext->netInterfaceList
533 || !(u_arraylist_length(g_networkMonitorContext->netInterfaceList)))
535 OIC_LOG(ERROR, IP_MONITOR_TAG, "Network not enabled");
536 ca_mutex_unlock(g_networkMonitorContextMutex);
537 return CA_ADAPTER_NOT_ENABLED;
540 uint32_t list_index = 0;
541 uint32_t list_length = u_arraylist_length(g_networkMonitorContext->netInterfaceList);
542 OIC_LOG_V(DEBUG, IP_MONITOR_TAG, "CAIPGetInterfaceInfo list length [%d]",
544 for (list_index = 0; list_index < list_length; list_index++)
546 CANetInfo_t *info = (CANetInfo_t *)u_arraylist_get(
547 g_networkMonitorContext->netInterfaceList, list_index);
552 OIC_LOG_V(DEBUG, IP_MONITOR_TAG, "CAIPGetInterfaceInfo ip [%s]",
554 CANetInfo_t *newNetinfo = (CANetInfo_t *) OICMalloc(sizeof(CANetInfo_t));
557 OIC_LOG(ERROR, IP_MONITOR_TAG, "Malloc failed!");
558 ca_mutex_unlock(g_networkMonitorContextMutex);
559 return CA_MEMORY_ALLOC_FAILED;
562 memcpy(newNetinfo, info, sizeof(*info));
564 CAResult_t result = u_arraylist_add(*netInterfaceList, (void *)newNetinfo);
565 if (CA_STATUS_OK != result)
567 OIC_LOG(ERROR, IP_MONITOR_TAG, "u_arraylist_add failed!");
568 ca_mutex_unlock(g_networkMonitorContextMutex);
569 return CA_STATUS_FAILED;
573 ca_mutex_unlock(g_networkMonitorContextMutex);
575 OIC_LOG(DEBUG, IP_MONITOR_TAG, "OUT");
579 CAResult_t CAIPGetInterfaceSubnetMask(const char *ipAddress, char **subnetMask)
581 OIC_LOG(DEBUG, IP_MONITOR_TAG, "IN");
583 VERIFY_NON_NULL(subnetMask, IP_MONITOR_TAG, "subnet mask");
584 VERIFY_NON_NULL(ipAddress, IP_MONITOR_TAG, "ipAddress is null");
585 VERIFY_NON_NULL(g_networkMonitorContext, IP_MONITOR_TAG,
586 "g_networkMonitorContext is null");
587 VERIFY_NON_NULL(g_networkMonitorContextMutex, IP_MONITOR_TAG,
588 "g_networkMonitorContextMutex is null");
590 // Get the interface and ipaddress information from cache
591 ca_mutex_lock(g_networkMonitorContextMutex);
592 if (!g_networkMonitorContext->netInterfaceList
593 || (0 == u_arraylist_length(g_networkMonitorContext->netInterfaceList)))
595 OIC_LOG(DEBUG, IP_MONITOR_TAG, "Network not enabled");
596 ca_mutex_unlock(g_networkMonitorContextMutex);
597 return CA_ADAPTER_NOT_ENABLED;
600 uint32_t list_index = 0;
601 uint32_t list_length = u_arraylist_length(g_networkMonitorContext->netInterfaceList);
602 OIC_LOG_V(DEBUG, IP_MONITOR_TAG, "list lenght [%d]", list_length);
603 for (list_index = 0; list_index < list_length; list_index++)
605 CANetInfo_t *info = (CANetInfo_t *)u_arraylist_get(
606 g_networkMonitorContext->netInterfaceList, list_index);
612 if (strncmp(info->ipAddress, ipAddress, strlen(ipAddress)) == 0)
614 OIC_LOG_V(DEBUG, IP_MONITOR_TAG,
615 "CAIPGetInterfaceSubnetMask subnetmask is %s", info->subnetMask);
616 *subnetMask = OICStrdup(info->subnetMask);
620 ca_mutex_unlock(g_networkMonitorContextMutex);
622 OIC_LOG(DEBUG, IP_MONITOR_TAG, "OUT");
626 bool CAIPIsConnected()
628 OIC_LOG(DEBUG, IP_MONITOR_TAG, "IN");
629 if (!g_networkMonitorContextMutex || !g_networkMonitorContext)
631 OIC_LOG(ERROR, IP_MONITOR_TAG, "IP is not connected");
635 ca_mutex_lock(g_networkMonitorContextMutex);
636 if (0 == u_arraylist_length(g_networkMonitorContext->netInterfaceList))
638 OIC_LOG(ERROR, IP_MONITOR_TAG, "IP is not connected");
639 ca_mutex_unlock(g_networkMonitorContextMutex);
642 ca_mutex_unlock(g_networkMonitorContextMutex);
644 OIC_LOG(DEBUG, IP_MONITOR_TAG, "OUT");
648 void CAIPSetConnectionStateChangeCallback(CAIPConnectionStateChangeCallback callback)
650 OIC_LOG(DEBUG, IP_MONITOR_TAG, "IN");
651 if (!g_networkMonitorContextMutex || !g_networkMonitorContext)
653 OIC_LOG(ERROR, IP_MONITOR_TAG, "CAIPSetConnectionStateChangeCallback failed");
656 ca_mutex_lock(g_networkMonitorContextMutex);
658 g_networkMonitorContext->networkChangeCb = callback;
660 ca_mutex_unlock(g_networkMonitorContextMutex);
662 OIC_LOG(DEBUG, IP_MONITOR_TAG, "OUT");