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/types.h>
28 #include <sys/select.h>
32 #include <arpa/inet.h>
33 #include <netinet/in.h>
39 #include <linux/netlink.h>
40 #include <linux/rtnetlink.h>
41 #include <arpa/inet.h>
42 #include <netinet/in.h>
46 #include "caadapterutils.h"
48 #include "oic_malloc.h"
49 #include "oic_string.h"
51 #define TAG "OIC_CA_IP_MONITOR"
54 * Mutex for synchronizing access to cached interface and IP address information.
56 static ca_mutex g_networkMonitorContextMutex = NULL;
59 * Used to storing network interface.
61 static u_arraylist_t *g_netInterfaceList = NULL;
63 static CAIPConnectionStateChangeCallback g_networkChangeCallback = NULL;
65 static CAResult_t CAIPInitializeNetworkMonitorList();
66 static void CAIPDestroyNetworkMonitorList();
67 static CAInterface_t *CANewInterfaceItem(int index, const char *name, int family,
68 uint32_t addr, int flags);
70 static CAResult_t CAIPInitializeNetworkMonitorList()
72 if (!g_networkMonitorContextMutex)
74 g_networkMonitorContextMutex = ca_mutex_new();
75 if (!g_networkMonitorContextMutex)
77 OIC_LOG(ERROR, TAG, "ca_mutex_new has failed");
78 return CA_STATUS_FAILED;
82 if (!g_netInterfaceList)
84 g_netInterfaceList = u_arraylist_create();
85 if (!g_netInterfaceList)
87 OIC_LOG(ERROR, TAG, "u_arraylist_create has failed");
88 CAIPDestroyNetworkMonitorList();
89 return CA_STATUS_FAILED;
94 static void CAIPDestroyNetworkMonitorList()
96 if (g_netInterfaceList)
98 u_arraylist_destroy(g_netInterfaceList);
99 g_netInterfaceList = NULL;
102 if (g_networkMonitorContextMutex)
104 ca_mutex_free(g_networkMonitorContextMutex);
105 g_networkMonitorContextMutex = NULL;
109 static bool CACmpNetworkList(uint32_t ifiindex)
111 if (!g_netInterfaceList)
113 OIC_LOG(ERROR, TAG, "g_netInterfaceList is NULL");
117 ca_mutex_lock(g_networkMonitorContextMutex);
119 uint32_t list_length = u_arraylist_length(g_netInterfaceList);
120 for (uint32_t list_index = 0; list_index < list_length; list_index++)
122 CAInterface_t *currItem = (CAInterface_t *) u_arraylist_get(g_netInterfaceList, list_index);
123 if (currItem->index == ifiindex)
125 ca_mutex_unlock(g_networkMonitorContextMutex);
129 ca_mutex_unlock(g_networkMonitorContextMutex);
133 static CAResult_t CAAddNetworkMonitorList(CAInterface_t *ifitem)
135 VERIFY_NON_NULL(g_netInterfaceList, TAG, "g_netInterfaceList is NULL");
136 VERIFY_NON_NULL(ifitem, TAG, "ifitem is NULL");
138 ca_mutex_lock(g_networkMonitorContextMutex);
139 bool result = u_arraylist_add(g_netInterfaceList, (void *) ifitem);
142 OIC_LOG(ERROR, TAG, "u_arraylist_add failed.");
143 ca_mutex_unlock(g_networkMonitorContextMutex);
144 return CA_STATUS_FAILED;
146 ca_mutex_unlock(g_networkMonitorContextMutex);
150 static void CARemoveNetworkMonitorList(int ifiindex)
152 VERIFY_NON_NULL_VOID(g_netInterfaceList, TAG, "g_netInterfaceList is NULL");
154 ca_mutex_lock(g_networkMonitorContextMutex);
156 uint32_t list_length = u_arraylist_length(g_netInterfaceList);
157 for (uint32_t list_index = 0; list_index < list_length; list_index++)
159 CAInterface_t *removedifitem = (CAInterface_t *) u_arraylist_get(
160 g_netInterfaceList, list_index);
161 if (removedifitem && removedifitem->index == ifiindex)
163 if (u_arraylist_remove(g_netInterfaceList, list_index))
165 OICFree(removedifitem);
166 ca_mutex_unlock(g_networkMonitorContextMutex);
172 ca_mutex_unlock(g_networkMonitorContextMutex);
176 CAResult_t CAIPStartNetworkMonitor()
178 return CAIPInitializeNetworkMonitorList();
181 CAResult_t CAIPStopNetworkMonitor()
183 CAIPDestroyNetworkMonitorList();
187 int CAGetPollingInterval(int interval)
192 void CAIPSetNetworkMonitorCallback(CAIPConnectionStateChangeCallback callback)
194 g_networkChangeCallback = callback;
197 static CAInterface_t *CANewInterfaceItem(int index, const char *name, int family,
198 uint32_t addr, int flags)
200 CAInterface_t *ifitem = (CAInterface_t *)OICCalloc(1, sizeof (CAInterface_t));
203 OIC_LOG(ERROR, TAG, "Malloc failed");
207 OICStrcpy(ifitem->name, sizeof (ifitem->name), name);
208 ifitem->index = index;
209 ifitem->family = family;
210 ifitem->ipv4addr = addr;
211 ifitem->flags = flags;
216 CAInterface_t *CAFindInterfaceChange()
218 CAInterface_t *foundNewInterface = NULL;
222 struct sockaddr_nl sa;
223 struct iovec iov = { buf, sizeof (buf) };
224 struct msghdr msg = { (void *)&sa, sizeof (sa), &iov, 1, NULL, 0, 0 };
226 size_t len = recvmsg(caglobals.ip.netlinkFd, &msg, 0);
228 for (nh = (struct nlmsghdr *)buf; NLMSG_OK(nh, len); nh = NLMSG_NEXT(nh, len))
230 if (nh != NULL && nh->nlmsg_type != RTM_NEWLINK)
235 struct ifinfomsg *ifi = (struct ifinfomsg *)NLMSG_DATA(nh);
237 int ifiIndex = ifi->ifi_index;
238 u_arraylist_t *iflist = CAIPGetInterfaceInformation(ifiIndex);
240 if ((!ifi || (ifi->ifi_flags & IFF_LOOPBACK) || !(ifi->ifi_flags & IFF_RUNNING)))
242 bool isFound = CACmpNetworkList(ifiIndex);
245 CARemoveNetworkMonitorList(ifiIndex);
246 if (g_networkChangeCallback)
248 g_networkChangeCallback(CA_ADAPTER_IP ,CA_INTERFACE_DOWN);
256 OIC_LOG_V(ERROR, TAG, "get interface info failed: %s", strerror(errno));
260 uint32_t listLength = u_arraylist_length(iflist);
261 for (uint32_t i = 0; i < listLength; i++)
263 CAInterface_t *ifitem = (CAInterface_t *)u_arraylist_get(iflist, i);
269 if ((int)ifitem->index != ifiIndex)
274 foundNewInterface = CANewInterfaceItem(ifitem->index, ifitem->name, ifitem->family,
275 ifitem->ipv4addr, ifitem->flags);
276 break; // we found the one we were looking for
278 u_arraylist_destroy(iflist);
281 return foundNewInterface;
284 u_arraylist_t *CAIPGetInterfaceInformation(int desiredIndex)
286 if (desiredIndex < 0)
288 OIC_LOG_V(ERROR, TAG, "invalid index : %d", desiredIndex);
292 u_arraylist_t *iflist = u_arraylist_create();
295 OIC_LOG_V(ERROR, TAG, "Failed to create iflist: %s", strerror(errno));
299 struct ifaddrs *ifp = NULL;
300 if (-1 == getifaddrs(&ifp))
302 OIC_LOG_V(ERROR, TAG, "Failed to get ifaddrs: %s", strerror(errno));
303 u_arraylist_destroy(iflist);
306 OIC_LOG(DEBUG, TAG, "Got ifaddrs");
308 struct ifaddrs *ifa = NULL;
309 for (ifa = ifp; ifa; ifa = ifa->ifa_next)
315 int family = ifa->ifa_addr->sa_family;
316 if ((ifa->ifa_flags & IFF_LOOPBACK) || (AF_INET != family && AF_INET6 != family))
321 int ifindex = if_nametoindex(ifa->ifa_name);
322 if (desiredIndex && (ifindex != desiredIndex))
327 int length = u_arraylist_length(iflist);
329 for (int i = length-1; i >= 0; i--)
331 CAInterface_t *ifitem = (CAInterface_t *)u_arraylist_get(iflist, i);
334 && (int)ifitem->index == ifindex
335 && ifitem->family == (uint16_t)family)
346 CAInterface_t *ifitem = (CAInterface_t *)OICCalloc(1, sizeof(CAInterface_t));
349 OIC_LOG(ERROR, TAG, "Malloc failed");
353 OICStrcpy(ifitem->name, INTERFACE_NAME_MAX, ifa->ifa_name);
354 ifitem->index = ifindex;
355 ifitem->family = family;
356 ifitem->ipv4addr = ((struct sockaddr_in *)(ifa->ifa_addr))->sin_addr.s_addr;
357 ifitem->flags = ifa->ifa_flags;
359 bool result = u_arraylist_add(iflist, ifitem);
362 OIC_LOG(ERROR, TAG, "u_arraylist_add failed.");
366 bool isFound = CACmpNetworkList(ifitem->index);
369 CAInterface_t *newifitem = CANewInterfaceItem(ifitem->index, ifitem->name, ifitem->family,
370 ifitem->ipv4addr, ifitem->flags);
371 CAResult_t ret = CAAddNetworkMonitorList(newifitem);
372 if (CA_STATUS_OK != ret)
377 if (g_networkChangeCallback)
379 g_networkChangeCallback(CA_ADAPTER_IP, CA_INTERFACE_UP);
381 OIC_LOG_V(DEBUG, TAG, "Added interface: %s (%d)", ifitem->name, ifitem->family);
389 u_arraylist_destroy(iflist);