merge master code to build iotivity
[platform/upstream/iotivity.git] / resource / csdk / connectivity / src / ip_adapter / android / 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 <sys/types.h>
24 #include <ifaddrs.h>
25 #include <sys/socket.h>
26 #include <netdb.h>
27 #include <string.h>
28 #include <errno.h>
29 #include <unistd.h>
30
31 #include <arpa/inet.h>
32 #include <linux/if.h>
33
34 #include "caadapterutils.h"
35 #include "logger.h"
36 #include "oic_malloc.h"
37 #include "oic_string.h"
38 #include "org_iotivity_ca_CaIpInterface.h"
39
40 #define TAG "IP_MONITOR"
41
42 static CAInterface_t *CANewInterfaceItem(int index, const char *name, int family,
43                                          uint32_t addr, int flags);
44
45 static CAResult_t CAAddInterfaceItem(u_arraylist_t *iflist, int index,
46                             const char *name, int family, uint32_t addr, int flags);
47
48 CAResult_t CAIPJniInit();
49
50 #define MAX_INTERFACE_INFO_LENGTH 1024 // allows 32 interfaces from SIOCGIFCONF
51
52 CAResult_t CAIPStartNetworkMonitor()
53 {
54     return CAIPJniInit();
55 }
56
57 CAResult_t CAIPStopNetworkMonitor()
58 {
59     return CA_STATUS_OK;
60 }
61
62 int CAGetPollingInterval(int interval)
63 {
64     return interval;
65 }
66
67 CAInterface_t *CAFindInterfaceChange()
68 {
69     char buf[MAX_INTERFACE_INFO_LENGTH] = { 0 };
70     struct ifconf ifc  = { .ifc_len = MAX_INTERFACE_INFO_LENGTH, .ifc_buf = buf };
71
72     int s = caglobals.ip.u6.fd != -1 ? caglobals.ip.u6.fd : caglobals.ip.u4.fd;
73     if (ioctl(s, SIOCGIFCONF, &ifc) < 0)
74     {
75         OIC_LOG_V(ERROR, TAG, "SIOCGIFCONF failed: %s", strerror(errno));
76         return NULL;
77     }
78
79     CAInterface_t *foundNewInterface = NULL;
80
81     struct ifreq* ifr = ifc.ifc_req;
82     size_t interfaces = ifc.ifc_len / sizeof (ifc.ifc_req[0]);
83     size_t ifreqsize = ifc.ifc_len;
84
85     CAIfItem_t *previous = (CAIfItem_t *)OICMalloc(ifreqsize);
86     if (!previous)
87     {
88         OIC_LOG(ERROR, TAG, "OICMalloc failed");
89         return NULL;
90     }
91
92     memcpy(previous, caglobals.ip.nm.ifItems, ifreqsize);
93     size_t numprevious = caglobals.ip.nm.numIfItems;
94
95     if (ifreqsize > caglobals.ip.nm.sizeIfItems)
96     {
97
98         CAIfItem_t *items = (CAIfItem_t *)OICRealloc(caglobals.ip.nm.ifItems, ifreqsize);
99         if (!items)
100         {
101             OIC_LOG(ERROR, TAG, "OICRealloc failed");
102             OICFree(previous);
103             return NULL;
104         }
105         caglobals.ip.nm.ifItems = items;
106         caglobals.ip.nm.sizeIfItems = ifreqsize;
107     }
108
109     caglobals.ip.nm.numIfItems = 0;
110     for (size_t i = 0; i < interfaces; i++)
111     {
112         struct ifreq* item = &ifr[i];
113         char *name = item->ifr_name;
114         struct sockaddr_in *sa4 = (struct sockaddr_in *)&item->ifr_addr;
115         uint32_t ipv4addr = sa4->sin_addr.s_addr;
116
117         if (ioctl(s, SIOCGIFFLAGS, item) < 0)
118         {
119             OIC_LOG_V(ERROR, TAG, "SIOCGIFFLAGS failed: %s", strerror(errno));
120             continue;
121         }
122         int16_t flags = item->ifr_flags;
123         if ((flags & IFF_LOOPBACK) || !(flags & IFF_RUNNING))
124         {
125             continue;
126         }
127         if (ioctl(s, SIOCGIFINDEX, item) < 0)
128         {
129             OIC_LOG_V(ERROR, TAG, "SIOCGIFINDEX failed: %s", strerror(errno));
130             continue;
131         }
132
133         int ifIndex = item->ifr_ifindex;
134         caglobals.ip.nm.ifItems[i].ifIndex = ifIndex;  // refill interface list
135         caglobals.ip.nm.numIfItems++;
136
137         if (foundNewInterface)
138         {
139             continue;   // continue updating interface list
140         }
141
142         // see if this interface didn't previously exist
143         bool found = false;
144         for (size_t j = 0; j < numprevious; j++)
145         {
146             if (ifIndex == previous[j].ifIndex)
147             {
148                 found = true;
149                 break;
150             }
151         }
152         if (found)
153         {
154             OIC_LOG_V(INFO, TAG, "Interface found: %s", name);
155             continue;
156         }
157
158         foundNewInterface = CANewInterfaceItem(ifIndex, name, AF_INET, ipv4addr, flags);
159     }
160
161     OICFree(previous);
162     return foundNewInterface;
163 }
164
165 u_arraylist_t *CAIPGetInterfaceInformation(int desiredIndex)
166 {
167     u_arraylist_t *iflist = u_arraylist_create();
168     if (!iflist)
169     {
170         OIC_LOG_V(ERROR, TAG, "Failed to create iflist: %s", strerror(errno));
171         return NULL;
172     }
173
174     char buf[MAX_INTERFACE_INFO_LENGTH] = { 0 };
175     struct ifconf ifc = { .ifc_len = MAX_INTERFACE_INFO_LENGTH, .ifc_buf = buf };
176
177     int s = caglobals.ip.u6.fd != -1 ? caglobals.ip.u6.fd : caglobals.ip.u4.fd;
178     if (ioctl(s, SIOCGIFCONF, &ifc) < 0)
179     {
180         OIC_LOG_V(ERROR, TAG, "SIOCGIFCONF failed: %s", strerror(errno));
181         u_arraylist_destroy(iflist);
182         return NULL;
183     }
184
185     struct ifreq* ifr = ifc.ifc_req;
186     size_t interfaces = ifc.ifc_len / sizeof (ifc.ifc_req[0]);
187     size_t ifreqsize = ifc.ifc_len;
188
189     if (ifreqsize > caglobals.ip.nm.sizeIfItems)
190     {
191         CAIfItem_t *items = (CAIfItem_t *)OICRealloc(caglobals.ip.nm.ifItems, ifreqsize);
192         if (!items)
193         {
194             OIC_LOG(ERROR, TAG, "OICRealloc failed");
195             goto exit;
196         }
197         caglobals.ip.nm.ifItems = items;
198         caglobals.ip.nm.sizeIfItems = ifreqsize;
199     }
200
201     caglobals.ip.nm.numIfItems = 0;
202     for (size_t i = 0; i < interfaces; i++)
203     {
204         CAResult_t result = CA_STATUS_OK;
205         struct ifreq* item = &ifr[i];
206         char *name = item->ifr_name;
207         struct sockaddr_in *sa4 = (struct sockaddr_in *)&item->ifr_addr;
208         uint32_t ipv4addr = sa4->sin_addr.s_addr;
209
210         if (ioctl(s, SIOCGIFFLAGS, item) < 0)
211         {
212             OIC_LOG_V(ERROR, TAG, "SIOCGIFFLAGS failed: %s", strerror(errno));
213             continue;
214         }
215         int16_t flags = item->ifr_flags;
216         if ((flags & IFF_LOOPBACK) || !(flags & IFF_RUNNING))
217         {
218             continue;
219         }
220         if (ioctl(s, SIOCGIFINDEX, item) < 0)
221         {
222             OIC_LOG_V(ERROR, TAG, "SIOCGIFINDEX failed: %s", strerror(errno));
223             continue;
224         }
225
226         int ifindex = item->ifr_ifindex;
227         caglobals.ip.nm.ifItems[i].ifIndex = ifindex;
228         caglobals.ip.nm.numIfItems++;
229
230         if (desiredIndex && (ifindex != desiredIndex))
231         {
232             continue;
233         }
234
235         // Add IPv4 interface
236         result = CAAddInterfaceItem(iflist, ifindex, name, AF_INET, ipv4addr, flags);
237         if (CA_STATUS_OK != result)
238         {
239             goto exit;
240         }
241
242         // Add IPv6 interface
243         result = CAAddInterfaceItem(iflist, ifindex, name, AF_INET6, ipv4addr, flags);
244         if (CA_STATUS_OK != result)
245         {
246             goto exit;
247         }
248     }
249     return iflist;
250
251 exit:
252     u_arraylist_destroy(iflist);
253     return NULL;
254 }
255
256 static CAResult_t CAAddInterfaceItem(u_arraylist_t *iflist, int index,
257                             const char *name, int family, uint32_t addr, int flags)
258 {
259     CAInterface_t *ifitem = CANewInterfaceItem(index, name, family, addr, flags);
260     if (!ifitem)
261     {
262         return CA_STATUS_FAILED;
263     }
264     bool result = u_arraylist_add(iflist, ifitem);
265     if (!result)
266     {
267         OIC_LOG(ERROR, TAG, "u_arraylist_add failed.");
268         OICFree(ifitem);
269         return CA_STATUS_FAILED;
270     }
271
272     return CA_STATUS_OK;
273 }
274
275 static CAInterface_t *CANewInterfaceItem(int index, const char *name, int family,
276                                          uint32_t addr, int flags)
277 {
278     CAInterface_t *ifitem = (CAInterface_t *)OICCalloc(1, sizeof (CAInterface_t));
279     if (!ifitem)
280     {
281         OIC_LOG(ERROR, TAG, "Malloc failed");
282         return NULL;
283     }
284
285     OICStrcpy(ifitem->name, sizeof (ifitem->name), name);
286     ifitem->index = index;
287     ifitem->family = family;
288     ifitem->ipv4addr = addr;
289     ifitem->flags = flags;
290
291     return ifitem;
292 }
293
294 CAResult_t CAIPJniInit()
295 {
296     OIC_LOG(DEBUG, TAG, "CAIPJniInit_IN");
297
298     JavaVM *jvm = CANativeJNIGetJavaVM();
299     if (!jvm)
300     {
301         OIC_LOG(ERROR, TAG, "Could not get JavaVM pointer");
302         return CA_STATUS_FAILED;
303     }
304
305     jobject context = CANativeJNIGetContext();
306     if (!context)
307     {
308         OIC_LOG(ERROR, TAG, "unable to get application context");
309         return CA_STATUS_FAILED;
310     }
311
312     JNIEnv* env;
313     if ((*jvm)->GetEnv(jvm, (void**) &env, JNI_VERSION_1_6) != JNI_OK)
314     {
315         OIC_LOG(ERROR, TAG, "Could not get JNIEnv pointer");
316         return CA_STATUS_FAILED;
317     }
318
319     jclass cls_Context = (*env)->FindClass(env, "android/content/Context");
320     if (!cls_Context)
321     {
322         OIC_LOG(ERROR, TAG, "Could not get context object class");
323         return CA_STATUS_FAILED;
324     }
325
326     jmethodID mid_getApplicationContext = (*env)->GetMethodID(env, cls_Context,
327                                                                 "getApplicationContext",
328                                                                 "()Landroid/content/Context;");
329     if (!mid_getApplicationContext)
330     {
331         OIC_LOG(ERROR, TAG, "Could not get getApplicationContext method");
332         return CA_STATUS_FAILED;
333     }
334
335     jobject jApplicationContext = (*env)->CallObjectMethod(env, context,
336                                                            mid_getApplicationContext);
337     if (!jApplicationContext)
338     {
339         OIC_LOG(ERROR, TAG, "Could not get application context");
340         return CA_STATUS_FAILED;
341     }
342
343     jclass cls_CaIpInterface = (*env)->FindClass(env, "org/iotivity/ca/CaIpInterface");
344     if (!cls_CaIpInterface)
345     {
346         OIC_LOG(ERROR, TAG, "Could not get CaIpInterface class");
347         return CA_STATUS_FAILED;
348     }
349
350     jmethodID mid_CaIpInterface_ctor = (*env)->GetMethodID(env, cls_CaIpInterface, "<init>",
351                                                                    "(Landroid/content/Context;)V");
352     if (!mid_CaIpInterface_ctor)
353     {
354         OIC_LOG(ERROR, TAG, "Could not get CaIpInterface constructor method");
355         return CA_STATUS_FAILED;
356     }
357
358     (*env)->NewObject(env, cls_CaIpInterface, mid_CaIpInterface_ctor, jApplicationContext);
359     OIC_LOG(DEBUG, TAG, "Create CaIpInterface instance, success");
360
361     OIC_LOG(DEBUG, TAG, "CAIPJniInit_OUT");
362     return CA_STATUS_OK;
363 }
364
365 JNIEXPORT void JNICALL
366 Java_org_iotivity_ca_CaIpInterface_caIpStateEnabled(JNIEnv *env, jclass class)
367 {
368     (void)env;
369     (void)class;
370     OIC_LOG(DEBUG, TAG, "caIpStateEnabled");
371
372     CAWakeUpForChange();
373 }
374
375 JNIEXPORT void JNICALL
376 Java_org_iotivity_ca_CaIpInterface_caIpStateDisabled(JNIEnv *env, jclass class)
377 {
378     (void)env;
379     (void)class;
380     OIC_LOG(DEBUG, TAG, "caIpStateDisabled");
381
382     CAIPGetInterfaceInformation(0);
383 }