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>
34 #include "caadapterutils.h"
35 #include "caipnwmonitor.h"
37 #include "oic_malloc.h"
38 #include "oic_string.h"
39 #include "org_iotivity_ca_CaIpInterface.h"
41 #define TAG "OIC_CA_IP_MONITOR"
42 #define NETLINK_MESSAGE_LENGTH (4096)
45 * Used to storing adapter changes callback interface.
47 static struct CAIPCBData_t *g_adapterCallbackList = NULL;
50 * Create new interface item to add in activated interface list.
51 * @param[in] index Network interface index number.
52 * @param[in] name Network interface name.
53 * @param[in] family Network interface family type.
54 * @param[in] addr New interface address.
55 * @param[in] flags The active flag word of a device.
56 * @return CAInterface_t objects.
58 static CAInterface_t *CANewInterfaceItem(int index, const char *name, int family,
59 const char *addr, int flags);
62 * Add created new interface item activated interface list.
63 * @param[in] iflist Network interface array list.
64 * @param[in] index Network interface index number.
65 * @param[in] name Network interface name.
66 * @param[in] family Network interface family type.
67 * @param[in] addr New interface address.
68 * @param[in] flags The active flag word of a device.
69 * @return ::CA_STATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
71 static CAResult_t CAAddInterfaceItem(u_arraylist_t *iflist, int index,
72 const char *name, int family, const char *addr, int flags);
75 * Initialize JNI interface.
76 * @return ::CA_STATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
78 CAResult_t CAIPJniInit();
81 * Destroy JNI interface.
82 * @return ::CA_STATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
84 static CAResult_t CAIPDestroyJniInterface();
86 #define MAX_INTERFACE_INFO_LENGTH 1024 // allows 32 interfaces from SIOCGIFCONF
88 CAResult_t CAIPStartNetworkMonitor(CAIPAdapterStateChangeCallback callback,
89 CATransportAdapter_t adapter)
91 CAResult_t res = CAIPJniInit();
92 if (CA_STATUS_OK != res)
94 OIC_LOG(ERROR, TAG, "failed to initialize ip jni interface");
98 return CAIPSetNetworkMonitorCallback(callback, adapter);
101 CAResult_t CAIPStopNetworkMonitor(CATransportAdapter_t adapter)
103 CAIPUnSetNetworkMonitorCallback(adapter);
105 // if there is no callback to pass the changed status, stop monitoring.
106 if (!g_adapterCallbackList)
108 return CAIPDestroyJniInterface();
114 int CAGetPollingInterval(int interval)
119 static void CAIPPassNetworkChangesToAdapter(CANetworkStatus_t status)
121 CAIPCBData_t *cbitem = NULL;
122 LL_FOREACH(g_adapterCallbackList, cbitem)
124 if (cbitem && cbitem->adapter)
126 cbitem->callback(cbitem->adapter, status);
131 CAResult_t CAIPSetNetworkMonitorCallback(CAIPAdapterStateChangeCallback callback,
132 CATransportAdapter_t adapter)
136 OIC_LOG(ERROR, TAG, "callback is null");
137 return CA_STATUS_INVALID_PARAM;
140 CAIPCBData_t *cbitem = NULL;
141 LL_FOREACH(g_adapterCallbackList, cbitem)
143 if (cbitem && adapter == cbitem->adapter && callback == cbitem->callback)
145 OIC_LOG(DEBUG, TAG, "this callback is already added");
150 cbitem = (CAIPCBData_t *)OICCalloc(1, sizeof(*cbitem));
153 OIC_LOG(ERROR, TAG, "Malloc failed");
154 return CA_STATUS_FAILED;
157 cbitem->adapter = adapter;
158 cbitem->callback = callback;
159 LL_APPEND(g_adapterCallbackList, cbitem);
164 CAResult_t CAIPUnSetNetworkMonitorCallback(CATransportAdapter_t adapter)
166 CAIPCBData_t *cbitem = NULL;
167 CAIPCBData_t *tmpCbitem = NULL;
168 LL_FOREACH_SAFE(g_adapterCallbackList, cbitem, tmpCbitem)
170 if (cbitem && adapter == cbitem->adapter)
172 OIC_LOG(DEBUG, TAG, "remove specific callback");
173 LL_DELETE(g_adapterCallbackList, cbitem);
181 u_arraylist_t *CAFindInterfaceChange()
183 // release netlink event
184 char *bufPtr = (char *)OICCalloc(NETLINK_MESSAGE_LENGTH, sizeof (char));
187 OIC_LOG(ERROR, TAG, "Malloc failed");
190 recv(caglobals.ip.netlinkFd, bufPtr, NETLINK_MESSAGE_LENGTH, 0);
194 char buf[MAX_INTERFACE_INFO_LENGTH] = { 0 };
195 struct ifconf ifc = { .ifc_len = MAX_INTERFACE_INFO_LENGTH, .ifc_buf = buf };
197 int s = caglobals.ip.u6.fd != -1 ? caglobals.ip.u6.fd : caglobals.ip.u4.fd;
198 if (ioctl(s, SIOCGIFCONF, &ifc) < 0)
200 OIC_LOG_V(ERROR, TAG, "SIOCGIFCONF failed: %s", strerror(errno));
204 u_arraylist_t *iflist = NULL;
205 CAInterface_t *foundNewInterface = NULL;
207 struct ifreq* ifr = ifc.ifc_req;
208 size_t interfaces = ifc.ifc_len / sizeof (ifc.ifc_req[0]);
209 size_t ifreqsize = ifc.ifc_len;
211 CAIfItem_t *previous = (CAIfItem_t *)OICMalloc(ifreqsize);
214 OIC_LOG(ERROR, TAG, "OICMalloc failed");
218 memcpy(previous, caglobals.ip.nm.ifItems, ifreqsize);
219 size_t numprevious = caglobals.ip.nm.numIfItems;
221 if (ifreqsize > caglobals.ip.nm.sizeIfItems)
224 CAIfItem_t *items = (CAIfItem_t *)OICRealloc(caglobals.ip.nm.ifItems, ifreqsize);
227 OIC_LOG(ERROR, TAG, "OICRealloc failed");
231 caglobals.ip.nm.ifItems = items;
232 caglobals.ip.nm.sizeIfItems = ifreqsize;
235 caglobals.ip.nm.numIfItems = 0;
236 for (size_t i = 0; i < interfaces; i++)
238 struct ifreq* item = &ifr[i];
239 char *name = item->ifr_name;
241 if (ioctl(s, SIOCGIFFLAGS, item) < 0)
243 OIC_LOG_V(ERROR, TAG, "SIOCGIFFLAGS failed: %s", strerror(errno));
246 int16_t flags = item->ifr_flags;
247 if ((flags & IFF_LOOPBACK) || !(flags & IFF_RUNNING))
251 if (ioctl(s, SIOCGIFINDEX, item) < 0)
253 OIC_LOG_V(ERROR, TAG, "SIOCGIFINDEX failed: %s", strerror(errno));
257 int ifIndex = item->ifr_ifindex;
258 caglobals.ip.nm.ifItems[i].ifIndex = ifIndex; // refill interface list
259 caglobals.ip.nm.numIfItems++;
261 if (foundNewInterface)
263 continue; // continue updating interface list
266 // see if this interface didn't previously exist
268 for (size_t j = 0; j < numprevious; j++)
270 if (ifIndex == previous[j].ifIndex)
278 OIC_LOG_V(INFO, TAG, "Interface found: %s", name);
282 // Get address of network interface.
283 char addr[MAX_ADDR_STR_SIZE_CA] = { 0 };
284 struct sockaddr_in *sa = (struct sockaddr_in *)&item->ifr_addr;
285 inet_ntop(AF_INET, (void *)&(sa->sin_addr), addr, sizeof(addr));
287 foundNewInterface = CANewInterfaceItem(ifIndex, name, AF_INET, addr, flags);
291 // below code is temporary impl for consistency with caipserver.
292 // TODO: whole code which using ioctl will be removed and changed with internal getifaddrs impl.
293 if (foundNewInterface)
295 iflist = u_arraylist_create();
299 OIC_LOG_V(ERROR, TAG, "Failed to create iflist: %s", strerror(errno));
303 CAResult_t result = CAAddInterfaceItem(iflist,
304 foundNewInterface->index,
305 foundNewInterface->name,
306 foundNewInterface->family,
307 foundNewInterface->addr,
308 foundNewInterface->flags);
309 if (CA_STATUS_OK != result)
314 // release foundNewInterface
315 OICFree(foundNewInterface);
316 foundNewInterface = NULL;
320 OICFree(foundNewInterface);
321 foundNewInterface = NULL;
322 u_arraylist_destroy(iflist);
326 u_arraylist_t *CAIPGetInterfaceInformation(int desiredIndex)
328 u_arraylist_t *iflist = u_arraylist_create();
331 OIC_LOG_V(ERROR, TAG, "Failed to create iflist: %s", strerror(errno));
335 char buf[MAX_INTERFACE_INFO_LENGTH] = { 0 };
336 struct ifconf ifc = { .ifc_len = MAX_INTERFACE_INFO_LENGTH, .ifc_buf = buf };
338 int s = caglobals.ip.u6.fd != -1 ? caglobals.ip.u6.fd : caglobals.ip.u4.fd;
339 if (ioctl(s, SIOCGIFCONF, &ifc) < 0)
341 OIC_LOG_V(ERROR, TAG, "SIOCGIFCONF failed: %s", strerror(errno));
342 u_arraylist_destroy(iflist);
346 struct ifreq* ifr = ifc.ifc_req;
347 size_t interfaces = ifc.ifc_len / sizeof (ifc.ifc_req[0]);
348 size_t ifreqsize = ifc.ifc_len;
350 if (ifreqsize > caglobals.ip.nm.sizeIfItems)
352 CAIfItem_t *items = (CAIfItem_t *)OICRealloc(caglobals.ip.nm.ifItems, ifreqsize);
355 OIC_LOG(ERROR, TAG, "OICRealloc failed");
358 caglobals.ip.nm.ifItems = items;
359 caglobals.ip.nm.sizeIfItems = ifreqsize;
362 caglobals.ip.nm.numIfItems = 0;
363 for (size_t i = 0; i < interfaces; i++)
365 struct ifreq* item = &ifr[i];
366 char *name = item->ifr_name;
368 if (ioctl(s, SIOCGIFFLAGS, item) < 0)
370 OIC_LOG_V(ERROR, TAG, "SIOCGIFFLAGS failed: %s", strerror(errno));
373 int16_t flags = item->ifr_flags;
374 if ((flags & IFF_LOOPBACK) || !(flags & IFF_RUNNING))
378 if (ioctl(s, SIOCGIFINDEX, item) < 0)
380 OIC_LOG_V(ERROR, TAG, "SIOCGIFINDEX failed: %s", strerror(errno));
384 int ifindex = item->ifr_ifindex;
385 caglobals.ip.nm.ifItems[i].ifIndex = ifindex;
386 caglobals.ip.nm.numIfItems++;
388 if (desiredIndex && (ifindex != desiredIndex))
393 // Get address of network interface.
394 char addr[MAX_ADDR_STR_SIZE_CA] = { 0 };
395 struct sockaddr_in *sa = (struct sockaddr_in *)&item->ifr_addr;
396 inet_ntop(AF_INET, (void *)&(sa->sin_addr), addr, sizeof(addr));
398 // Add IPv4 interface
399 CAResult_t result = CAAddInterfaceItem(iflist, ifindex, name, AF_INET, addr, flags);
400 if (CA_STATUS_OK != result)
405 // Add IPv6 interface
406 result = CAAddInterfaceItem(iflist, ifindex, name, AF_INET6, addr, flags);
407 if (CA_STATUS_OK != result)
415 u_arraylist_destroy(iflist);
419 static CAResult_t CAAddInterfaceItem(u_arraylist_t *iflist, int index,
420 const char *name, int family, const char *addr, int flags)
422 CAInterface_t *ifitem = CANewInterfaceItem(index, name, family, addr, flags);
425 return CA_STATUS_FAILED;
427 bool result = u_arraylist_add(iflist, ifitem);
430 OIC_LOG(ERROR, TAG, "u_arraylist_add failed.");
432 return CA_STATUS_FAILED;
438 static CAInterface_t *CANewInterfaceItem(int index, const char *name, int family,
439 const char *addr, int flags)
441 CAInterface_t *ifitem = (CAInterface_t *)OICCalloc(1, sizeof (CAInterface_t));
444 OIC_LOG(ERROR, TAG, "Malloc failed");
448 OICStrcpy(ifitem->name, sizeof (ifitem->name), name);
449 ifitem->index = index;
450 ifitem->family = family;
451 OICStrcpy(ifitem->addr, sizeof (ifitem->addr), addr);
452 ifitem->flags = flags;
457 CAResult_t CAIPJniInit()
459 OIC_LOG(DEBUG, TAG, "CAIPJniInit_IN");
461 JavaVM *jvm = CANativeJNIGetJavaVM();
464 OIC_LOG(ERROR, TAG, "Could not get JavaVM pointer");
465 return CA_STATUS_FAILED;
468 jobject context = CANativeJNIGetContext();
471 OIC_LOG(ERROR, TAG, "unable to get application context");
472 return CA_STATUS_FAILED;
476 if ((*jvm)->GetEnv(jvm, (void**) &env, JNI_VERSION_1_6) != JNI_OK)
478 OIC_LOG(ERROR, TAG, "Could not get JNIEnv pointer");
479 return CA_STATUS_FAILED;
482 jmethodID mid_getApplicationContext = CAGetJNIMethodID(env, "android/content/Context",
483 "getApplicationContext",
484 "()Landroid/content/Context;");
486 if (!mid_getApplicationContext)
488 OIC_LOG(ERROR, TAG, "Could not get getApplicationContext method");
489 return CA_STATUS_FAILED;
492 jobject jApplicationContext = (*env)->CallObjectMethod(env, context,
493 mid_getApplicationContext);
494 if (!jApplicationContext)
496 OIC_LOG(ERROR, TAG, "Could not get application context");
497 return CA_STATUS_FAILED;
500 jclass cls_CaIpInterface = (*env)->FindClass(env, "org/iotivity/ca/CaIpInterface");
501 if (!cls_CaIpInterface)
503 OIC_LOG(ERROR, TAG, "Could not get CaIpInterface class");
504 return CA_STATUS_FAILED;
507 jmethodID mid_CaIpInterface_ctor = (*env)->GetMethodID(env, cls_CaIpInterface, "<init>",
508 "(Landroid/content/Context;)V");
509 if (!mid_CaIpInterface_ctor)
511 OIC_LOG(ERROR, TAG, "Could not get CaIpInterface constructor method");
512 return CA_STATUS_FAILED;
515 (*env)->NewObject(env, cls_CaIpInterface, mid_CaIpInterface_ctor, jApplicationContext);
516 OIC_LOG(DEBUG, TAG, "Create CaIpInterface instance, success");
518 OIC_LOG(DEBUG, TAG, "CAIPJniInit_OUT");
522 static CAResult_t CAIPDestroyJniInterface()
524 OIC_LOG(DEBUG, TAG, "CAIPDestroyJniInterface");
526 JavaVM *jvm = CANativeJNIGetJavaVM();
529 OIC_LOG(ERROR, TAG, "Could not get JavaVM pointer");
530 return CA_STATUS_FAILED;
533 bool isAttached = false;
535 jint res = (*jvm)->GetEnv(jvm, (void**) &env, JNI_VERSION_1_6);
538 OIC_LOG(INFO, TAG, "Could not get JNIEnv pointer");
539 res = (*jvm)->AttachCurrentThread(jvm, &env, NULL);
543 OIC_LOG(ERROR, TAG, "AttachCurrentThread has failed");
544 return CA_STATUS_FAILED;
549 jclass jni_IpInterface = (*env)->FindClass(env, "org/iotivity/ca/CaIpInterface");
550 if (!jni_IpInterface)
552 OIC_LOG(ERROR, TAG, "Could not get CaIpInterface class");
556 jmethodID jni_InterfaceDestroyMethod = (*env)->GetStaticMethodID(env, jni_IpInterface,
557 "destroyIpInterface",
559 if (!jni_InterfaceDestroyMethod)
561 OIC_LOG(ERROR, TAG, "Could not get CaIpInterface destroy method");
565 (*env)->CallStaticVoidMethod(env, jni_IpInterface, jni_InterfaceDestroyMethod);
567 if ((*env)->ExceptionCheck(env))
569 OIC_LOG(ERROR, TAG, "destroyIpInterface has failed");
570 (*env)->ExceptionDescribe(env);
571 (*env)->ExceptionClear(env);
575 OIC_LOG(DEBUG, TAG, "Destroy instance for CaIpInterface");
579 (*jvm)->DetachCurrentThread(jvm);
588 (*jvm)->DetachCurrentThread(jvm);
591 return CA_STATUS_FAILED;
594 JNIEXPORT void JNICALL
595 Java_org_iotivity_ca_CaIpInterface_caIpStateEnabled(JNIEnv *env, jclass class)
600 OIC_LOG(DEBUG, TAG, "Wifi is in Activated State");
601 CAIPPassNetworkChangesToAdapter(CA_INTERFACE_UP);
604 JNIEXPORT void JNICALL
605 Java_org_iotivity_ca_CaIpInterface_caIpStateDisabled(JNIEnv *env, jclass class)
610 OIC_LOG(DEBUG, TAG, "Wifi is in Deactivated State");
611 CAIPPassNetworkChangesToAdapter(CA_INTERFACE_DOWN);