c1471b265d3b735dc1cf4533f54a30fc7d69063a
[platform/upstream/iotivity.git] / resource / csdk / connectivity / src / ip_adapter / linux / caipnwmonitor.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 <stdio.h>
24 #include <string.h>
25 #include <sys/types.h>
26 #include <sys/socket.h>
27 #include <sys/select.h>
28 #include <ifaddrs.h>
29 #include <unistd.h>
30 #include <fcntl.h>
31 #include <arpa/inet.h>
32 #include <netinet/in.h>
33 #include <net/if.h>
34 #include <netdb.h>
35 #include <errno.h>
36
37 #ifdef __linux__
38 #include <linux/netlink.h>
39 #include <linux/rtnetlink.h>
40 #endif
41
42 #include "caipnwmonitor.h"
43 #include "octhread.h"
44 #include "caadapterutils.h"
45 #include "logger.h"
46 #include "oic_malloc.h"
47 #include "oic_string.h"
48 #include <coap/utlist.h>
49
50 #define TAG "OIC_CA_IP_MONITOR"
51
52 /**
53  * Mutex for synchronizing access to cached interface and IP address information.
54  */
55 static oc_mutex g_networkMonitorContextMutex = NULL;
56
57 /**
58  * Used to storing network interface.
59  */
60 static u_arraylist_t *g_netInterfaceList = NULL;
61
62 /**
63  * Used to storing adapter changes callback interface.
64  */
65 static struct CAIPCBData_t *g_adapterCallbackList = NULL;
66
67 /**
68  * Initialize the network interface monitoring list.
69  */
70 static CAResult_t CAIPInitializeNetworkMonitorList();
71
72 /**
73  * Destroy the network interface monitoring list.
74  */
75 static void CAIPDestroyNetworkMonitorList();
76
77 /**
78  * Compare the interface with the already added interface in list.
79  */
80 static bool CACmpNetworkList(uint32_t ifiindex);
81
82 /**
83  * Add new network interface in list.
84  */
85 static CAResult_t CAAddNetworkMonitorList(CAInterface_t *ifitem);
86
87 /**
88  * Remove network interface from list.
89  */
90 static void CARemoveNetworkMonitorList(int ifiindex);
91
92 /**
93  * Pass the changed network status through the stored callback.
94  */
95 static void CAIPPassNetworkChangesToAdapter(CANetworkStatus_t status);
96
97 /**
98  * Create new interface item.
99  */
100 static CAInterface_t *CANewInterfaceItem(int index, const char *name, int family,
101                                          const char *addr, int flags);
102
103 static CAResult_t CAIPInitializeNetworkMonitorList()
104 {
105     if (!g_networkMonitorContextMutex)
106     {
107         g_networkMonitorContextMutex = oc_mutex_new();
108         if (!g_networkMonitorContextMutex)
109         {
110             OIC_LOG(ERROR, TAG, "oc_mutex_new has failed");
111             return CA_STATUS_FAILED;
112         }
113     }
114
115     if (!g_netInterfaceList)
116     {
117         g_netInterfaceList = u_arraylist_create();
118         if (!g_netInterfaceList)
119         {
120             OIC_LOG(ERROR, TAG, "u_arraylist_create has failed");
121             CAIPDestroyNetworkMonitorList();
122             return CA_STATUS_FAILED;
123         }
124     }
125     return CA_STATUS_OK;
126 }
127
128 static void CAIPDestroyNetworkMonitorList()
129 {
130     if (g_netInterfaceList)
131     {
132         u_arraylist_destroy(g_netInterfaceList);
133         g_netInterfaceList = NULL;
134     }
135
136     if (g_networkMonitorContextMutex)
137     {
138         oc_mutex_free(g_networkMonitorContextMutex);
139         g_networkMonitorContextMutex = NULL;
140     }
141 }
142
143 static bool CACmpNetworkList(uint32_t ifiindex)
144 {
145     if (!g_netInterfaceList)
146     {
147         OIC_LOG(ERROR, TAG, "g_netInterfaceList is NULL");
148         return false;
149     }
150
151     oc_mutex_lock(g_networkMonitorContextMutex);
152
153     uint32_t list_length = u_arraylist_length(g_netInterfaceList);
154     for (uint32_t list_index = 0; list_index < list_length; list_index++)
155     {
156         CAInterface_t *currItem = (CAInterface_t *) u_arraylist_get(g_netInterfaceList,
157                                                                     list_index);
158         if (currItem->index == ifiindex)
159         {
160             oc_mutex_unlock(g_networkMonitorContextMutex);
161             return true;
162         }
163     }
164     oc_mutex_unlock(g_networkMonitorContextMutex);
165     return false;
166 }
167
168 static CAResult_t CAAddNetworkMonitorList(CAInterface_t *ifitem)
169 {
170     VERIFY_NON_NULL(g_netInterfaceList, TAG, "g_netInterfaceList is NULL");
171     VERIFY_NON_NULL(ifitem, TAG, "ifitem is NULL");
172
173     oc_mutex_lock(g_networkMonitorContextMutex);
174     bool result = u_arraylist_add(g_netInterfaceList, (void *) ifitem);
175     if (!result)
176     {
177         OIC_LOG(ERROR, TAG, "u_arraylist_add failed.");
178         oc_mutex_unlock(g_networkMonitorContextMutex);
179         return CA_STATUS_FAILED;
180     }
181     oc_mutex_unlock(g_networkMonitorContextMutex);
182     return CA_STATUS_OK;
183 }
184
185 static void CARemoveNetworkMonitorList(int ifiindex)
186 {
187     VERIFY_NON_NULL_VOID(g_netInterfaceList, TAG, "g_netInterfaceList is NULL");
188
189     oc_mutex_lock(g_networkMonitorContextMutex);
190
191     uint32_t list_length = u_arraylist_length(g_netInterfaceList);
192     for (uint32_t list_index = 0; list_index < list_length; list_index++)
193     {
194         CAInterface_t *removedifitem = (CAInterface_t *) u_arraylist_get(
195                 g_netInterfaceList, list_index);
196         if (removedifitem && ((int)removedifitem->index) == ifiindex)
197         {
198             if (u_arraylist_remove(g_netInterfaceList, list_index))
199             {
200                 OICFree(removedifitem);
201                 oc_mutex_unlock(g_networkMonitorContextMutex);
202                 return;
203             }
204             continue;
205         }
206     }
207     oc_mutex_unlock(g_networkMonitorContextMutex);
208     return;
209 }
210
211 CAResult_t CAIPStartNetworkMonitor(CAIPAdapterStateChangeCallback callback,
212                                    CATransportAdapter_t adapter)
213 {
214     CAResult_t res = CAIPInitializeNetworkMonitorList();
215     if (CA_STATUS_OK == res)
216     {
217         return CAIPSetNetworkMonitorCallback(callback, adapter);
218     }
219     return res;
220 }
221
222 CAResult_t CAIPStopNetworkMonitor(CATransportAdapter_t adapter)
223 {
224     CAIPDestroyNetworkMonitorList();
225     return CAIPUnSetNetworkMonitorCallback(adapter);
226 }
227
228 int CAGetPollingInterval(int interval)
229 {
230     return interval;
231 }
232
233 static void CAIPPassNetworkChangesToAdapter(CANetworkStatus_t status)
234 {
235     CAIPCBData_t *cbitem = NULL;
236     LL_FOREACH(g_adapterCallbackList, cbitem)
237     {
238         if (cbitem && cbitem->adapter)
239         {
240             cbitem->callback(cbitem->adapter, status);
241         }
242     }
243 }
244
245 CAResult_t CAIPSetNetworkMonitorCallback(CAIPAdapterStateChangeCallback callback,
246                                          CATransportAdapter_t adapter)
247 {
248     if (!callback)
249     {
250         OIC_LOG(ERROR, TAG, "callback is null");
251         return CA_STATUS_INVALID_PARAM;
252     }
253
254     CAIPCBData_t *cbitem = NULL;
255     LL_FOREACH(g_adapterCallbackList, cbitem)
256     {
257         if (cbitem && adapter == cbitem->adapter && callback == cbitem->callback)
258         {
259             OIC_LOG(DEBUG, TAG, "this callback is already added");
260             return CA_STATUS_OK;
261         }
262     }
263
264     cbitem = (CAIPCBData_t *)OICCalloc(1, sizeof(*cbitem));
265     if (!cbitem)
266     {
267         OIC_LOG(ERROR, TAG, "Malloc failed");
268         return CA_STATUS_FAILED;
269     }
270
271     cbitem->adapter = adapter;
272     cbitem->callback = callback;
273     LL_APPEND(g_adapterCallbackList, cbitem);
274
275     return CA_STATUS_OK;
276 }
277
278 CAResult_t CAIPUnSetNetworkMonitorCallback(CATransportAdapter_t adapter)
279 {
280     CAIPCBData_t *cbitem = NULL;
281     CAIPCBData_t *tmpCbitem = NULL;
282     LL_FOREACH_SAFE(g_adapterCallbackList, cbitem, tmpCbitem)
283     {
284         if (cbitem && adapter == cbitem->adapter)
285         {
286             OIC_LOG(DEBUG, TAG, "remove specific callback");
287             LL_DELETE(g_adapterCallbackList, cbitem);
288             OICFree(cbitem);
289             return CA_STATUS_OK;
290         }
291     }
292     return CA_STATUS_OK;
293 }
294
295 static CAInterface_t *CANewInterfaceItem(int index, const char *name, int family,
296                                          const char *addr, int flags)
297 {
298     CAInterface_t *ifitem = (CAInterface_t *)OICCalloc(1, sizeof (CAInterface_t));
299     if (!ifitem)
300     {
301         OIC_LOG(ERROR, TAG, "Malloc failed");
302         return NULL;
303     }
304
305     OICStrcpy(ifitem->name, sizeof (ifitem->name), name);
306     ifitem->index = index;
307     ifitem->family = family;
308     OICStrcpy(ifitem->addr, sizeof (ifitem->addr), addr);
309     ifitem->flags = flags;
310
311     return ifitem;
312 }
313
314 CAInterface_t *CAFindInterfaceChange()
315 {
316     CAInterface_t *foundNewInterface = NULL;
317 #ifdef __linux__
318     char buf[4096] = { 0 };
319     struct nlmsghdr *nh = NULL;
320     struct sockaddr_nl sa = { .nl_family = 0 };
321     struct iovec iov = { .iov_base = buf,
322                          .iov_len = sizeof (buf) };
323     struct msghdr msg = { .msg_name = (void *)&sa,
324                           .msg_namelen = sizeof (sa),
325                           .msg_iov = &iov,
326                           .msg_iovlen = 1 };
327
328     size_t len = recvmsg(caglobals.ip.netlinkFd, &msg, 0);
329
330     for (nh = (struct nlmsghdr *)buf; NLMSG_OK(nh, len); nh = NLMSG_NEXT(nh, len))
331     {
332         if (nh != NULL && nh->nlmsg_type != RTM_NEWLINK)
333         {
334             continue;
335         }
336
337         struct ifinfomsg *ifi = (struct ifinfomsg *)NLMSG_DATA(nh);
338
339         int ifiIndex = ifi->ifi_index;
340
341         if ((!ifi || (ifi->ifi_flags & IFF_LOOPBACK) || !(ifi->ifi_flags & IFF_RUNNING)))
342         {
343             bool isFound = CACmpNetworkList(ifiIndex);
344             if (isFound)
345             {
346                 CARemoveNetworkMonitorList(ifiIndex);
347                 CAIPPassNetworkChangesToAdapter(CA_INTERFACE_DOWN);
348             }
349             continue;
350         }
351
352         u_arraylist_t *iflist = CAIPGetInterfaceInformation(ifiIndex);
353         if (!iflist)
354         {
355             OIC_LOG_V(ERROR, TAG, "get interface info failed: %s", strerror(errno));
356             return NULL;
357         }
358
359         uint32_t listLength = u_arraylist_length(iflist);
360         for (uint32_t i = 0; i < listLength; i++)
361         {
362             CAInterface_t *ifitem = (CAInterface_t *)u_arraylist_get(iflist, i);
363             if (!ifitem)
364             {
365                 continue;
366             }
367
368             if ((int)ifitem->index != ifiIndex)
369             {
370                 continue;
371             }
372
373             foundNewInterface = CANewInterfaceItem(ifitem->index, ifitem->name, ifitem->family,
374                                                    ifitem->addr, ifitem->flags);
375             break;    // we found the one we were looking for
376         }
377         u_arraylist_destroy(iflist);
378     }
379 #endif
380     return foundNewInterface;
381 }
382
383 u_arraylist_t *CAIPGetInterfaceInformation(int desiredIndex)
384 {
385     if (desiredIndex < 0)
386     {
387         OIC_LOG_V(ERROR, TAG, "invalid index : %d", desiredIndex);
388         return NULL;
389     }
390
391     u_arraylist_t *iflist = u_arraylist_create();
392     if (!iflist)
393     {
394         OIC_LOG_V(ERROR, TAG, "Failed to create iflist: %s", strerror(errno));
395         return NULL;
396     }
397
398     struct ifaddrs *ifp = NULL;
399     if (-1 == getifaddrs(&ifp))
400     {
401         OIC_LOG_V(ERROR, TAG, "Failed to get ifaddrs: %s", strerror(errno));
402         u_arraylist_destroy(iflist);
403         return NULL;
404     }
405
406     struct ifaddrs *ifa = NULL;
407     for (ifa = ifp; ifa; ifa = ifa->ifa_next)
408     {
409         if (!ifa->ifa_addr)
410         {
411             continue;
412         }
413         int family = ifa->ifa_addr->sa_family;
414         if ((ifa->ifa_flags & IFF_LOOPBACK) || (AF_INET != family && AF_INET6 != family))
415         {
416             continue;
417         }
418
419         int ifindex = if_nametoindex(ifa->ifa_name);
420         if (desiredIndex && (ifindex != desiredIndex))
421         {
422             continue;
423         }
424
425         int length = u_arraylist_length(iflist);
426         int already = false;
427         for (int i = length-1; i >= 0; i--)
428         {
429             CAInterface_t *ifitem = (CAInterface_t *)u_arraylist_get(iflist, i);
430
431             if (ifitem
432                 && (int)ifitem->index == ifindex
433                 && ifitem->family == (uint16_t)family)
434             {
435                 already = true;
436                 break;
437             }
438         }
439         if (already)
440         {
441             continue;
442         }
443
444         CAInterface_t *ifitem = (CAInterface_t *)OICCalloc(1, sizeof(CAInterface_t));
445         if (!ifitem)
446         {
447             OIC_LOG(ERROR, TAG, "Malloc failed");
448             goto exit;
449         }
450
451         OICStrcpy(ifitem->name, INTERFACE_NAME_MAX, ifa->ifa_name);
452         ifitem->index = ifindex;
453         ifitem->family = family;
454         ifitem->flags = ifa->ifa_flags;
455
456         if (ifitem->family == AF_INET6)
457         {
458             struct sockaddr_in6 *in6 = (struct sockaddr_in6*) ifa->ifa_addr;
459             inet_ntop(ifitem->family, (void *)&(in6->sin6_addr), ifitem->addr,
460                       sizeof(ifitem->addr));
461         }
462         else if (ifitem->family == AF_INET)
463         {
464             struct sockaddr_in *in = (struct sockaddr_in*) ifa->ifa_addr;
465             inet_ntop(ifitem->family, (void *)&(in->sin_addr), ifitem->addr,
466                       sizeof(ifitem->addr));
467         }
468
469         bool result = u_arraylist_add(iflist, ifitem);
470         if (!result)
471         {
472             OIC_LOG(ERROR, TAG, "u_arraylist_add failed.");
473             goto exit;
474         }
475
476         bool isFound = CACmpNetworkList(ifitem->index);
477         if (!isFound)
478         {
479             CAInterface_t *newifitem = CANewInterfaceItem(ifitem->index, ifitem->name, ifitem->family,
480                                                           ifitem->addr, ifitem->flags);
481             CAResult_t ret = CAAddNetworkMonitorList(newifitem);
482             if (CA_STATUS_OK != ret)
483             {
484                 OICFree(newifitem);
485                 goto exit;
486             }
487             CAIPPassNetworkChangesToAdapter(CA_INTERFACE_UP);
488             OIC_LOG_V(DEBUG, TAG, "Added interface: %s (%d)", ifitem->name, ifitem->family);
489         }
490     }
491     freeifaddrs(ifp);
492     return iflist;
493
494 exit:
495     freeifaddrs(ifp);
496     u_arraylist_destroy(iflist);
497     return NULL;
498 }