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