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