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 * 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.
64 static CAInterface_t *CANewInterfaceItem(int index, const char *name, int family,
65 const char *addr, int flags);
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).
77 static CAResult_t CAAddInterfaceItem(u_arraylist_t *iflist, int index,
78 const char *name, int family, const char *addr, int flags);
81 * Initialize JNI interface.
82 * @return ::CA_STATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
84 CAResult_t CAIPJniInit();
87 * Destroy JNI interface.
88 * @return ::CA_STATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
90 static CAResult_t CAIPDestroyJniInterface();
92 #define MAX_INTERFACE_INFO_LENGTH 1024 // allows 32 interfaces from SIOCGIFCONF
94 CAResult_t CAIPStartNetworkMonitor(CAIPAdapterStateChangeCallback callback,
95 CATransportAdapter_t adapter)
97 CAResult_t res = CAIPJniInit();
98 if (CA_STATUS_OK != res)
100 OIC_LOG(ERROR, TAG, "failed to initialize ip jni interface");
104 return CAIPSetNetworkMonitorCallback(callback, adapter);
107 CAResult_t CAIPStopNetworkMonitor(CATransportAdapter_t adapter)
109 CAIPUnSetNetworkMonitorCallback(adapter);
111 // if there is no callback to pass the changed status, stop monitoring.
112 if (!g_adapterCallbackList)
114 return CAIPDestroyJniInterface();
120 int CAGetPollingInterval(int interval)
125 static void CAIPPassNetworkChangesToAdapter(CANetworkStatus_t status)
127 CAIPCBData_t *cbitem = NULL;
128 LL_FOREACH(g_adapterCallbackList, cbitem)
130 if (cbitem && cbitem->adapter)
132 cbitem->callback(cbitem->adapter, status);
137 CAResult_t CAIPSetNetworkMonitorCallback(CAIPAdapterStateChangeCallback callback,
138 CATransportAdapter_t adapter)
142 OIC_LOG(ERROR, TAG, "callback is null");
143 return CA_STATUS_INVALID_PARAM;
146 CAIPCBData_t *cbitem = NULL;
147 LL_FOREACH(g_adapterCallbackList, cbitem)
149 if (cbitem && adapter == cbitem->adapter && callback == cbitem->callback)
151 OIC_LOG(DEBUG, TAG, "this callback is already added");
156 cbitem = (CAIPCBData_t *)OICCalloc(1, sizeof(*cbitem));
159 OIC_LOG(ERROR, TAG, "Malloc failed");
160 return CA_STATUS_FAILED;
163 cbitem->adapter = adapter;
164 cbitem->callback = callback;
165 LL_APPEND(g_adapterCallbackList, cbitem);
170 CAResult_t CAIPUnSetNetworkMonitorCallback(CATransportAdapter_t adapter)
172 CAIPCBData_t *cbitem = NULL;
173 CAIPCBData_t *tmpCbitem = NULL;
174 LL_FOREACH_SAFE(g_adapterCallbackList, cbitem, tmpCbitem)
176 if (cbitem && adapter == cbitem->adapter)
178 OIC_LOG(DEBUG, TAG, "remove specific callback");
179 LL_DELETE(g_adapterCallbackList, cbitem);
187 u_arraylist_t *CAFindInterfaceChange()
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),
199 ssize_t len = recvmsg(caglobals.ip.netlinkFd, &msg, 0);
204 * Used to send netlink query to kernel and recv response from kernel.
206 * @param[in] idx desired network interface index, 0 means all interfaces.
207 * @param[out] iflist linked list.
210 static bool CAParsingNetorkInfo(int idx, u_arraylist_t *iflist)
212 if ((idx < 0) || (iflist == NULL))
217 struct ifaddrs *ifp = NULL;
218 CAResult_t ret = CAGetIfaddrsUsingNetlink(&ifp);
219 if (CA_STATUS_OK != ret)
221 OIC_LOG_V(ERROR, TAG, "Failed to get ifaddrs err code is: %d", ret);
225 struct ifaddrs *ifa = NULL;
226 for (ifa = ifp; ifa; ifa = ifa->ifa_next)
233 int family = ifa->ifa_addr->sa_family;
234 if ((ifa->ifa_flags & IFF_LOOPBACK) || (AF_INET != family && AF_INET6 != family))
239 int ifindex = if_nametoindex(ifa->ifa_name);
240 if (idx && (ifindex != idx))
245 char ipaddr[MAX_ADDR_STR_SIZE_CA] = {0};
246 if (family == AF_INET6)
248 struct sockaddr_in6 *in6 = (struct sockaddr_in6*) ifa->ifa_addr;
249 inet_ntop(family, (void *)&(in6->sin6_addr), ipaddr, sizeof(ipaddr));
251 else if (family == AF_INET)
253 struct sockaddr_in *in = (struct sockaddr_in*) ifa->ifa_addr;
254 inet_ntop(family, (void *)&(in->sin_addr), ipaddr, sizeof(ipaddr));
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))
261 OIC_LOG(DEBUG, TAG, "LOOPBACK continue!!!");
265 CAResult_t result = CAAddInterfaceItem(iflist, ifindex,
266 ifa->ifa_name, family,
267 ipaddr, ifa->ifa_flags);
268 if (CA_STATUS_OK != result)
270 OIC_LOG(ERROR, TAG, "CAAddInterfaceItem fail");
282 u_arraylist_t *CAIPGetInterfaceInformation(int desiredIndex)
284 u_arraylist_t *iflist = u_arraylist_create();
287 OIC_LOG_V(ERROR, TAG, "Failed to create iflist: %s", strerror(errno));
291 if (!CAParsingNetorkInfo(desiredIndex, iflist))
299 u_arraylist_destroy(iflist);
303 static CAResult_t CAAddInterfaceItem(u_arraylist_t *iflist, int index,
304 const char *name, int family, const char *addr, int flags)
306 CAInterface_t *ifitem = CANewInterfaceItem(index, name, family, addr, flags);
309 return CA_STATUS_FAILED;
311 bool result = u_arraylist_add(iflist, ifitem);
314 OIC_LOG(ERROR, TAG, "u_arraylist_add failed.");
316 return CA_STATUS_FAILED;
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.
323 CreateMulticastSocket();
328 static CAInterface_t *CANewInterfaceItem(int index, const char *name, int family,
329 const char *addr, int flags)
331 CAInterface_t *ifitem = (CAInterface_t *)OICCalloc(1, sizeof (CAInterface_t));
334 OIC_LOG(ERROR, TAG, "Malloc failed in CANewInterfaceItem");
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;
347 CAResult_t CAIPJniInit()
349 OIC_LOG(DEBUG, TAG, "CAIPJniInit_IN");
351 JavaVM *jvm = CANativeJNIGetJavaVM();
354 OIC_LOG(ERROR, TAG, "Could not get JavaVM pointer");
355 return CA_STATUS_FAILED;
358 jobject context = CANativeJNIGetContext();
361 OIC_LOG(ERROR, TAG, "unable to get application context");
362 return CA_STATUS_FAILED;
366 if ((*jvm)->GetEnv(jvm, (void**) &env, JNI_VERSION_1_6) != JNI_OK)
368 OIC_LOG(ERROR, TAG, "Could not get JNIEnv pointer");
369 return CA_STATUS_FAILED;
372 jmethodID mid_getApplicationContext = CAGetJNIMethodID(env, "android/content/Context",
373 "getApplicationContext",
374 "()Landroid/content/Context;");
376 if (!mid_getApplicationContext)
378 OIC_LOG(ERROR, TAG, "Could not get getApplicationContext method");
379 return CA_STATUS_FAILED;
382 jobject jApplicationContext = (*env)->CallObjectMethod(env, context,
383 mid_getApplicationContext);
384 if (!jApplicationContext)
386 OIC_LOG(ERROR, TAG, "Could not get application context");
387 return CA_STATUS_FAILED;
390 jclass cls_CaIpInterface = (*env)->FindClass(env, "org/iotivity/ca/CaIpInterface");
391 if (!cls_CaIpInterface)
393 OIC_LOG(ERROR, TAG, "Could not get CaIpInterface class");
394 return CA_STATUS_FAILED;
397 jmethodID mid_CaIpInterface_ctor = (*env)->GetMethodID(env, cls_CaIpInterface, "<init>",
398 "(Landroid/content/Context;)V");
399 if (!mid_CaIpInterface_ctor)
401 OIC_LOG(ERROR, TAG, "Could not get CaIpInterface constructor method");
402 return CA_STATUS_FAILED;
405 (*env)->NewObject(env, cls_CaIpInterface, mid_CaIpInterface_ctor, jApplicationContext);
406 OIC_LOG(DEBUG, TAG, "Create CaIpInterface instance, success");
408 OIC_LOG(DEBUG, TAG, "CAIPJniInit_OUT");
412 static CAResult_t CAIPDestroyJniInterface()
414 OIC_LOG(DEBUG, TAG, "CAIPDestroyJniInterface");
416 JavaVM *jvm = CANativeJNIGetJavaVM();
419 OIC_LOG(ERROR, TAG, "Could not get JavaVM pointer");
420 return CA_STATUS_FAILED;
423 bool isAttached = false;
425 jint res = (*jvm)->GetEnv(jvm, (void**) &env, JNI_VERSION_1_6);
428 OIC_LOG(INFO, TAG, "Could not get JNIEnv pointer");
429 res = (*jvm)->AttachCurrentThread(jvm, &env, NULL);
433 OIC_LOG(ERROR, TAG, "AttachCurrentThread has failed");
434 return CA_STATUS_FAILED;
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 ((*env)->ExceptionCheck(env))
459 OIC_LOG(ERROR, TAG, "destroyIpInterface has failed");
460 (*env)->ExceptionDescribe(env);
461 (*env)->ExceptionClear(env);
465 OIC_LOG(DEBUG, TAG, "Destroy instance for CaIpInterface");
469 (*jvm)->DetachCurrentThread(jvm);
478 (*jvm)->DetachCurrentThread(jvm);
481 return CA_STATUS_FAILED;
484 JNIEXPORT void JNICALL
485 Java_org_iotivity_ca_CaIpInterface_caIpStateEnabled(JNIEnv *env, jclass class)
490 OIC_LOG(DEBUG, TAG, "Wifi is in Activated State");
491 CAIPPassNetworkChangesToAdapter(CA_INTERFACE_UP);
493 // Closing sockets so that it will be created again when interfaces are identified(CONPRO-1269).
494 CloseMulticastSocket();
497 // Apply network interface changes.
498 u_arraylist_t *iflist = CAIPGetInterfaceInformation(0);
501 OIC_LOG_V(ERROR, TAG, "get interface info failed: %s", strerror(errno));
505 uint32_t listLength = u_arraylist_length(iflist);
506 for (uint32_t i = 0; i < listLength; i++)
508 CAInterface_t *ifitem = (CAInterface_t *)u_arraylist_get(iflist, i);
514 CAProcessNewInterface(ifitem);
517 u_arraylist_destroy(iflist);
520 JNIEXPORT void JNICALL
521 Java_org_iotivity_ca_CaIpInterface_caIpStateDisabled(JNIEnv *env, jclass class)
526 OIC_LOG(DEBUG, TAG, "Wifi is in Deactivated State");
527 CAIPPassNetworkChangesToAdapter(CA_INTERFACE_DOWN);