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"
25 #include <sys/types.h>
26 #include <sys/socket.h>
27 #include <sys/select.h>
31 #include <arpa/inet.h>
32 #include <netinet/in.h>
38 #include "caipnwmonitor.h"
39 #include "caadapterutils.h"
41 #include "oic_malloc.h"
42 #include "oic_string.h"
43 #include <coap/utlist.h>
45 #import <Foundation/Foundation.h>
46 #import <SystemConfiguration/CaptiveNetwork.h>
48 #define TAG "OIC_CA_IP_MONITOR"
51 * Mutex for synchronizing access to cached interface and IP address information.
53 static oc_mutex g_networkMonitorContextMutex = NULL;
56 * Used to storing network interface.
58 static u_arraylist_t *g_netInterfaceList = NULL;
61 * Used to storing initial AP Name.
63 NSString *initialAPName = nil;
66 * Used to storing adapter changes callback interface.
68 static struct CAIPCBData_t *g_adapterCallbackList = NULL;
71 * Initialize the network interface monitoring list.
73 static CAResult_t CAIPInitializeNetworkMonitorList();
76 * Destroy the network interface monitoring list.
78 static void CAIPDestroyNetworkMonitorList();
81 * Compare the interface with the already added interface in list.
83 static bool CACmpNetworkList(size_t ifiindex);
86 * Add new network interface in list.
88 static CAResult_t CAAddNetworkMonitorList(CAInterface_t *ifitem);
91 * Remove network interace from list.
93 static void CARemoveNetworkMonitorList(int ifiindex);
96 * Pass the changed network status through the stored callback.
98 static void CAIPPassNetworkChangesToAdapter(CANetworkStatus_t status);
101 * Create new interface item.
103 static CAInterface_t *CANewInterfaceItem(int index, const char *name, int family,
104 const char *addr, int flags);
107 * Callback function invoked for each observer of a notification
108 * when the notification is posted.
109 * @param center The notification center handling the notification
110 * @param observer An arbitrary value, other than NULL, that identifies the observer
111 * @param name The name of the notification being posted
112 * @param object An arbitrary value that identifies the object posting the notification
113 * @param userInfo A dictionary containing additional information regarding
116 static void onNotifyCallback(CFNotificationCenterRef center, void *observer,
117 CFStringRef name, const void *object, CFDictionaryRef userInfo);
120 * Check whether Celluler data is On/Off
122 bool isCellulerDataEnabled();
124 static CAResult_t CAIPInitializeNetworkMonitorList()
126 if (!g_networkMonitorContextMutex)
128 g_networkMonitorContextMutex = oc_mutex_new();
129 if (!g_networkMonitorContextMutex)
131 OIC_LOG(ERROR, TAG, "oc_mutex_new has failed");
132 return CA_STATUS_FAILED;
136 if (!g_netInterfaceList)
138 g_netInterfaceList = u_arraylist_create();
139 if (!g_netInterfaceList)
141 OIC_LOG(ERROR, TAG, "u_arraylist_create has failed");
142 CAIPDestroyNetworkMonitorList();
143 return CA_STATUS_FAILED;
149 static void CAIPDestroyNetworkMonitorList()
151 if (g_netInterfaceList)
153 u_arraylist_destroy(g_netInterfaceList);
154 g_netInterfaceList = NULL;
157 if (g_networkMonitorContextMutex)
159 oc_mutex_free(g_networkMonitorContextMutex);
160 g_networkMonitorContextMutex = NULL;
164 static bool CACmpNetworkList(size_t ifiindex)
166 if (!g_netInterfaceList)
168 OIC_LOG(ERROR, TAG, "g_netInterfaceList is NULL");
172 oc_mutex_lock(g_networkMonitorContextMutex);
174 size_t list_length = u_arraylist_length(g_netInterfaceList);
175 for (size_t list_index = 0; list_index < list_length; list_index++)
177 CAInterface_t *currItem = (CAInterface_t *) u_arraylist_get(g_netInterfaceList,
179 if (currItem->index == ifiindex)
181 oc_mutex_unlock(g_networkMonitorContextMutex);
185 oc_mutex_unlock(g_networkMonitorContextMutex);
189 static CAResult_t CAAddNetworkMonitorList(CAInterface_t *ifitem)
191 VERIFY_NON_NULL(g_netInterfaceList, TAG, "g_netInterfaceList is NULL");
192 VERIFY_NON_NULL(ifitem, TAG, "ifitem is NULL");
194 oc_mutex_lock(g_networkMonitorContextMutex);
195 bool result = u_arraylist_add(g_netInterfaceList, (void *) ifitem);
198 OIC_LOG(ERROR, TAG, "u_arraylist_add failed.");
199 oc_mutex_unlock(g_networkMonitorContextMutex);
200 return CA_STATUS_FAILED;
202 oc_mutex_unlock(g_networkMonitorContextMutex);
206 static void CARemoveNetworkMonitorList(int ifiindex)
208 VERIFY_NON_NULL_VOID(g_netInterfaceList, TAG, "g_netInterfaceList is NULL");
210 oc_mutex_lock(g_networkMonitorContextMutex);
212 size_t list_length = u_arraylist_length(g_netInterfaceList);
213 for (size_t list_index = 0; list_index < list_length; list_index++)
215 CAInterface_t *removedifitem = (CAInterface_t *) u_arraylist_get(
216 g_netInterfaceList, list_index);
217 if (removedifitem && ((int)removedifitem->index) == ifiindex)
219 if (u_arraylist_remove(g_netInterfaceList, list_index))
221 OICFree(removedifitem);
222 oc_mutex_unlock(g_networkMonitorContextMutex);
228 oc_mutex_unlock(g_networkMonitorContextMutex);
232 CAResult_t CAIPStartNetworkMonitor(CAIPAdapterStateChangeCallback callback,
233 CATransportAdapter_t adapter)
235 NSDictionary *connectionDetails = [NSDictionary dictionary];
236 NSArray *myArray = (id) CNCopySupportedInterfaces();
238 CFDictionaryRef myDict = CNCopyCurrentNetworkInfo((__bridge CFStringRef)myArray[0]);
239 connectionDetails = (NSDictionary*) myDict;
242 initialAPName = connectionDetails[@"SSID"];
243 OIC_LOG_V(INFO, TAG, "Initial AP Name = %s", [initialAPName UTF8String]);
245 CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(),
248 CFSTR("com.apple.system.config.network_change"),
250 CFNotificationSuspensionBehaviorDeliverImmediately);
252 OIC_LOG_V(INFO, TAG, "Celluler Data Enabled = %d", isCellulerDataEnabled());
254 CAResult_t res = CAIPInitializeNetworkMonitorList();
255 if (CA_STATUS_OK == res)
257 return CAIPSetNetworkMonitorCallback(callback, adapter);
262 CAResult_t CAIPStopNetworkMonitor(CATransportAdapter_t adapter)
264 CFNotificationCenterRemoveObserver(CFNotificationCenterGetDarwinNotifyCenter(),
265 NULL, CFSTR("com.apple.system.config.network_change"), NULL);
266 CAIPDestroyNetworkMonitorList();
267 return CAIPUnSetNetworkMonitorCallback(adapter);
270 int CAGetPollingInterval(int interval)
275 static void CAIPPassNetworkChangesToAdapter(CANetworkStatus_t status)
277 CAIPCBData_t *cbitem = NULL;
278 LL_FOREACH(g_adapterCallbackList, cbitem)
280 if (cbitem && cbitem->adapter)
282 cbitem->callback(cbitem->adapter, status);
287 CAResult_t CAIPSetNetworkMonitorCallback(CAIPAdapterStateChangeCallback callback,
288 CATransportAdapter_t adapter)
292 OIC_LOG(ERROR, TAG, "callback is null");
293 return CA_STATUS_INVALID_PARAM;
296 CAIPCBData_t *cbitem = NULL;
297 LL_FOREACH(g_adapterCallbackList, cbitem)
299 if (cbitem && adapter == cbitem->adapter && callback == cbitem->callback)
301 OIC_LOG(DEBUG, TAG, "this callback is already added");
306 cbitem = (CAIPCBData_t *)OICCalloc(1, sizeof(*cbitem));
309 OIC_LOG(ERROR, TAG, "Malloc failed");
310 return CA_STATUS_FAILED;
313 cbitem->adapter = adapter;
314 cbitem->callback = callback;
315 LL_APPEND(g_adapterCallbackList, cbitem);
320 CAResult_t CAIPUnSetNetworkMonitorCallback(CATransportAdapter_t adapter)
322 CAIPCBData_t *cbitem = NULL;
323 CAIPCBData_t *tmpCbitem = NULL;
324 LL_FOREACH_SAFE(g_adapterCallbackList, cbitem, tmpCbitem)
326 if (cbitem && adapter == cbitem->adapter)
328 OIC_LOG(DEBUG, TAG, "remove specific callback");
329 LL_DELETE(g_adapterCallbackList, cbitem);
337 static CAInterface_t *CANewInterfaceItem(int index, const char *name, int family,
338 const char *addr, int flags)
340 CAInterface_t *ifitem = (CAInterface_t *)OICCalloc(1, sizeof (CAInterface_t));
343 OIC_LOG(ERROR, TAG, "Malloc failed");
347 OICStrcpy(ifitem->name, sizeof (ifitem->name), name);
348 ifitem->index = index;
349 ifitem->family = family;
350 OICStrcpy(ifitem->addr, sizeof (ifitem->addr), addr);
351 ifitem->flags = flags;
356 u_arraylist_t *CAFindInterfaceChange()
358 u_arraylist_t *iflist = NULL;
359 char buf[4096] = { 0 };
360 struct nlmsghdr *nh = NULL;
361 struct iovec iov = { .iov_base = buf,
362 .iov_len = sizeof (buf) };
363 struct msghdr msg = { .msg_name = (void *)0,
368 ssize_t len = recvmsg(caglobals.ip.netlinkFd, &msg, 0);
372 u_arraylist_t *CAIPGetInterfaceInformation(int desiredIndex)
374 if (desiredIndex < 0)
376 OIC_LOG_V(ERROR, TAG, "invalid index : %d", desiredIndex);
380 u_arraylist_t *iflist = u_arraylist_create();
383 OIC_LOG_V(ERROR, TAG, "Failed to create iflist: %s", strerror(errno));
387 struct ifaddrs *ifp = NULL;
388 if (-1 == getifaddrs(&ifp))
390 OIC_LOG_V(ERROR, TAG, "Failed to get ifaddrs: %s", strerror(errno));
391 u_arraylist_destroy(iflist);
395 struct ifaddrs *ifa = NULL;
396 for (ifa = ifp; ifa; ifa = ifa->ifa_next)
402 int family = ifa->ifa_addr->sa_family;
403 if ((ifa->ifa_flags & IFF_LOOPBACK) || (AF_INET != family && AF_INET6 != family))
408 int ifindex = if_nametoindex(ifa->ifa_name);
409 if (desiredIndex && (ifindex != desiredIndex))
414 int length = u_arraylist_length(iflist);
416 for (int i = length-1; i >= 0; i--)
418 CAInterface_t *ifitem = (CAInterface_t *)u_arraylist_get(iflist, i);
421 && (int)ifitem->index == ifindex
422 && ifitem->family == (uint16_t)family)
433 CAInterface_t *ifitem = (CAInterface_t *)OICCalloc(1, sizeof(CAInterface_t));
436 OIC_LOG(ERROR, TAG, "Malloc failed");
440 OICStrcpy(ifitem->name, INTERFACE_NAME_MAX, ifa->ifa_name);
441 ifitem->index = ifindex;
442 ifitem->family = family;
443 ifitem->flags = ifa->ifa_flags;
445 if (ifitem->family == AF_INET6)
447 struct sockaddr_in6 *in6 = (struct sockaddr_in6*) ifa->ifa_addr;
448 inet_ntop(ifitem->family, (void *)&(in6->sin6_addr), ifitem->addr,
449 sizeof(ifitem->addr));
451 else if (ifitem->family == AF_INET)
453 struct sockaddr_in *in = (struct sockaddr_in*) ifa->ifa_addr;
454 inet_ntop(ifitem->family, (void *)&(in->sin_addr), ifitem->addr,
455 sizeof(ifitem->addr));
458 bool result = u_arraylist_add(iflist, ifitem);
461 OIC_LOG(ERROR, TAG, "u_arraylist_add failed.");
465 bool isFound = CACmpNetworkList(ifitem->index);
468 CAInterface_t *newifitem = CANewInterfaceItem(ifitem->index, ifitem->name,
469 ifitem->family, ifitem->addr, ifitem->flags);
470 CAResult_t ret = CAAddNetworkMonitorList(newifitem);
471 if (CA_STATUS_OK != ret)
476 CAIPPassNetworkChangesToAdapter(CA_INTERFACE_UP);
477 OIC_LOG_V(DEBUG, TAG, "Added interface: %s (%d)", ifitem->name, ifitem->family);
485 u_arraylist_destroy(iflist);
490 void CAIpStateEnabled()
492 OIC_LOG(DEBUG, TAG, "Wifi is in Activated State");
493 CAIPPassNetworkChangesToAdapter(CA_INTERFACE_UP);
495 u_arraylist_t *iflist = CAIPGetInterfaceInformation(0);
498 OIC_LOG_V(ERROR, TAG, "get interface info failed: %s", strerror(errno));
502 size_t listLength = u_arraylist_length(iflist);
503 for (size_t i = 0; i < listLength; i++)
505 CAInterface_t *ifitem = (CAInterface_t *)u_arraylist_get(iflist, i);
510 CAProcessNewInterface(ifitem);
512 u_arraylist_destroy(iflist);
515 void CAIpStateDisabled()
517 OIC_LOG(DEBUG, TAG, "Wifi or Celluler Data is in Deactivated State");
518 CAIPPassNetworkChangesToAdapter(CA_INTERFACE_DOWN);
521 bool isCellulerDataEnabled()
523 struct ifaddrs* interfaces = NULL;
524 struct ifaddrs* temp_addr = NULL;
526 bool isEnabled = false;
528 success = getifaddrs(&interfaces);
532 temp_addr = interfaces;
534 while (temp_addr != NULL)
536 if ((temp_addr->ifa_addr->sa_family == AF_INET) || (temp_addr->ifa_addr->sa_family == AF_INET6))
538 NSString* ifa_name = [NSString stringWithUTF8String: temp_addr->ifa_name];
539 if ([ifa_name isEqualToString:@"pdp_ip0"])
545 temp_addr = temp_addr->ifa_next;
548 freeifaddrs(interfaces);
553 static void onNotifyCallback(CFNotificationCenterRef center, void *observer, CFStringRef name,
554 const void *object, CFDictionaryRef userInfo)
556 NSString* notifyName = (__bridge NSString*) name;
557 if ([notifyName isEqualToString:@"com.apple.system.config.network_change"]) {
558 NSDictionary *connectionDetails = [NSDictionary dictionary];
559 NSArray *myArray = (id) CNCopySupportedInterfaces();
561 CFDictionaryRef myDict = CNCopyCurrentNetworkInfo((__bridge CFStringRef)myArray[0]);
562 connectionDetails = (NSDictionary*)myDict;
565 NSString *apName = connectionDetails[@"SSID"];
566 if (apName == nil && !isCellulerDataEnabled())
568 OIC_LOG(INFO, TAG, "WiFi AP or Celluler Data is OFF!");
572 else if(![apName isEqualToString:initialAPName] || isCellulerDataEnabled())
574 initialAPName = apName;
575 OIC_LOG_V(INFO, TAG, "Current AP Name = %s", [initialAPName UTF8String]);
576 OIC_LOG_V(INFO, TAG, "Celluler Data Enabled = %d", isCellulerDataEnabled());