1 /******************************************************************
3 * Copyright 2014 Samsung Electronics All Rights Reserved.
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 ******************************************************************/
21 #include "caipinterface.h"
23 #include <sys/types.h>
24 #include <sys/socket.h>
30 #include <arpa/inet.h>
32 #include <coap/utlist.h>
33 #include <linux/netlink.h>
34 #include <linux/rtnetlink.h>
37 #include "caadapterutils.h"
38 #include "caipnwmonitor.h"
39 #include "caipnwmonitor_common.h"
41 #include "oic_malloc.h"
42 #include "oic_string.h"
43 #include "org_iotivity_ca_CaIpInterface.h"
44 #include "caifaddrs.h"
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"
52 * Used to storing adapter changes callback interface.
54 static struct CAIPCBData_t *g_adapterCallbackList = NULL;
57 * Used to indicate whether WiFi is enabled or not during init.
59 static bool g_wifiConnectionDuringInit = false;
62 * WiFi Interface's Name.
64 static const char *g_wifiInterfaceName = NULL;
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.
75 static CAInterface_t *CANewInterfaceItem(int index, const char *name, int family,
76 const char *addr, int flags);
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).
88 static CAResult_t CAAddInterfaceItem(u_arraylist_t *iflist, int index,
89 const char *name, int family, const char *addr, int flags);
92 * Initialize JNI interface.
93 * @return ::CA_STATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
95 CAResult_t CAIPJniInit();
98 * Destroy JNI interface.
99 * @return ::CA_STATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
101 static CAResult_t CAIPDestroyJniInterface();
103 #define MAX_INTERFACE_INFO_LENGTH 1024 // allows 32 interfaces from SIOCGIFCONF
105 CAResult_t CAIPStartNetworkMonitor(CAIPAdapterStateChangeCallback callback,
106 CATransportAdapter_t adapter)
108 CAResult_t res = CAIPJniInit();
109 if (CA_STATUS_OK != res)
111 OIC_LOG(ERROR, TAG, "failed to initialize ip jni interface");
115 return CAIPSetNetworkMonitorCallback(callback, adapter);
118 CAResult_t CAIPStopNetworkMonitor(CATransportAdapter_t adapter)
120 CAIPUnSetNetworkMonitorCallback(adapter);
122 // if there is no callback to pass the changed status, stop monitoring.
123 if (!g_adapterCallbackList)
125 return CAIPDestroyJniInterface();
131 static void CAIPPassNetworkChangesToAdapter(CANetworkStatus_t status)
133 CAIPPassNetworkChangesToAdapterInternal(status, g_adapterCallbackList, CA_IP_NW_COMMON_ANDROID);
136 CAResult_t CAIPSetNetworkMonitorCallback(CAIPAdapterStateChangeCallback callback,
137 CATransportAdapter_t adapter)
139 return CAIPSetNetworkMonitorCallbackInternal(callback, adapter, g_adapterCallbackList);
142 CAResult_t CAIPUnSetNetworkMonitorCallback(CATransportAdapter_t adapter)
144 return CAIPUnSetNetworkMonitorCallbackInternal(adapter, g_adapterCallbackList);
147 u_arraylist_t *CAFindInterfaceChange()
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),
159 ssize_t len = recvmsg(caglobals.ip.netlinkFd, &msg, 0);
164 * Used to send netlink query to kernel and recv response from kernel.
166 * @param[in] idx desired network interface index, 0 means all interfaces.
167 * @param[out] iflist linked list.
170 static bool CAParsingNetorkInfo(int idx, u_arraylist_t *iflist)
172 if ((idx < 0) || (iflist == NULL))
177 struct ifaddrs *ifp = NULL;
178 CAResult_t ret = CAGetIfaddrsUsingNetlink(&ifp);
179 if (CA_STATUS_OK != ret)
181 OIC_LOG_V(ERROR, TAG, "Failed to get ifaddrs err code is: %d", ret);
185 struct ifaddrs *ifa = NULL;
186 for (ifa = ifp; ifa; ifa = ifa->ifa_next)
193 int family = ifa->ifa_addr->sa_family;
194 if ((ifa->ifa_flags & IFF_LOOPBACK) || (AF_INET != family && AF_INET6 != family))
199 int ifindex = if_nametoindex(ifa->ifa_name);
200 if (idx && (ifindex != idx))
205 // Ignoring all non WiFi interfaces.
206 if (g_wifiInterfaceName != NULL && (strlen(g_wifiInterfaceName) > 0) &&
207 (strcmp(ifa->ifa_name, g_wifiInterfaceName) != 0))
209 OIC_LOG_V(DEBUG, TAG, "Ignoring Non-WiFi interface: %s(%d)", ifa->ifa_name, ifindex);
213 char ipaddr[MAX_ADDR_STR_SIZE_CA] = {0};
214 if (family == AF_INET6)
216 struct sockaddr_in6 *in6 = (struct sockaddr_in6*) ifa->ifa_addr;
217 inet_ntop(family, (void *)&(in6->sin6_addr), ipaddr, sizeof(ipaddr));
219 else if (family == AF_INET)
221 struct sockaddr_in *in = (struct sockaddr_in*) ifa->ifa_addr;
222 inet_ntop(family, (void *)&(in->sin_addr), ipaddr, sizeof(ipaddr));
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))
229 OIC_LOG(DEBUG, TAG, "LOOPBACK continue!!!");
233 CAResult_t result = CAAddInterfaceItem(iflist, ifindex,
234 ifa->ifa_name, family,
235 ipaddr, ifa->ifa_flags);
236 if (CA_STATUS_OK != result)
238 OIC_LOG(ERROR, TAG, "CAAddInterfaceItem fail");
250 u_arraylist_t *CAIPGetInterfaceInformation(int desiredIndex)
252 u_arraylist_t *iflist = u_arraylist_create();
255 OIC_LOG_V(ERROR, TAG, "Failed to create iflist: %s", strerror(errno));
259 if (!CAParsingNetorkInfo(desiredIndex, iflist))
267 u_arraylist_destroy(iflist);
271 static CAResult_t CAAddInterfaceItem(u_arraylist_t *iflist, int index,
272 const char *name, int family, const char *addr, int flags)
274 CAInterface_t *ifitem = CANewInterfaceItem(index, name, family, addr, flags);
277 return CA_STATUS_FAILED;
279 bool result = u_arraylist_add(iflist, ifitem);
282 OIC_LOG(ERROR, TAG, "u_arraylist_add failed.");
284 return CA_STATUS_FAILED;
290 static CAInterface_t *CANewInterfaceItem(int index, const char *name, int family,
291 const char *addr, int flags)
293 CAInterface_t *ifitem = (CAInterface_t *)OICCalloc(1, sizeof (CAInterface_t));
296 OIC_LOG(ERROR, TAG, "Malloc failed in CANewInterfaceItem");
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;
309 CAResult_t CAIPJniInit()
311 OIC_LOG(DEBUG, TAG, "CAIPJniInit_IN");
313 JavaVM *jvm = CANativeJNIGetJavaVM();
316 OIC_LOG(ERROR, TAG, "Could not get JavaVM pointer");
317 return CA_STATUS_FAILED;
320 jobject context = CANativeJNIGetContext();
323 OIC_LOG(ERROR, TAG, "unable to get application context");
324 return CA_STATUS_FAILED;
328 if ((*jvm)->GetEnv(jvm, (void**) &env, JNI_VERSION_1_6) != JNI_OK)
330 OIC_LOG(ERROR, TAG, "Could not get JNIEnv pointer");
331 return CA_STATUS_FAILED;
334 jmethodID mid_getApplicationContext = CAGetJNIMethodID(env, "android/content/Context",
335 "getApplicationContext",
336 "()Landroid/content/Context;");
338 if (!mid_getApplicationContext)
340 OIC_LOG(ERROR, TAG, "Could not get getApplicationContext method");
341 return CA_STATUS_FAILED;
344 jobject jApplicationContext = (*env)->CallObjectMethod(env, context,
345 mid_getApplicationContext);
346 if (!jApplicationContext)
348 OIC_LOG(ERROR, TAG, "Could not get application context");
349 return CA_STATUS_FAILED;
352 jclass cls_CaIpInterface = (*env)->FindClass(env, "org/iotivity/ca/CaIpInterface");
353 if (!cls_CaIpInterface)
355 OIC_LOG(ERROR, TAG, "Could not get CaIpInterface class");
356 return CA_STATUS_FAILED;
359 jmethodID mid_CaIpInterface_ctor = (*env)->GetMethodID(env, cls_CaIpInterface, "<init>",
360 "(Landroid/content/Context;)V");
361 if (!mid_CaIpInterface_ctor)
363 OIC_LOG(ERROR, TAG, "Could not get CaIpInterface constructor method");
364 return CA_STATUS_FAILED;
367 jobject jCaIpInterface = (*env)->NewObject(env, cls_CaIpInterface, mid_CaIpInterface_ctor, jApplicationContext);
370 OIC_LOG(ERROR, TAG, "Could not create an instance of CaIpInterface");
371 return CA_STATUS_FAILED;
374 // Get WiFi Connection status.
375 jmethodID mid_hasWifiConnection = (*env)->GetMethodID(env, cls_CaIpInterface, "hasWifiConnection", "()Z");
376 if (!mid_hasWifiConnection)
378 OIC_LOG(ERROR, TAG, "Could not get hasWifiConnection method");
379 return CA_STATUS_FAILED;
382 g_wifiConnectionDuringInit = (*env)->CallBooleanMethod(env, jCaIpInterface, mid_hasWifiConnection);
384 // Get WiFi Interface's name.
385 jmethodID mid_getWiFiInterfaceName = (*env)->GetMethodID(env, cls_CaIpInterface,
386 "getWiFiInterfaceName", "()Ljava/lang/String;");
387 if (!mid_getWiFiInterfaceName)
389 OIC_LOG(ERROR, TAG, "Could not get getWiFiInterfaceName method");
390 return CA_STATUS_FAILED;
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)
398 OIC_LOG(ERROR, TAG, "Failed to duplicate the Wifi Interface name.");
401 (*env)->ReleaseStringUTFChars(env, jWifiInterfaceName, wifiInterfaceNameLocal);
403 OIC_LOG_V(DEBUG, TAG, "WiFi Interface Name: %s, WiFi Connection State: %d", g_wifiInterfaceName,
404 g_wifiConnectionDuringInit);
406 OIC_LOG(DEBUG, TAG, "CAIPJniInit_OUT");
410 static CAResult_t CAIPDestroyJniInterface()
412 OIC_LOG(DEBUG, TAG, "CAIPDestroyJniInterface");
414 JavaVM *jvm = CANativeJNIGetJavaVM();
417 OIC_LOG(ERROR, TAG, "Could not get JavaVM pointer");
418 return CA_STATUS_FAILED;
421 bool isAttached = false;
423 jint res = (*jvm)->GetEnv(jvm, (void**) &env, JNI_VERSION_1_6);
426 OIC_LOG(INFO, TAG, "Could not get JNIEnv pointer");
427 res = (*jvm)->AttachCurrentThread(jvm, &env, NULL);
431 OIC_LOG(ERROR, TAG, "AttachCurrentThread has failed");
432 return CA_STATUS_FAILED;
437 CACheckJNIException(env);
439 jclass jni_IpInterface = (*env)->FindClass(env, "org/iotivity/ca/CaIpInterface");
440 if (!jni_IpInterface)
442 OIC_LOG(ERROR, TAG, "Could not get CaIpInterface class");
446 jmethodID jni_InterfaceDestroyMethod = (*env)->GetStaticMethodID(env, jni_IpInterface,
447 "destroyIpInterface",
449 if (!jni_InterfaceDestroyMethod)
451 OIC_LOG(ERROR, TAG, "Could not get CaIpInterface destroy method");
455 (*env)->CallStaticVoidMethod(env, jni_IpInterface, jni_InterfaceDestroyMethod);
457 if (CACheckJNIException(env))
459 OIC_LOG(ERROR, TAG, "destroyIpInterface has failed");
463 OIC_LOG(DEBUG, TAG, "Destroy instance for CaIpInterface");
465 if (g_wifiInterfaceName)
467 OICFree(g_wifiInterfaceName);
468 g_wifiInterfaceName = NULL;
473 (*jvm)->DetachCurrentThread(jvm);
482 (*jvm)->DetachCurrentThread(jvm);
485 return CA_STATUS_FAILED;
488 bool isWifiConnectedDuringInit()
490 return g_wifiConnectionDuringInit;
493 const char *getWifiInterfaceName()
495 return g_wifiInterfaceName;
498 JNIEXPORT void JNICALL
499 Java_org_iotivity_ca_CaIpInterface_caIpStateEnabled(JNIEnv *env, jclass class,
505 CAIPPassNetworkChangesToAdapter(CA_INTERFACE_UP);
512 OIC_LOG(DEBUG, TAG, "Wifi is in Activated State");
514 // Closing sockets for safety reasons to handle missed out WiFi state disabled events.
515 CloseMulticastSocket();
518 CreateMulticastSocket();
520 // Apply network interface changes.
521 u_arraylist_t *iflist = CAIPGetInterfaceInformation(0);
524 OIC_LOG_V(ERROR, TAG, "get interface info failed: %s", strerror(errno));
528 uint32_t listLength = u_arraylist_length(iflist);
529 for (uint32_t i = 0; i < listLength; i++)
531 CAInterface_t *ifitem = (CAInterface_t *)u_arraylist_get(iflist, i);
537 CAProcessNewInterface(ifitem);
539 u_arraylist_destroy(iflist);
542 JNIEXPORT void JNICALL
543 Java_org_iotivity_ca_CaIpInterface_caIpStateDisabled(JNIEnv *env, jclass class)
548 OIC_LOG(DEBUG, TAG, "No network connectivity");
549 CAIPPassNetworkChangesToAdapter(CA_INTERFACE_DOWN);
551 CloseMulticastSocket();