Merge branch 'tizen' into tizen_5.5
[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 "octhread.h"
43 #include "caipnwmonitor.h"
44 #include "caipnwmonitor_common.h"
45 #include "caadapterutils.h"
46 #include "logger.h"
47 #include "oic_malloc.h"
48 #include "oic_string.h"
49 #include <coap/utlist.h>
50
51 #define TAG "OIC_CA_IP_MONITOR"
52
53 /**
54  * Mutex for synchronizing access to cached interface and IP address information.
55  */
56 static oc_mutex g_networkMonitorContextMutex = NULL;
57
58 /**
59  * Used to storing network interface.
60  */
61 static u_arraylist_t *g_netInterfaceList = NULL;
62
63 /**
64  * Used to storing adapter changes callback interface.
65  */
66 static struct CAIPCBData_t *g_adapterCallbackList = NULL;
67
68 /**
69  * Initialize the network interface monitoring list.
70  */
71 static CAResult_t CAIPInitializeNetworkMonitorList();
72
73 /**
74  * Destroy the network interface monitoring list.
75  */
76 static void CAIPDestroyNetworkMonitorList();
77
78 /**
79  * Compare the interface with the already added interface in list.
80  */
81 static bool CACmpNetworkList(uint32_t ifiindex);
82
83 /**
84  * Add new network interface in list.
85  */
86 static CAResult_t CAAddNetworkMonitorList(CAInterface_t *ifitem);
87
88 /**
89  * Remove network interace from list.
90  */
91 static void CARemoveNetworkMonitorList(int ifiindex);
92
93 /**
94  * Pass the changed network status through the stored callback.
95  */
96 static void CAIPPassNetworkChangesToAdapter(CANetworkStatus_t status);
97
98 /**
99  * Create new interface item.
100  */
101 static CAInterface_t *CANewInterfaceItem(int index, const char *name, int family,
102                                          const char *addr, int flags);
103
104 static CAResult_t CAIPInitializeNetworkMonitorList()
105 {
106     if (!g_networkMonitorContextMutex)
107     {
108         g_networkMonitorContextMutex = oc_mutex_new();
109         if (!g_networkMonitorContextMutex)
110         {
111             OIC_LOG(ERROR, TAG, "oc_mutex_new has failed");
112             return CA_STATUS_FAILED;
113         }
114     }
115
116     if (!g_netInterfaceList)
117     {
118         g_netInterfaceList = u_arraylist_create();
119         if (!g_netInterfaceList)
120         {
121             OIC_LOG(ERROR, TAG, "u_arraylist_create has failed");
122             CAIPDestroyNetworkMonitorList();
123             return CA_STATUS_FAILED;
124         }
125     }
126     return CA_STATUS_OK;
127 }
128
129 static void CAIPDestroyNetworkMonitorList()
130 {
131     if (g_netInterfaceList)
132     {
133         u_arraylist_destroy(g_netInterfaceList);
134         g_netInterfaceList = NULL;
135     }
136
137     if (g_networkMonitorContextMutex)
138     {
139         oc_mutex_free(g_networkMonitorContextMutex);
140         g_networkMonitorContextMutex = NULL;
141     }
142 }
143
144 static bool CACmpNetworkList(uint32_t ifiindex)
145 {
146     if (!g_netInterfaceList)
147     {
148         OIC_LOG(ERROR, TAG, "g_netInterfaceList is NULL");
149         return false;
150     }
151
152     oc_mutex_lock(g_networkMonitorContextMutex);
153
154     uint32_t list_length = u_arraylist_length(g_netInterfaceList);
155     for (uint32_t list_index = 0; list_index < list_length; list_index++)
156     {
157         CAInterface_t *currItem = (CAInterface_t *) u_arraylist_get(g_netInterfaceList,
158                                                                     list_index);
159         if (currItem->index == ifiindex)
160         {
161             oc_mutex_unlock(g_networkMonitorContextMutex);
162             return true;
163         }
164     }
165     oc_mutex_unlock(g_networkMonitorContextMutex);
166     return false;
167 }
168
169 static CAResult_t CAAddNetworkMonitorList(CAInterface_t *ifitem)
170 {
171     VERIFY_NON_NULL(g_netInterfaceList, TAG, "g_netInterfaceList is NULL");
172     VERIFY_NON_NULL(ifitem, TAG, "ifitem is NULL");
173
174     oc_mutex_lock(g_networkMonitorContextMutex);
175     bool result = u_arraylist_add(g_netInterfaceList, (void *) ifitem);
176     if (!result)
177     {
178         OIC_LOG(ERROR, TAG, "u_arraylist_add failed.");
179         oc_mutex_unlock(g_networkMonitorContextMutex);
180         return CA_STATUS_FAILED;
181     }
182     oc_mutex_unlock(g_networkMonitorContextMutex);
183     return CA_STATUS_OK;
184 }
185
186 static void CARemoveNetworkMonitorList(int ifiindex)
187 {
188     VERIFY_NON_NULL_VOID(g_netInterfaceList, TAG, "g_netInterfaceList is NULL");
189
190     oc_mutex_lock(g_networkMonitorContextMutex);
191
192     uint32_t list_length = u_arraylist_length(g_netInterfaceList);
193     for (uint32_t list_index = 0; list_index < list_length; list_index++)
194     {
195         CAInterface_t *removedifitem = (CAInterface_t *) u_arraylist_get(
196                 g_netInterfaceList, list_index);
197         if (removedifitem && ((int)removedifitem->index) == ifiindex)
198         {
199             if (u_arraylist_remove(g_netInterfaceList, list_index))
200             {
201                 OICFree(removedifitem);
202                 oc_mutex_unlock(g_networkMonitorContextMutex);
203                 return;
204             }
205             continue;
206         }
207     }
208     oc_mutex_unlock(g_networkMonitorContextMutex);
209     return;
210 }
211
212 CAResult_t CAIPStartNetworkMonitor(CAIPAdapterStateChangeCallback callback,
213                                    CATransportAdapter_t adapter)
214 {
215     CAResult_t res = CAIPInitializeNetworkMonitorList();
216     if (CA_STATUS_OK == res)
217     {
218         return CAIPSetNetworkMonitorCallback(callback, adapter);
219     }
220     return res;
221 }
222
223 CAResult_t CAIPStopNetworkMonitor(CATransportAdapter_t adapter)
224 {
225     CAIPDestroyNetworkMonitorList();
226     return CAIPUnSetNetworkMonitorCallback(adapter);
227 }
228
229 static void CAIPPassNetworkChangesToAdapter(CANetworkStatus_t status)
230 {
231     CAIPPassNetworkChangesToAdapterInternal(status, g_adapterCallbackList, CA_IP_NW_COMMON_LINUX);
232 }
233
234 CAResult_t CAIPSetNetworkMonitorCallback(CAIPAdapterStateChangeCallback callback,
235                                          CATransportAdapter_t adapter)
236 {
237     return CAIPSetNetworkMonitorCallbackInternal(callback, adapter, g_adapterCallbackList);
238 }
239
240 CAResult_t CAIPUnSetNetworkMonitorCallback(CATransportAdapter_t adapter)
241 {
242     return CAIPUnSetNetworkMonitorCallbackInternal(adapter, g_adapterCallbackList);
243 }
244
245 static CAInterface_t *CANewInterfaceItem(int index, const char *name, int family,
246                                          const char *addr, int flags)
247 {
248     CAInterface_t *ifitem = (CAInterface_t *)OICCalloc(1, sizeof (CAInterface_t));
249     if (!ifitem)
250     {
251         OIC_LOG(ERROR, TAG, "Malloc failed");
252         return NULL;
253     }
254
255     OICStrcpy(ifitem->name, sizeof (ifitem->name), name);
256     ifitem->index = index;
257     ifitem->family = family;
258     OICStrcpy(ifitem->addr, sizeof (ifitem->addr), addr);
259     ifitem->flags = flags;
260
261     return ifitem;
262 }
263
264 u_arraylist_t *CAFindInterfaceChange()
265 {
266     u_arraylist_t *iflist = NULL;
267 #ifdef __linux__
268     char buf[4096] = { 0 };
269     struct nlmsghdr *nh = NULL;
270     struct sockaddr_nl sa = { .nl_family = 0 };
271     struct iovec iov = { .iov_base = buf,
272                          .iov_len = sizeof (buf) };
273     struct msghdr msg = { .msg_name = (void *)&sa,
274                           .msg_namelen = sizeof (sa),
275                           .msg_iov = &iov,
276                           .msg_iovlen = 1 };
277
278     ssize_t len = recvmsg(caglobals.ip.netlinkFd, &msg, 0);
279
280     for (nh = (struct nlmsghdr *)buf; nh != NULL && NLMSG_OK(nh, len); nh = NLMSG_NEXT(nh, len))
281     {
282         if (nh->nlmsg_type != RTM_DELADDR && nh->nlmsg_type != RTM_NEWADDR)
283         {
284             continue;
285         }
286
287         if (RTM_DELADDR == nh->nlmsg_type)
288         {
289             struct ifaddrmsg *ifa = (struct ifaddrmsg *)NLMSG_DATA (nh);
290             int ifiIndex = ifa->ifa_index;
291             bool isFound = CACmpNetworkList(ifiIndex);
292             if (isFound)
293             {
294                 CARemoveNetworkMonitorList(ifiIndex);
295                 CAIPPassNetworkChangesToAdapter(CA_INTERFACE_DOWN);
296             }
297             continue;
298         }
299
300         // Netlink message type is RTM_NEWADDR.
301         struct ifaddrmsg *ifa = (struct ifaddrmsg *)NLMSG_DATA (nh);
302         int ifiIndex = ifa->ifa_index;
303
304         iflist = CAIPGetInterfaceInformation(ifiIndex);
305         if (!iflist)
306         {
307             OIC_LOG_V(ERROR, TAG, "get interface info failed: %s", strerror(errno));
308             return NULL;
309         }
310     }
311 #endif
312     return iflist;
313 }
314
315 u_arraylist_t *CAIPGetInterfaceInformation(int desiredIndex)
316 {
317     if (desiredIndex < 0)
318     {
319         OIC_LOG_V(ERROR, TAG, "invalid index : %d", desiredIndex);
320         return NULL;
321     }
322
323     u_arraylist_t *iflist = u_arraylist_create();
324     if (!iflist)
325     {
326         OIC_LOG_V(ERROR, TAG, "Failed to create iflist: %s", strerror(errno));
327         return NULL;
328     }
329
330     struct ifaddrs *ifp = NULL;
331     if (-1 == getifaddrs(&ifp))
332     {
333         OIC_LOG_V(ERROR, TAG, "Failed to get ifaddrs: %s", strerror(errno));
334         u_arraylist_destroy(iflist);
335         return NULL;
336     }
337
338     struct ifaddrs *ifa = NULL;
339     for (ifa = ifp; ifa; ifa = ifa->ifa_next)
340     {
341         if (!ifa->ifa_addr)
342         {
343             continue;
344         }
345         int family = ifa->ifa_addr->sa_family;
346         if ((ifa->ifa_flags & IFF_LOOPBACK) || (AF_INET != family && AF_INET6 != family))
347         {
348             continue;
349         }
350
351         int ifindex = if_nametoindex(ifa->ifa_name);
352         if (desiredIndex && (ifindex != desiredIndex))
353         {
354             continue;
355         }
356
357         int length = u_arraylist_length(iflist);
358         int already = false;
359         for (int i = length-1; i >= 0; i--)
360         {
361             CAInterface_t *ifitem = (CAInterface_t *)u_arraylist_get(iflist, i);
362
363             if (ifitem
364                 && (int)ifitem->index == ifindex
365                 && ifitem->family == (uint16_t)family)
366             {
367                 already = true;
368                 break;
369             }
370         }
371         if (already)
372         {
373             continue;
374         }
375
376         CAInterface_t *ifitem = (CAInterface_t *)OICCalloc(1, sizeof(CAInterface_t));
377         if (!ifitem)
378         {
379             OIC_LOG(ERROR, TAG, "Malloc failed");
380             goto exit;
381         }
382
383         OICStrcpy(ifitem->name, INTERFACE_NAME_MAX, ifa->ifa_name);
384         ifitem->index = ifindex;
385         ifitem->family = family;
386         ifitem->flags = ifa->ifa_flags;
387
388         if (ifitem->family == AF_INET6)
389         {
390             struct sockaddr_in6 *in6 = (struct sockaddr_in6*) ifa->ifa_addr;
391             inet_ntop(ifitem->family, (void *)&(in6->sin6_addr), ifitem->addr,
392                       sizeof(ifitem->addr));
393         }
394         else if (ifitem->family == AF_INET)
395         {
396             struct sockaddr_in *in = (struct sockaddr_in*) ifa->ifa_addr;
397             inet_ntop(ifitem->family, (void *)&(in->sin_addr), ifitem->addr,
398                       sizeof(ifitem->addr));
399         }
400
401         bool result = u_arraylist_add(iflist, ifitem);
402         if (!result)
403         {
404             OIC_LOG(ERROR, TAG, "u_arraylist_add failed.");
405             goto exit;
406         }
407
408         bool isFound = CACmpNetworkList(ifitem->index);
409         if (!isFound)
410         {
411             CAInterface_t *newifitem = CANewInterfaceItem(ifitem->index, ifitem->name, ifitem->family,
412                                                           ifitem->addr, ifitem->flags);
413             CAResult_t ret = CAAddNetworkMonitorList(newifitem);
414             if (CA_STATUS_OK != ret)
415             {
416                 OICFree(newifitem);
417                 goto exit;
418             }
419             CAIPPassNetworkChangesToAdapter(CA_INTERFACE_UP);
420             OIC_LOG_V(DEBUG, TAG, "Added interface: %s (%d)", ifitem->name, ifitem->family);
421         }
422     }
423 #ifndef __TIZENRT__
424     freeifaddrs(ifp);
425 #endif
426     return iflist;
427
428 exit:
429 #ifndef __TIZENRT__
430     freeifaddrs(ifp);
431 #endif
432     u_arraylist_destroy(iflist);
433     return NULL;
434 }