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"
40 #include "oic_malloc.h"
41 #include "oic_string.h"
42 #include "org_iotivity_ca_CaIpInterface.h"
43 #include "caifaddrs.h"
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"
51 * Used to storing adapter changes callback interface.
53 static struct CAIPCBData_t *g_adapterCallbackList = NULL;
56 * Used to indicate whether WiFi is enabled or not during init.
58 static bool g_wifiConnectionDuringInit = false;
61 * WiFi Interface's Name.
63 static const char *g_wifiInterfaceName = NULL;
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.
74 static CAInterface_t *CANewInterfaceItem(int index, const char *name, int family,
75 const char *addr, int flags);
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).
87 static CAResult_t CAAddInterfaceItem(u_arraylist_t *iflist, int index,
88 const char *name, int family, const char *addr, int flags);
91 * Initialize JNI interface.
92 * @return ::CA_STATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
94 CAResult_t CAIPJniInit();
97 * Destroy JNI interface.
98 * @return ::CA_STATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
100 static CAResult_t CAIPDestroyJniInterface();
102 #define MAX_INTERFACE_INFO_LENGTH 1024 // allows 32 interfaces from SIOCGIFCONF
104 CAResult_t CAIPStartNetworkMonitor(CAIPAdapterStateChangeCallback callback,
105 CATransportAdapter_t adapter)
107 CAResult_t res = CAIPJniInit();
108 if (CA_STATUS_OK != res)
110 OIC_LOG(ERROR, TAG, "failed to initialize ip jni interface");
114 return CAIPSetNetworkMonitorCallback(callback, adapter);
117 CAResult_t CAIPStopNetworkMonitor(CATransportAdapter_t adapter)
119 CAIPUnSetNetworkMonitorCallback(adapter);
121 // if there is no callback to pass the changed status, stop monitoring.
122 if (!g_adapterCallbackList)
124 return CAIPDestroyJniInterface();
130 int CAGetPollingInterval(int interval)
135 static void CAIPPassNetworkChangesToAdapter(CANetworkStatus_t status)
137 CAIPCBData_t *cbitem = NULL;
138 LL_FOREACH(g_adapterCallbackList, cbitem)
140 if (cbitem && cbitem->adapter)
142 cbitem->callback(cbitem->adapter, status);
147 CAResult_t CAIPSetNetworkMonitorCallback(CAIPAdapterStateChangeCallback callback,
148 CATransportAdapter_t adapter)
152 OIC_LOG(ERROR, TAG, "callback is null");
153 return CA_STATUS_INVALID_PARAM;
156 CAIPCBData_t *cbitem = NULL;
157 LL_FOREACH(g_adapterCallbackList, cbitem)
159 if (cbitem && adapter == cbitem->adapter && callback == cbitem->callback)
161 OIC_LOG(DEBUG, TAG, "this callback is already added");
166 cbitem = (CAIPCBData_t *)OICCalloc(1, sizeof(*cbitem));
169 OIC_LOG(ERROR, TAG, "Malloc failed");
170 return CA_STATUS_FAILED;
173 cbitem->adapter = adapter;
174 cbitem->callback = callback;
175 LL_APPEND(g_adapterCallbackList, cbitem);
180 CAResult_t CAIPUnSetNetworkMonitorCallback(CATransportAdapter_t adapter)
182 CAIPCBData_t *cbitem = NULL;
183 CAIPCBData_t *tmpCbitem = NULL;
184 LL_FOREACH_SAFE(g_adapterCallbackList, cbitem, tmpCbitem)
186 if (cbitem && adapter == cbitem->adapter)
188 OIC_LOG(DEBUG, TAG, "remove specific callback");
189 LL_DELETE(g_adapterCallbackList, cbitem);
197 u_arraylist_t *CAFindInterfaceChange()
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),
209 ssize_t len = recvmsg(caglobals.ip.netlinkFd, &msg, 0);
214 * Used to send netlink query to kernel and recv response from kernel.
216 * @param[in] idx desired network interface index, 0 means all interfaces.
217 * @param[out] iflist linked list.
220 static bool CAParsingNetorkInfo(int idx, u_arraylist_t *iflist)
222 if ((idx < 0) || (iflist == NULL))
227 struct ifaddrs *ifp = NULL;
228 CAResult_t ret = CAGetIfaddrsUsingNetlink(&ifp);
229 if (CA_STATUS_OK != ret)
231 OIC_LOG_V(ERROR, TAG, "Failed to get ifaddrs err code is: %d", ret);
235 struct ifaddrs *ifa = NULL;
236 for (ifa = ifp; ifa; ifa = ifa->ifa_next)
243 int family = ifa->ifa_addr->sa_family;
244 if ((ifa->ifa_flags & IFF_LOOPBACK) || (AF_INET != family && AF_INET6 != family))
249 int ifindex = if_nametoindex(ifa->ifa_name);
250 if (idx && (ifindex != idx))
255 // Ignoring all non WiFi interfaces.
256 if (g_wifiInterfaceName != NULL && (strlen(g_wifiInterfaceName) > 0) &&
257 (strcmp(ifa->ifa_name, g_wifiInterfaceName) != 0))
259 OIC_LOG_V(DEBUG, TAG, "Ignoring Non-WiFi interface: %s(%d)", ifa->ifa_name, ifindex);
263 char ipaddr[MAX_ADDR_STR_SIZE_CA] = {0};
264 if (family == AF_INET6)
266 struct sockaddr_in6 *in6 = (struct sockaddr_in6*) ifa->ifa_addr;
267 inet_ntop(family, (void *)&(in6->sin6_addr), ipaddr, sizeof(ipaddr));
269 else if (family == AF_INET)
271 struct sockaddr_in *in = (struct sockaddr_in*) ifa->ifa_addr;
272 inet_ntop(family, (void *)&(in->sin_addr), ipaddr, sizeof(ipaddr));
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))
279 OIC_LOG(DEBUG, TAG, "LOOPBACK continue!!!");
283 CAResult_t result = CAAddInterfaceItem(iflist, ifindex,
284 ifa->ifa_name, family,
285 ipaddr, ifa->ifa_flags);
286 if (CA_STATUS_OK != result)
288 OIC_LOG(ERROR, TAG, "CAAddInterfaceItem fail");
300 u_arraylist_t *CAIPGetInterfaceInformation(int desiredIndex)
302 u_arraylist_t *iflist = u_arraylist_create();
305 OIC_LOG_V(ERROR, TAG, "Failed to create iflist: %s", strerror(errno));
309 if (!CAParsingNetorkInfo(desiredIndex, iflist))
317 u_arraylist_destroy(iflist);
321 static CAResult_t CAAddInterfaceItem(u_arraylist_t *iflist, int index,
322 const char *name, int family, const char *addr, int flags)
324 CAInterface_t *ifitem = CANewInterfaceItem(index, name, family, addr, flags);
327 return CA_STATUS_FAILED;
329 bool result = u_arraylist_add(iflist, ifitem);
332 OIC_LOG(ERROR, TAG, "u_arraylist_add failed.");
334 return CA_STATUS_FAILED;
340 static CAInterface_t *CANewInterfaceItem(int index, const char *name, int family,
341 const char *addr, int flags)
343 CAInterface_t *ifitem = (CAInterface_t *)OICCalloc(1, sizeof (CAInterface_t));
346 OIC_LOG(ERROR, TAG, "Malloc failed in CANewInterfaceItem");
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;
359 CAResult_t CAIPJniInit()
361 OIC_LOG(DEBUG, TAG, "CAIPJniInit_IN");
363 JavaVM *jvm = CANativeJNIGetJavaVM();
366 OIC_LOG(ERROR, TAG, "Could not get JavaVM pointer");
367 return CA_STATUS_FAILED;
370 jobject context = CANativeJNIGetContext();
373 OIC_LOG(ERROR, TAG, "unable to get application context");
374 return CA_STATUS_FAILED;
378 if ((*jvm)->GetEnv(jvm, (void**) &env, JNI_VERSION_1_6) != JNI_OK)
380 OIC_LOG(ERROR, TAG, "Could not get JNIEnv pointer");
381 return CA_STATUS_FAILED;
384 jmethodID mid_getApplicationContext = CAGetJNIMethodID(env, "android/content/Context",
385 "getApplicationContext",
386 "()Landroid/content/Context;");
388 if (!mid_getApplicationContext)
390 OIC_LOG(ERROR, TAG, "Could not get getApplicationContext method");
391 return CA_STATUS_FAILED;
394 jobject jApplicationContext = (*env)->CallObjectMethod(env, context,
395 mid_getApplicationContext);
396 if (!jApplicationContext)
398 OIC_LOG(ERROR, TAG, "Could not get application context");
399 return CA_STATUS_FAILED;
402 jclass cls_CaIpInterface = (*env)->FindClass(env, "org/iotivity/ca/CaIpInterface");
403 if (!cls_CaIpInterface)
405 OIC_LOG(ERROR, TAG, "Could not get CaIpInterface class");
406 return CA_STATUS_FAILED;
409 jmethodID mid_CaIpInterface_ctor = (*env)->GetMethodID(env, cls_CaIpInterface, "<init>",
410 "(Landroid/content/Context;)V");
411 if (!mid_CaIpInterface_ctor)
413 OIC_LOG(ERROR, TAG, "Could not get CaIpInterface constructor method");
414 return CA_STATUS_FAILED;
417 jobject jCaIpInterface = (*env)->NewObject(env, cls_CaIpInterface, mid_CaIpInterface_ctor, jApplicationContext);
420 OIC_LOG(ERROR, TAG, "Could not create an instance of CaIpInterface");
421 return CA_STATUS_FAILED;
424 // Get WiFi Connection status.
425 jmethodID mid_hasWifiConnection = (*env)->GetMethodID(env, cls_CaIpInterface, "hasWifiConnection", "()Z");
426 if (!mid_hasWifiConnection)
428 OIC_LOG(ERROR, TAG, "Could not get hasWifiConnection method");
429 return CA_STATUS_FAILED;
432 g_wifiConnectionDuringInit = (*env)->CallBooleanMethod(env, jCaIpInterface, mid_hasWifiConnection);
434 // Get WiFi Interface's name.
435 jmethodID mid_getWiFiInterfaceName = (*env)->GetMethodID(env, cls_CaIpInterface,
436 "getWiFiInterfaceName", "()Ljava/lang/String;");
437 if (!mid_getWiFiInterfaceName)
439 OIC_LOG(ERROR, TAG, "Could not get getWiFiInterfaceName method");
440 return CA_STATUS_FAILED;
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)
448 OIC_LOG(ERROR, TAG, "Failed to duplicate the Wifi Interface name.");
451 (*env)->ReleaseStringUTFChars(env, jWifiInterfaceName, wifiInterfaceNameLocal);
453 OIC_LOG_V(DEBUG, TAG, "WiFi Interface Name: %s, WiFi Connection State: %d", g_wifiInterfaceName,
454 g_wifiConnectionDuringInit);
456 OIC_LOG(DEBUG, TAG, "CAIPJniInit_OUT");
460 static CAResult_t CAIPDestroyJniInterface()
462 OIC_LOG(DEBUG, TAG, "CAIPDestroyJniInterface");
464 JavaVM *jvm = CANativeJNIGetJavaVM();
467 OIC_LOG(ERROR, TAG, "Could not get JavaVM pointer");
468 return CA_STATUS_FAILED;
471 bool isAttached = false;
473 jint res = (*jvm)->GetEnv(jvm, (void**) &env, JNI_VERSION_1_6);
476 OIC_LOG(INFO, TAG, "Could not get JNIEnv pointer");
477 res = (*jvm)->AttachCurrentThread(jvm, &env, NULL);
481 OIC_LOG(ERROR, TAG, "AttachCurrentThread has failed");
482 return CA_STATUS_FAILED;
487 CACheckJNIException(env);
489 jclass jni_IpInterface = (*env)->FindClass(env, "org/iotivity/ca/CaIpInterface");
490 if (!jni_IpInterface)
492 OIC_LOG(ERROR, TAG, "Could not get CaIpInterface class");
496 jmethodID jni_InterfaceDestroyMethod = (*env)->GetStaticMethodID(env, jni_IpInterface,
497 "destroyIpInterface",
499 if (!jni_InterfaceDestroyMethod)
501 OIC_LOG(ERROR, TAG, "Could not get CaIpInterface destroy method");
505 (*env)->CallStaticVoidMethod(env, jni_IpInterface, jni_InterfaceDestroyMethod);
507 if (CACheckJNIException(env))
509 OIC_LOG(ERROR, TAG, "destroyIpInterface has failed");
513 OIC_LOG(DEBUG, TAG, "Destroy instance for CaIpInterface");
515 if (g_wifiInterfaceName)
517 OICFree(g_wifiInterfaceName);
518 g_wifiInterfaceName = NULL;
523 (*jvm)->DetachCurrentThread(jvm);
532 (*jvm)->DetachCurrentThread(jvm);
535 return CA_STATUS_FAILED;
538 bool isWifiConnectedDuringInit()
540 return g_wifiConnectionDuringInit;
543 const char *getWifiInterfaceName()
545 return g_wifiInterfaceName;
548 JNIEXPORT void JNICALL
549 Java_org_iotivity_ca_CaIpInterface_caIpStateEnabled(JNIEnv *env, jclass class,
555 CAIPPassNetworkChangesToAdapter(CA_INTERFACE_UP);
562 OIC_LOG(DEBUG, TAG, "Wifi is in Activated State");
564 // Closing sockets for safety reasons to handle missed out WiFi state disabled events.
565 CloseMulticastSocket();
568 CreateMulticastSocket();
570 // Apply network interface changes.
571 u_arraylist_t *iflist = CAIPGetInterfaceInformation(0);
574 OIC_LOG_V(ERROR, TAG, "get interface info failed: %s", strerror(errno));
578 uint32_t listLength = u_arraylist_length(iflist);
579 for (uint32_t i = 0; i < listLength; i++)
581 CAInterface_t *ifitem = (CAInterface_t *)u_arraylist_get(iflist, i);
587 CAProcessNewInterface(ifitem);
589 u_arraylist_destroy(iflist);
592 JNIEXPORT void JNICALL
593 Java_org_iotivity_ca_CaIpInterface_caIpStateDisabled(JNIEnv *env, jclass class)
598 OIC_LOG(DEBUG, TAG, "No network connectivity");
599 CAIPPassNetworkChangesToAdapter(CA_INTERFACE_DOWN);
601 CloseMulticastSocket();