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>
33 #include "caadapterutils.h"
35 #include "oic_malloc.h"
36 #include "oic_string.h"
37 #include "org_iotivity_ca_CaIpInterface.h"
39 #define TAG "OIC_CA_IP_MONITOR"
41 static CAIPConnectionStateChangeCallback g_networkChangeCallback;
43 static CAInterface_t *CANewInterfaceItem(int index, const char *name, int family,
44 uint32_t addr, int flags);
46 static CAResult_t CAAddInterfaceItem(u_arraylist_t *iflist, int index,
47 const char *name, int family, uint32_t addr, int flags);
49 CAResult_t CAIPJniInit();
52 * destroy JNI interface.
53 * @return ::CA_STATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
55 static CAResult_t CAIPDestroyJniInterface();
57 #define MAX_INTERFACE_INFO_LENGTH 1024 // allows 32 interfaces from SIOCGIFCONF
59 CAResult_t CAIPStartNetworkMonitor()
64 CAResult_t CAIPStopNetworkMonitor()
66 return CAIPDestroyJniInterface();
69 int CAGetPollingInterval(int interval)
74 void CAIPSetNetworkMonitorCallback(CAIPConnectionStateChangeCallback callback)
76 g_networkChangeCallback = callback;
79 CAInterface_t *CAFindInterfaceChange()
81 char buf[MAX_INTERFACE_INFO_LENGTH] = { 0 };
82 struct ifconf ifc = { .ifc_len = MAX_INTERFACE_INFO_LENGTH, .ifc_buf = buf };
84 int s = caglobals.ip.u6.fd != -1 ? caglobals.ip.u6.fd : caglobals.ip.u4.fd;
85 if (ioctl(s, SIOCGIFCONF, &ifc) < 0)
87 OIC_LOG_V(ERROR, TAG, "SIOCGIFCONF failed: %s", strerror(errno));
91 CAInterface_t *foundNewInterface = NULL;
93 struct ifreq* ifr = ifc.ifc_req;
94 size_t interfaces = ifc.ifc_len / sizeof (ifc.ifc_req[0]);
95 size_t ifreqsize = ifc.ifc_len;
97 CAIfItem_t *previous = (CAIfItem_t *)OICMalloc(ifreqsize);
100 OIC_LOG(ERROR, TAG, "OICMalloc failed");
104 memcpy(previous, caglobals.ip.nm.ifItems, ifreqsize);
105 size_t numprevious = caglobals.ip.nm.numIfItems;
107 if (ifreqsize > caglobals.ip.nm.sizeIfItems)
110 CAIfItem_t *items = (CAIfItem_t *)OICRealloc(caglobals.ip.nm.ifItems, ifreqsize);
113 OIC_LOG(ERROR, TAG, "OICRealloc failed");
117 caglobals.ip.nm.ifItems = items;
118 caglobals.ip.nm.sizeIfItems = ifreqsize;
121 caglobals.ip.nm.numIfItems = 0;
122 for (size_t i = 0; i < interfaces; i++)
124 struct ifreq* item = &ifr[i];
125 char *name = item->ifr_name;
126 struct sockaddr_in *sa4 = (struct sockaddr_in *)&item->ifr_addr;
127 uint32_t ipv4addr = sa4->sin_addr.s_addr;
129 if (ioctl(s, SIOCGIFFLAGS, item) < 0)
131 OIC_LOG_V(ERROR, TAG, "SIOCGIFFLAGS failed: %s", strerror(errno));
134 int16_t flags = item->ifr_flags;
135 if ((flags & IFF_LOOPBACK) || !(flags & IFF_RUNNING))
139 if (ioctl(s, SIOCGIFINDEX, item) < 0)
141 OIC_LOG_V(ERROR, TAG, "SIOCGIFINDEX failed: %s", strerror(errno));
145 int ifIndex = item->ifr_ifindex;
146 caglobals.ip.nm.ifItems[i].ifIndex = ifIndex; // refill interface list
147 caglobals.ip.nm.numIfItems++;
149 if (foundNewInterface)
151 continue; // continue updating interface list
154 // see if this interface didn't previously exist
156 for (size_t j = 0; j < numprevious; j++)
158 if (ifIndex == previous[j].ifIndex)
166 OIC_LOG_V(INFO, TAG, "Interface found: %s", name);
170 foundNewInterface = CANewInterfaceItem(ifIndex, name, AF_INET, ipv4addr, flags);
174 return foundNewInterface;
177 u_arraylist_t *CAIPGetInterfaceInformation(int desiredIndex)
179 u_arraylist_t *iflist = u_arraylist_create();
182 OIC_LOG_V(ERROR, TAG, "Failed to create iflist: %s", strerror(errno));
186 char buf[MAX_INTERFACE_INFO_LENGTH] = { 0 };
187 struct ifconf ifc = { .ifc_len = MAX_INTERFACE_INFO_LENGTH, .ifc_buf = buf };
189 int s = caglobals.ip.u6.fd != -1 ? caglobals.ip.u6.fd : caglobals.ip.u4.fd;
190 if (ioctl(s, SIOCGIFCONF, &ifc) < 0)
192 OIC_LOG_V(ERROR, TAG, "SIOCGIFCONF failed: %s", strerror(errno));
193 u_arraylist_destroy(iflist);
197 struct ifreq* ifr = ifc.ifc_req;
198 size_t interfaces = ifc.ifc_len / sizeof (ifc.ifc_req[0]);
199 size_t ifreqsize = ifc.ifc_len;
201 if (ifreqsize > caglobals.ip.nm.sizeIfItems)
203 CAIfItem_t *items = (CAIfItem_t *)OICRealloc(caglobals.ip.nm.ifItems, ifreqsize);
206 OIC_LOG(ERROR, TAG, "OICRealloc failed");
209 caglobals.ip.nm.ifItems = items;
210 caglobals.ip.nm.sizeIfItems = ifreqsize;
213 caglobals.ip.nm.numIfItems = 0;
214 for (size_t i = 0; i < interfaces; i++)
216 CAResult_t result = CA_STATUS_OK;
217 struct ifreq* item = &ifr[i];
218 char *name = item->ifr_name;
219 struct sockaddr_in *sa4 = (struct sockaddr_in *)&item->ifr_addr;
220 uint32_t ipv4addr = sa4->sin_addr.s_addr;
222 if (ioctl(s, SIOCGIFFLAGS, item) < 0)
224 OIC_LOG_V(ERROR, TAG, "SIOCGIFFLAGS failed: %s", strerror(errno));
227 int16_t flags = item->ifr_flags;
228 if ((flags & IFF_LOOPBACK) || !(flags & IFF_RUNNING))
232 if (ioctl(s, SIOCGIFINDEX, item) < 0)
234 OIC_LOG_V(ERROR, TAG, "SIOCGIFINDEX failed: %s", strerror(errno));
238 int ifindex = item->ifr_ifindex;
239 caglobals.ip.nm.ifItems[i].ifIndex = ifindex;
240 caglobals.ip.nm.numIfItems++;
242 if (desiredIndex && (ifindex != desiredIndex))
247 // Add IPv4 interface
248 result = CAAddInterfaceItem(iflist, ifindex, name, AF_INET, ipv4addr, flags);
249 if (CA_STATUS_OK != result)
254 // Add IPv6 interface
255 result = CAAddInterfaceItem(iflist, ifindex, name, AF_INET6, ipv4addr, flags);
256 if (CA_STATUS_OK != result)
264 u_arraylist_destroy(iflist);
268 static CAResult_t CAAddInterfaceItem(u_arraylist_t *iflist, int index,
269 const char *name, int family, uint32_t addr, int flags)
271 CAInterface_t *ifitem = CANewInterfaceItem(index, name, family, addr, flags);
274 return CA_STATUS_FAILED;
276 bool result = u_arraylist_add(iflist, ifitem);
279 OIC_LOG(ERROR, TAG, "u_arraylist_add failed.");
281 return CA_STATUS_FAILED;
287 static CAInterface_t *CANewInterfaceItem(int index, const char *name, int family,
288 uint32_t addr, int flags)
290 CAInterface_t *ifitem = (CAInterface_t *)OICCalloc(1, sizeof (CAInterface_t));
293 OIC_LOG(ERROR, TAG, "Malloc failed");
297 OICStrcpy(ifitem->name, sizeof (ifitem->name), name);
298 ifitem->index = index;
299 ifitem->family = family;
300 ifitem->ipv4addr = addr;
301 ifitem->flags = flags;
306 CAResult_t CAIPJniInit()
308 OIC_LOG(DEBUG, TAG, "CAIPJniInit_IN");
310 JavaVM *jvm = CANativeJNIGetJavaVM();
313 OIC_LOG(ERROR, TAG, "Could not get JavaVM pointer");
314 return CA_STATUS_FAILED;
317 jobject context = CANativeJNIGetContext();
320 OIC_LOG(ERROR, TAG, "unable to get application context");
321 return CA_STATUS_FAILED;
325 if ((*jvm)->GetEnv(jvm, (void**) &env, JNI_VERSION_1_6) != JNI_OK)
327 OIC_LOG(ERROR, TAG, "Could not get JNIEnv pointer");
328 return CA_STATUS_FAILED;
331 jclass cls_Context = (*env)->FindClass(env, "android/content/Context");
334 OIC_LOG(ERROR, TAG, "Could not get context object class");
335 return CA_STATUS_FAILED;
338 jmethodID mid_getApplicationContext = (*env)->GetMethodID(env, cls_Context,
339 "getApplicationContext",
340 "()Landroid/content/Context;");
341 if (!mid_getApplicationContext)
343 OIC_LOG(ERROR, TAG, "Could not get getApplicationContext method");
344 return CA_STATUS_FAILED;
347 jobject jApplicationContext = (*env)->CallObjectMethod(env, context,
348 mid_getApplicationContext);
349 if (!jApplicationContext)
351 OIC_LOG(ERROR, TAG, "Could not get application context");
352 return CA_STATUS_FAILED;
355 jclass cls_CaIpInterface = (*env)->FindClass(env, "org/iotivity/ca/CaIpInterface");
356 if (!cls_CaIpInterface)
358 OIC_LOG(ERROR, TAG, "Could not get CaIpInterface class");
359 return CA_STATUS_FAILED;
362 jmethodID mid_CaIpInterface_ctor = (*env)->GetMethodID(env, cls_CaIpInterface, "<init>",
363 "(Landroid/content/Context;)V");
364 if (!mid_CaIpInterface_ctor)
366 OIC_LOG(ERROR, TAG, "Could not get CaIpInterface constructor method");
367 return CA_STATUS_FAILED;
370 (*env)->NewObject(env, cls_CaIpInterface, mid_CaIpInterface_ctor, jApplicationContext);
371 OIC_LOG(DEBUG, TAG, "Create CaIpInterface instance, success");
373 OIC_LOG(DEBUG, TAG, "CAIPJniInit_OUT");
377 static CAResult_t CAIPDestroyJniInterface()
379 OIC_LOG(DEBUG, TAG, "CAIPDestroyJniInterface");
381 JavaVM *jvm = CANativeJNIGetJavaVM();
384 OIC_LOG(ERROR, TAG, "Could not get JavaVM pointer");
385 return CA_STATUS_FAILED;
388 bool isAttached = false;
390 jint res = (*jvm)->GetEnv(jvm, (void**) &env, JNI_VERSION_1_6);
393 OIC_LOG(INFO, TAG, "Could not get JNIEnv pointer");
394 res = (*jvm)->AttachCurrentThread(jvm, &env, NULL);
398 OIC_LOG(ERROR, TAG, "AttachCurrentThread has failed");
399 return CA_STATUS_FAILED;
404 jclass jni_IpInterface = (*env)->FindClass(env, "org/iotivity/ca/CaIpInterface");
405 if (!jni_IpInterface)
407 OIC_LOG(ERROR, TAG, "Could not get CaIpInterface class");
411 jmethodID jni_InterfaceDestroyMethod = (*env)->GetStaticMethodID(env, jni_IpInterface,
412 "destroyIpInterface",
414 if (!jni_InterfaceDestroyMethod)
416 OIC_LOG(ERROR, TAG, "Could not get CaIpInterface destroy method");
420 (*env)->CallStaticVoidMethod(env, jni_IpInterface, jni_InterfaceDestroyMethod);
422 if ((*env)->ExceptionCheck(env))
424 OIC_LOG(ERROR, TAG, "destroyIpInterface has failed");
425 (*env)->ExceptionDescribe(env);
426 (*env)->ExceptionClear(env);
430 OIC_LOG(DEBUG, TAG, "Destroy instance for CaIpInterface");
434 (*jvm)->DetachCurrentThread(jvm);
443 (*jvm)->DetachCurrentThread(jvm);
446 return CA_STATUS_FAILED;
449 JNIEXPORT void JNICALL
450 Java_org_iotivity_ca_CaIpInterface_caIpStateEnabled(JNIEnv *env, jclass class)
455 OIC_LOG(DEBUG, TAG, "Wifi is in Activated State");
456 g_networkChangeCallback(CA_ADAPTER_IP, CA_INTERFACE_UP);
459 JNIEXPORT void JNICALL
460 Java_org_iotivity_ca_CaIpInterface_caIpStateDisabled(JNIEnv *env, jclass class)
465 OIC_LOG(DEBUG, TAG, "Wifi is in Deactivated State");
466 g_networkChangeCallback(CA_ADAPTER_IP, CA_INTERFACE_DOWN);