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