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