Merge branch 'tizen' into tizen_5.5
[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 #include <coap/utlist.h>
33 #include <linux/netlink.h>
34 #include <linux/rtnetlink.h>
35 #include <net/if.h>
36
37 #include "caadapterutils.h"
38 #include "caipnwmonitor.h"
39 #include "caipnwmonitor_common.h"
40 #include "logger.h"
41 #include "oic_malloc.h"
42 #include "oic_string.h"
43 #include "org_iotivity_ca_CaIpInterface.h"
44 #include "caifaddrs.h"
45
46 #define TAG "OIC_CA_IP_MONITOR"
47 #define NETLINK_MESSAGE_LENGTH  (4096)
48 #define IFC_LABEL_LOOP          "lo"
49 #define IFC_ADDR_LOOP_IPV4      "127.0.0.1"
50 #define IFC_ADDR_LOOP_IPV6      "::1"
51 /**
52  * Used to storing adapter changes callback interface.
53  */
54 static struct CAIPCBData_t *g_adapterCallbackList = NULL;
55
56 /**
57  * Used to indicate whether WiFi is enabled or not during init.
58  */
59 static bool g_wifiConnectionDuringInit = false;
60
61 /**
62  * WiFi Interface's Name.
63  */
64 static const char *g_wifiInterfaceName = NULL;
65
66 /**
67  * Create new interface item to add in activated interface list.
68  * @param[in]  index    Network interface index number.
69  * @param[in]  name     Network interface name.
70  * @param[in]  family   Network interface family type.
71  * @param[in]  addr     New interface address.
72  * @param[in]  flags    The active flag word of a device.
73  * @return  CAInterface_t objects.
74  */
75 static CAInterface_t *CANewInterfaceItem(int index, const char *name, int family,
76                                          const char *addr, int flags);
77
78 /**
79  * Add created new interface item activated interface list.
80  * @param[in]  iflist   Network interface array list.
81  * @param[in]  index    Network interface index number.
82  * @param[in]  name     Network interface name.
83  * @param[in]  family   Network interface family type.
84  * @param[in]  addr     New interface address.
85  * @param[in]  flags    The active flag word of a device.
86  * @return  ::CA_STATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
87  */
88 static CAResult_t CAAddInterfaceItem(u_arraylist_t *iflist, int index,
89                                      const char *name, int family, const char *addr, int flags);
90
91 /**
92  * Initialize JNI interface.
93  * @return  ::CA_STATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
94  */
95 CAResult_t CAIPJniInit();
96
97 /**
98  * Destroy JNI interface.
99  * @return  ::CA_STATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
100  */
101 static CAResult_t CAIPDestroyJniInterface();
102
103 #define MAX_INTERFACE_INFO_LENGTH 1024 // allows 32 interfaces from SIOCGIFCONF
104
105 CAResult_t CAIPStartNetworkMonitor(CAIPAdapterStateChangeCallback callback,
106                                    CATransportAdapter_t adapter)
107 {
108     CAResult_t res = CAIPJniInit();
109     if (CA_STATUS_OK != res)
110     {
111         OIC_LOG(ERROR, TAG, "failed to initialize ip jni interface");
112         return res;
113     }
114
115     return CAIPSetNetworkMonitorCallback(callback, adapter);
116 }
117
118 CAResult_t CAIPStopNetworkMonitor(CATransportAdapter_t adapter)
119 {
120     CAIPUnSetNetworkMonitorCallback(adapter);
121
122     // if there is no callback to pass the changed status, stop monitoring.
123     if (!g_adapterCallbackList)
124     {
125         return CAIPDestroyJniInterface();
126     }
127
128     return CA_STATUS_OK;
129 }
130
131 static void CAIPPassNetworkChangesToAdapter(CANetworkStatus_t status)
132 {
133     CAIPPassNetworkChangesToAdapterInternal(status, g_adapterCallbackList, CA_IP_NW_COMMON_ANDROID);
134 }
135
136 CAResult_t CAIPSetNetworkMonitorCallback(CAIPAdapterStateChangeCallback callback,
137                                          CATransportAdapter_t adapter)
138 {
139     return CAIPSetNetworkMonitorCallbackInternal(callback, adapter, g_adapterCallbackList);
140 }
141
142 CAResult_t CAIPUnSetNetworkMonitorCallback(CATransportAdapter_t adapter)
143 {
144     return CAIPUnSetNetworkMonitorCallbackInternal(adapter, g_adapterCallbackList);
145 }
146
147 u_arraylist_t *CAFindInterfaceChange()
148 {
149     // release netlink event
150     char buf[NETLINK_MESSAGE_LENGTH] = { 0 };
151     struct sockaddr_nl sa = { 0 };
152     struct iovec iov = { .iov_base = buf,
153                          .iov_len = sizeof (buf) };
154     struct msghdr msg = { .msg_name = (void *)&sa,
155                           .msg_namelen = sizeof (sa),
156                           .msg_iov = &iov,
157                           .msg_iovlen = 1 };
158
159     ssize_t len = recvmsg(caglobals.ip.netlinkFd, &msg, 0);
160     return NULL;
161 }
162
163 /**
164  * Used to send netlink query to kernel and recv response from kernel.
165  *
166  * @param[in]   idx       desired network interface index, 0 means all interfaces.
167  * @param[out]  iflist    linked list.
168  *
169  */
170 static bool CAParsingNetorkInfo(int idx, u_arraylist_t *iflist)
171 {
172     if ((idx < 0) || (iflist == NULL))
173     {
174         return false;
175     }
176
177     struct ifaddrs *ifp = NULL;
178     CAResult_t ret = CAGetIfaddrsUsingNetlink(&ifp);
179     if (CA_STATUS_OK != ret)
180     {
181         OIC_LOG_V(ERROR, TAG, "Failed to get ifaddrs err code is: %d", ret);
182         return false;
183     }
184
185     struct ifaddrs *ifa = NULL;
186     for (ifa = ifp; ifa; ifa = ifa->ifa_next)
187     {
188         if (!ifa->ifa_addr)
189         {
190             continue;
191         }
192
193         int family = ifa->ifa_addr->sa_family;
194         if ((ifa->ifa_flags & IFF_LOOPBACK) || (AF_INET != family && AF_INET6 != family))
195         {
196             continue;
197         }
198
199         int ifindex = if_nametoindex(ifa->ifa_name);
200         if (idx && (ifindex != idx))
201         {
202             continue;
203         }
204
205         // Ignoring all non WiFi interfaces.
206         if (g_wifiInterfaceName != NULL && (strlen(g_wifiInterfaceName) > 0) &&
207             (strcmp(ifa->ifa_name, g_wifiInterfaceName) != 0))
208         {
209             OIC_LOG_V(DEBUG, TAG, "Ignoring Non-WiFi interface: %s(%d)", ifa->ifa_name, ifindex);
210             continue;
211         }
212
213         char ipaddr[MAX_ADDR_STR_SIZE_CA] = {0};
214         if (family == AF_INET6)
215         {
216             struct sockaddr_in6 *in6 = (struct sockaddr_in6*) ifa->ifa_addr;
217             inet_ntop(family, (void *)&(in6->sin6_addr), ipaddr, sizeof(ipaddr));
218         }
219         else if (family == AF_INET)
220         {
221             struct sockaddr_in *in = (struct sockaddr_in*) ifa->ifa_addr;
222             inet_ntop(family, (void *)&(in->sin_addr), ipaddr, sizeof(ipaddr));
223         }
224
225         if ((strcmp(ipaddr, IFC_ADDR_LOOP_IPV4) == 0) ||
226             (strcmp(ipaddr, IFC_ADDR_LOOP_IPV6) == 0) ||
227             (strcmp(ifa->ifa_name, IFC_LABEL_LOOP) == 0))
228         {
229             OIC_LOG(DEBUG, TAG, "LOOPBACK continue!!!");
230             continue;
231         }
232
233         CAResult_t result = CAAddInterfaceItem(iflist, ifindex,
234                                                ifa->ifa_name, family,
235                                                ipaddr, ifa->ifa_flags);
236         if (CA_STATUS_OK != result)
237         {
238             OIC_LOG(ERROR, TAG, "CAAddInterfaceItem fail");
239             goto exit;
240         }
241     }
242     CAFreeIfAddrs(ifp);
243     return true;
244
245 exit:
246     CAFreeIfAddrs(ifp);
247     return false;
248 }
249
250 u_arraylist_t *CAIPGetInterfaceInformation(int desiredIndex)
251 {
252     u_arraylist_t *iflist = u_arraylist_create();
253     if (!iflist)
254     {
255         OIC_LOG_V(ERROR, TAG, "Failed to create iflist: %s", strerror(errno));
256         return NULL;
257     }
258
259     if (!CAParsingNetorkInfo(desiredIndex, iflist))
260     {
261         goto exit;
262     }
263
264     return iflist;
265
266 exit:
267     u_arraylist_destroy(iflist);
268     return NULL;
269 }
270
271 static CAResult_t CAAddInterfaceItem(u_arraylist_t *iflist, int index,
272                                      const char *name, int family, const char *addr, int flags)
273 {
274     CAInterface_t *ifitem = CANewInterfaceItem(index, name, family, addr, flags);
275     if (!ifitem)
276     {
277         return CA_STATUS_FAILED;
278     }
279     bool result = u_arraylist_add(iflist, ifitem);
280     if (!result)
281     {
282         OIC_LOG(ERROR, TAG, "u_arraylist_add failed.");
283         OICFree(ifitem);
284         return CA_STATUS_FAILED;
285     }
286
287     return CA_STATUS_OK;
288 }
289
290 static CAInterface_t *CANewInterfaceItem(int index, const char *name, int family,
291                                          const char *addr, int flags)
292 {
293     CAInterface_t *ifitem = (CAInterface_t *)OICCalloc(1, sizeof (CAInterface_t));
294     if (!ifitem)
295     {
296         OIC_LOG(ERROR, TAG, "Malloc failed in CANewInterfaceItem");
297         return NULL;
298     }
299
300     OICStrcpy(ifitem->name, sizeof (ifitem->name), name);
301     ifitem->index = index;
302     ifitem->family = family;
303     OICStrcpy(ifitem->addr, sizeof (ifitem->addr), addr);
304     ifitem->flags = flags;
305
306     return ifitem;
307 }
308
309 CAResult_t CAIPJniInit()
310 {
311     OIC_LOG(DEBUG, TAG, "CAIPJniInit_IN");
312
313     JavaVM *jvm = CANativeJNIGetJavaVM();
314     if (!jvm)
315     {
316         OIC_LOG(ERROR, TAG, "Could not get JavaVM pointer");
317         return CA_STATUS_FAILED;
318     }
319
320     jobject context = CANativeJNIGetContext();
321     if (!context)
322     {
323         OIC_LOG(ERROR, TAG, "unable to get application context");
324         return CA_STATUS_FAILED;
325     }
326
327     JNIEnv* env = NULL;
328     if ((*jvm)->GetEnv(jvm, (void**) &env, JNI_VERSION_1_6) != JNI_OK)
329     {
330         OIC_LOG(ERROR, TAG, "Could not get JNIEnv pointer");
331         return CA_STATUS_FAILED;
332     }
333
334     jmethodID mid_getApplicationContext = CAGetJNIMethodID(env, "android/content/Context",
335                                                            "getApplicationContext",
336                                                            "()Landroid/content/Context;");
337
338     if (!mid_getApplicationContext)
339     {
340         OIC_LOG(ERROR, TAG, "Could not get getApplicationContext method");
341         return CA_STATUS_FAILED;
342     }
343
344     jobject jApplicationContext = (*env)->CallObjectMethod(env, context,
345                                                            mid_getApplicationContext);
346     if (!jApplicationContext)
347     {
348         OIC_LOG(ERROR, TAG, "Could not get application context");
349         return CA_STATUS_FAILED;
350     }
351
352     jclass cls_CaIpInterface = (*env)->FindClass(env, "org/iotivity/ca/CaIpInterface");
353     if (!cls_CaIpInterface)
354     {
355         OIC_LOG(ERROR, TAG, "Could not get CaIpInterface class");
356         return CA_STATUS_FAILED;
357     }
358
359     jmethodID mid_CaIpInterface_ctor = (*env)->GetMethodID(env, cls_CaIpInterface, "<init>",
360                                                                    "(Landroid/content/Context;)V");
361     if (!mid_CaIpInterface_ctor)
362     {
363         OIC_LOG(ERROR, TAG, "Could not get CaIpInterface constructor method");
364         return CA_STATUS_FAILED;
365     }
366
367     jobject jCaIpInterface = (*env)->NewObject(env, cls_CaIpInterface, mid_CaIpInterface_ctor, jApplicationContext);
368     if (!jCaIpInterface)
369     {
370         OIC_LOG(ERROR, TAG, "Could not create an instance of CaIpInterface");
371         return CA_STATUS_FAILED;
372     }
373
374     // Get WiFi Connection status.
375     jmethodID mid_hasWifiConnection = (*env)->GetMethodID(env, cls_CaIpInterface, "hasWifiConnection", "()Z");
376     if (!mid_hasWifiConnection)
377     {
378         OIC_LOG(ERROR, TAG, "Could not get hasWifiConnection method");
379         return CA_STATUS_FAILED;
380     }
381
382     g_wifiConnectionDuringInit = (*env)->CallBooleanMethod(env, jCaIpInterface, mid_hasWifiConnection);
383
384     // Get WiFi Interface's name.
385     jmethodID mid_getWiFiInterfaceName = (*env)->GetMethodID(env, cls_CaIpInterface,
386                                                                         "getWiFiInterfaceName", "()Ljava/lang/String;");
387     if (!mid_getWiFiInterfaceName)
388     {
389         OIC_LOG(ERROR, TAG, "Could not get getWiFiInterfaceName method");
390         return CA_STATUS_FAILED;
391     }
392
393     jstring jWifiInterfaceName = (*env)->CallObjectMethod(env, jCaIpInterface, mid_getWiFiInterfaceName);
394     const char *wifiInterfaceNameLocal = (*env)->GetStringUTFChars(env, jWifiInterfaceName, NULL);
395     g_wifiInterfaceName = OICStrdup(wifiInterfaceNameLocal);
396     if (!g_wifiInterfaceName)
397     {
398         OIC_LOG(ERROR, TAG, "Failed to duplicate the Wifi Interface name.");
399     }
400
401     (*env)->ReleaseStringUTFChars(env, jWifiInterfaceName, wifiInterfaceNameLocal);
402
403     OIC_LOG_V(DEBUG, TAG, "WiFi Interface Name: %s, WiFi Connection State: %d", g_wifiInterfaceName,
404         g_wifiConnectionDuringInit);
405
406     OIC_LOG(DEBUG, TAG, "CAIPJniInit_OUT");
407     return CA_STATUS_OK;
408 }
409
410 static CAResult_t CAIPDestroyJniInterface()
411 {
412     OIC_LOG(DEBUG, TAG, "CAIPDestroyJniInterface");
413
414     JavaVM *jvm = CANativeJNIGetJavaVM();
415     if (!jvm)
416     {
417         OIC_LOG(ERROR, TAG, "Could not get JavaVM pointer");
418         return CA_STATUS_FAILED;
419     }
420
421     bool isAttached = false;
422     JNIEnv* env = NULL;
423     jint res = (*jvm)->GetEnv(jvm, (void**) &env, JNI_VERSION_1_6);
424     if (JNI_OK != res)
425     {
426         OIC_LOG(INFO, TAG, "Could not get JNIEnv pointer");
427         res = (*jvm)->AttachCurrentThread(jvm, &env, NULL);
428
429         if (JNI_OK != res)
430         {
431             OIC_LOG(ERROR, TAG, "AttachCurrentThread has failed");
432             return CA_STATUS_FAILED;
433         }
434         isAttached = true;
435     }
436
437     CACheckJNIException(env);
438
439     jclass jni_IpInterface = (*env)->FindClass(env, "org/iotivity/ca/CaIpInterface");
440     if (!jni_IpInterface)
441     {
442         OIC_LOG(ERROR, TAG, "Could not get CaIpInterface class");
443         goto error_exit;
444     }
445
446     jmethodID jni_InterfaceDestroyMethod = (*env)->GetStaticMethodID(env, jni_IpInterface,
447                                                                      "destroyIpInterface",
448                                                                      "()V");
449     if (!jni_InterfaceDestroyMethod)
450     {
451         OIC_LOG(ERROR, TAG, "Could not get CaIpInterface destroy method");
452         goto error_exit;
453     }
454
455     (*env)->CallStaticVoidMethod(env, jni_IpInterface, jni_InterfaceDestroyMethod);
456
457     if (CACheckJNIException(env))
458     {
459         OIC_LOG(ERROR, TAG, "destroyIpInterface has failed");
460         goto error_exit;
461     }
462
463     OIC_LOG(DEBUG, TAG, "Destroy instance for CaIpInterface");
464
465     if (g_wifiInterfaceName)
466     {
467         OICFree(g_wifiInterfaceName);
468         g_wifiInterfaceName = NULL;
469     }
470
471     if (isAttached)
472     {
473         (*jvm)->DetachCurrentThread(jvm);
474     }
475
476     return CA_STATUS_OK;
477
478 error_exit:
479
480     if (isAttached)
481     {
482         (*jvm)->DetachCurrentThread(jvm);
483     }
484
485     return CA_STATUS_FAILED;
486 }
487
488 bool isWifiConnectedDuringInit()
489 {
490     return g_wifiConnectionDuringInit;
491 }
492
493 const char *getWifiInterfaceName()
494 {
495     return g_wifiInterfaceName;
496 }
497
498 JNIEXPORT void JNICALL
499 Java_org_iotivity_ca_CaIpInterface_caIpStateEnabled(JNIEnv *env, jclass class,
500     jboolean wifi)
501 {
502     (void)env;
503     (void)class;
504
505     CAIPPassNetworkChangesToAdapter(CA_INTERFACE_UP);
506
507     if(!wifi)
508     {
509         return;
510     }
511
512     OIC_LOG(DEBUG, TAG, "Wifi is in Activated State");
513
514     // Closing sockets for safety reasons to handle missed out WiFi state disabled events.
515     CloseMulticastSocket();
516
517     // Creating sockets.
518     CreateMulticastSocket();
519
520     // Apply network interface changes.
521     u_arraylist_t *iflist = CAIPGetInterfaceInformation(0);
522     if (!iflist)
523     {
524         OIC_LOG_V(ERROR, TAG, "get interface info failed: %s", strerror(errno));
525         return;
526     }
527
528     uint32_t listLength = u_arraylist_length(iflist);
529     for (uint32_t i = 0; i < listLength; i++)
530     {
531         CAInterface_t *ifitem = (CAInterface_t *)u_arraylist_get(iflist, i);
532         if (!ifitem)
533         {
534             continue;
535         }
536
537         CAProcessNewInterface(ifitem);
538     }
539     u_arraylist_destroy(iflist);
540 }
541
542 JNIEXPORT void JNICALL
543 Java_org_iotivity_ca_CaIpInterface_caIpStateDisabled(JNIEnv *env, jclass class)
544 {
545     (void)env;
546     (void)class;
547
548     OIC_LOG(DEBUG, TAG, "No network connectivity");
549     CAIPPassNetworkChangesToAdapter(CA_INTERFACE_DOWN);
550
551     CloseMulticastSocket();
552 }