f6ebf6b5d726a7f8ce27f198af8ac04845a6d688
[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     jclass cls_Context = (*env)->FindClass(env, "android/content/Context");
332     if (!cls_Context)
333     {
334         OIC_LOG(ERROR, TAG, "Could not get context object class");
335         return CA_STATUS_FAILED;
336     }
337
338     jmethodID mid_getApplicationContext = (*env)->GetMethodID(env, cls_Context,
339                                                                 "getApplicationContext",
340                                                                 "()Landroid/content/Context;");
341     if (!mid_getApplicationContext)
342     {
343         OIC_LOG(ERROR, TAG, "Could not get getApplicationContext method");
344         return CA_STATUS_FAILED;
345     }
346
347     jobject jApplicationContext = (*env)->CallObjectMethod(env, context,
348                                                            mid_getApplicationContext);
349     if (!jApplicationContext)
350     {
351         OIC_LOG(ERROR, TAG, "Could not get application context");
352         return CA_STATUS_FAILED;
353     }
354
355     jclass cls_CaIpInterface = (*env)->FindClass(env, "org/iotivity/ca/CaIpInterface");
356     if (!cls_CaIpInterface)
357     {
358         OIC_LOG(ERROR, TAG, "Could not get CaIpInterface class");
359         return CA_STATUS_FAILED;
360     }
361
362     jmethodID mid_CaIpInterface_ctor = (*env)->GetMethodID(env, cls_CaIpInterface, "<init>",
363                                                                    "(Landroid/content/Context;)V");
364     if (!mid_CaIpInterface_ctor)
365     {
366         OIC_LOG(ERROR, TAG, "Could not get CaIpInterface constructor method");
367         return CA_STATUS_FAILED;
368     }
369
370     (*env)->NewObject(env, cls_CaIpInterface, mid_CaIpInterface_ctor, jApplicationContext);
371     OIC_LOG(DEBUG, TAG, "Create CaIpInterface instance, success");
372
373     OIC_LOG(DEBUG, TAG, "CAIPJniInit_OUT");
374     return CA_STATUS_OK;
375 }
376
377 static CAResult_t CAIPDestroyJniInterface()
378 {
379     OIC_LOG(DEBUG, TAG, "CAIPDestroyJniInterface");
380
381     JavaVM *jvm = CANativeJNIGetJavaVM();
382     if (!jvm)
383     {
384         OIC_LOG(ERROR, TAG, "Could not get JavaVM pointer");
385         return CA_STATUS_FAILED;
386     }
387
388     bool isAttached = false;
389     JNIEnv* env;
390     jint res = (*jvm)->GetEnv(jvm, (void**) &env, JNI_VERSION_1_6);
391     if (JNI_OK != res)
392     {
393         OIC_LOG(INFO, TAG, "Could not get JNIEnv pointer");
394         res = (*jvm)->AttachCurrentThread(jvm, &env, NULL);
395
396         if (JNI_OK != res)
397         {
398             OIC_LOG(ERROR, TAG, "AttachCurrentThread has failed");
399             return CA_STATUS_FAILED;
400         }
401         isAttached = true;
402     }
403
404     jclass jni_IpInterface = (*env)->FindClass(env, "org/iotivity/ca/CaIpInterface");
405     if (!jni_IpInterface)
406     {
407         OIC_LOG(ERROR, TAG, "Could not get CaIpInterface class");
408         goto error_exit;
409     }
410
411     jmethodID jni_InterfaceDestroyMethod = (*env)->GetStaticMethodID(env, jni_IpInterface,
412                                                                      "destroyIpInterface",
413                                                                      "()V");
414     if (!jni_InterfaceDestroyMethod)
415     {
416         OIC_LOG(ERROR, TAG, "Could not get CaIpInterface destroy method");
417         goto error_exit;
418     }
419
420     (*env)->CallStaticVoidMethod(env, jni_IpInterface, jni_InterfaceDestroyMethod);
421
422     if ((*env)->ExceptionCheck(env))
423     {
424         OIC_LOG(ERROR, TAG, "destroyIpInterface has failed");
425         (*env)->ExceptionDescribe(env);
426         (*env)->ExceptionClear(env);
427         goto error_exit;
428     }
429
430     OIC_LOG(DEBUG, TAG, "Destroy instance for CaIpInterface");
431
432     if (isAttached)
433     {
434         (*jvm)->DetachCurrentThread(jvm);
435     }
436
437     return CA_STATUS_OK;
438
439 error_exit:
440
441     if (isAttached)
442     {
443         (*jvm)->DetachCurrentThread(jvm);
444     }
445
446     return CA_STATUS_FAILED;
447 }
448
449 JNIEXPORT void JNICALL
450 Java_org_iotivity_ca_CaIpInterface_caIpStateEnabled(JNIEnv *env, jclass class)
451 {
452     (void)env;
453     (void)class;
454
455     OIC_LOG(DEBUG, TAG, "Wifi is in Activated State");
456     g_networkChangeCallback(CA_ADAPTER_IP, CA_INTERFACE_UP);
457 }
458
459 JNIEXPORT void JNICALL
460 Java_org_iotivity_ca_CaIpInterface_caIpStateDisabled(JNIEnv *env, jclass class)
461 {
462     (void)env;
463     (void)class;
464
465     OIC_LOG(DEBUG, TAG, "Wifi is in Deactivated State");
466     g_networkChangeCallback(CA_ADAPTER_IP, CA_INTERFACE_DOWN);
467 }