Merge branch 'master' into simulator
[platform/upstream/iotivity.git] / resource / csdk / connectivity / src / ip_adapter / android / caipnwmonitor.c
old mode 100644 (file)
new mode 100755 (executable)
index da57dc1..7df7585
@@ -21,7 +21,6 @@
 #include "caipinterface.h"
 
 #include <sys/types.h>
-#include <ifaddrs.h>
 #include <sys/socket.h>
 #include <netdb.h>
 #include <string.h>
 #include "logger.h"
 #include "oic_malloc.h"
 #include "oic_string.h"
+#include "org_iotivity_ca_CaIpInterface.h"
 
 #define TAG "IP_MONITOR"
 
-char *getHostIPAddress(const char *ifa_name) {
-    static char address[INET_ADDRSTRLEN] = {};
-    memset(&address, 0, INET_ADDRSTRLEN);
-    struct ifreq ifr;
-    int sck, status, len = sizeof(ifr.ifr_name) - 1;
-    char *ip;
+static CAInterface_t *CANewInterfaceItem(int index, const char *name, int family,
+                                         uint32_t addr, int flags);
 
-    if ((sck = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+static CAResult_t CAAddInterfaceItem(u_arraylist_t *iflist, int index,
+                            const char *name, int family, uint32_t addr, int flags);
+
+CAResult_t CAIPJniInit();
+
+/**
+ * destroy JNI interface.
+ * @return  ::CA_STATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
+ */
+static CAResult_t CAIPDestroyJniInterface();
+
+#define MAX_INTERFACE_INFO_LENGTH 1024 // allows 32 interfaces from SIOCGIFCONF
+
+CAResult_t CAIPStartNetworkMonitor()
+{
+    return CAIPJniInit();
+}
+
+CAResult_t CAIPStopNetworkMonitor()
+{
+    return CAIPDestroyJniInterface();
+}
+
+int CAGetPollingInterval(int interval)
+{
+    return interval;
+}
+
+CAInterface_t *CAFindInterfaceChange()
+{
+    char buf[MAX_INTERFACE_INFO_LENGTH] = { 0 };
+    struct ifconf ifc  = { .ifc_len = MAX_INTERFACE_INFO_LENGTH, .ifc_buf = buf };
+
+    int s = caglobals.ip.u6.fd != -1 ? caglobals.ip.u6.fd : caglobals.ip.u4.fd;
+    if (ioctl(s, SIOCGIFCONF, &ifc) < 0)
+    {
+        OIC_LOG_V(ERROR, TAG, "SIOCGIFCONF failed: %s", strerror(errno));
         return NULL;
     }
 
-    strncpy(ifr.ifr_name, ifa_name, len);
-    ifr.ifr_name[len] = '\0';
-    if ((status = ioctl(sck, SIOCGIFADDR, &ifr)) < 0) {
-        close(sck);
+    CAInterface_t *foundNewInterface = NULL;
+
+    struct ifreq* ifr = ifc.ifc_req;
+    size_t interfaces = ifc.ifc_len / sizeof (ifc.ifc_req[0]);
+    size_t ifreqsize = ifc.ifc_len;
+
+    CAIfItem_t *previous = (CAIfItem_t *)OICMalloc(ifreqsize);
+    if (!previous)
+    {
+        OIC_LOG(ERROR, TAG, "OICMalloc failed");
         return NULL;
     }
-    close(sck);
-    ip = inet_ntoa(((struct sockaddr_in *)(&ifr.ifr_addr))->sin_addr);
-    len = sizeof(address) - 1;
-    strncpy(address, ip, len);
-    address[len] = '\0';
-    return address;
+
+    memcpy(previous, caglobals.ip.nm.ifItems, ifreqsize);
+    size_t numprevious = caglobals.ip.nm.numIfItems;
+
+    if (ifreqsize > caglobals.ip.nm.sizeIfItems)
+    {
+
+        CAIfItem_t *items = (CAIfItem_t *)OICRealloc(caglobals.ip.nm.ifItems, ifreqsize);
+        if (!items)
+        {
+            OIC_LOG(ERROR, TAG, "OICRealloc failed");
+            OICFree(previous);
+            return NULL;
+        }
+        caglobals.ip.nm.ifItems = items;
+        caglobals.ip.nm.sizeIfItems = ifreqsize;
+    }
+
+    caglobals.ip.nm.numIfItems = 0;
+    for (size_t i = 0; i < interfaces; i++)
+    {
+        struct ifreq* item = &ifr[i];
+        char *name = item->ifr_name;
+        struct sockaddr_in *sa4 = (struct sockaddr_in *)&item->ifr_addr;
+        uint32_t ipv4addr = sa4->sin_addr.s_addr;
+
+        if (ioctl(s, SIOCGIFFLAGS, item) < 0)
+        {
+            OIC_LOG_V(ERROR, TAG, "SIOCGIFFLAGS failed: %s", strerror(errno));
+            continue;
+        }
+        int16_t flags = item->ifr_flags;
+        if ((flags & IFF_LOOPBACK) || !(flags & IFF_RUNNING))
+        {
+            continue;
+        }
+        if (ioctl(s, SIOCGIFINDEX, item) < 0)
+        {
+            OIC_LOG_V(ERROR, TAG, "SIOCGIFINDEX failed: %s", strerror(errno));
+            continue;
+        }
+
+        int ifIndex = item->ifr_ifindex;
+        caglobals.ip.nm.ifItems[i].ifIndex = ifIndex;  // refill interface list
+        caglobals.ip.nm.numIfItems++;
+
+        if (foundNewInterface)
+        {
+            continue;   // continue updating interface list
+        }
+
+        // see if this interface didn't previously exist
+        bool found = false;
+        for (size_t j = 0; j < numprevious; j++)
+        {
+            if (ifIndex == previous[j].ifIndex)
+            {
+                found = true;
+                break;
+            }
+        }
+        if (found)
+        {
+            OIC_LOG_V(INFO, TAG, "Interface found: %s", name);
+            continue;
+        }
+
+        foundNewInterface = CANewInterfaceItem(ifIndex, name, AF_INET, ipv4addr, flags);
+    }
+
+    OICFree(previous);
+    return foundNewInterface;
 }
 
 u_arraylist_t *CAIPGetInterfaceInformation(int desiredIndex)
@@ -72,34 +176,81 @@ u_arraylist_t *CAIPGetInterfaceInformation(int desiredIndex)
         return NULL;
     }
 
-    char* ipAddr = getHostIPAddress("wlan0");
-    if (NULL == ipAddr)
+    char buf[MAX_INTERFACE_INFO_LENGTH] = { 0 };
+    struct ifconf ifc = { .ifc_len = MAX_INTERFACE_INFO_LENGTH, .ifc_buf = buf };
+
+    int s = caglobals.ip.u6.fd != -1 ? caglobals.ip.u6.fd : caglobals.ip.u4.fd;
+    if (ioctl(s, SIOCGIFCONF, &ifc) < 0)
     {
-        OIC_LOG_V(ERROR, TAG, "Failed to get ifaddrs: %s", strerror(errno));
+        OIC_LOG_V(ERROR, TAG, "SIOCGIFCONF failed: %s", strerror(errno));
         u_arraylist_destroy(iflist);
         return NULL;
     }
-    OIC_LOG_V(DEBUG, TAG, "Got ifaddrs:: %s", ipAddr);
-
-    struct in_addr inaddr;
-    inet_pton(AF_INET, ipAddr, &(inaddr));
 
-    CAInterface_t *ifitem = (CAInterface_t *)OICCalloc(1, sizeof(CAInterface_t));;
-    OICStrcpy(ifitem->name, INTERFACE_NAME_MAX, "wlan0");
-    ifitem->index = 0; //if_nametoindex("wlan0");
-    ifitem->family = AF_INET; //we support ipv4 only
-    ifitem->ipv4addr = inaddr.s_addr;
-    ifitem->flags = IFF_UP|IFF_RUNNING;
+    struct ifreq* ifr = ifc.ifc_req;
+    size_t interfaces = ifc.ifc_len / sizeof (ifc.ifc_req[0]);
+    size_t ifreqsize = ifc.ifc_len;
 
-    CAResult_t result = u_arraylist_add(iflist, ifitem);
-    if (CA_STATUS_OK != result)
+    if (ifreqsize > caglobals.ip.nm.sizeIfItems)
     {
-        OIC_LOG(ERROR, TAG, "u_arraylist_add failed.");
-        goto exit;
+        CAIfItem_t *items = (CAIfItem_t *)OICRealloc(caglobals.ip.nm.ifItems, ifreqsize);
+        if (!items)
+        {
+            OIC_LOG(ERROR, TAG, "OICRealloc failed");
+            goto exit;
+        }
+        caglobals.ip.nm.ifItems = items;
+        caglobals.ip.nm.sizeIfItems = ifreqsize;
     }
 
-    OIC_LOG_V(ERROR, TAG, "Added interface: %s (%d)", ifitem->name, ifitem->family);
+    caglobals.ip.nm.numIfItems = 0;
+    for (size_t i = 0; i < interfaces; i++)
+    {
+        CAResult_t result = CA_STATUS_OK;
+        struct ifreq* item = &ifr[i];
+        char *name = item->ifr_name;
+        struct sockaddr_in *sa4 = (struct sockaddr_in *)&item->ifr_addr;
+        uint32_t ipv4addr = sa4->sin_addr.s_addr;
+
+        if (ioctl(s, SIOCGIFFLAGS, item) < 0)
+        {
+            OIC_LOG_V(ERROR, TAG, "SIOCGIFFLAGS failed: %s", strerror(errno));
+            continue;
+        }
+        int16_t flags = item->ifr_flags;
+        if ((flags & IFF_LOOPBACK) || !(flags & IFF_RUNNING))
+        {
+            continue;
+        }
+        if (ioctl(s, SIOCGIFINDEX, item) < 0)
+        {
+            OIC_LOG_V(ERROR, TAG, "SIOCGIFINDEX failed: %s", strerror(errno));
+            continue;
+        }
+
+        int ifindex = item->ifr_ifindex;
+        caglobals.ip.nm.ifItems[i].ifIndex = ifindex;
+        caglobals.ip.nm.numIfItems++;
+
+        if (desiredIndex && (ifindex != desiredIndex))
+        {
+            continue;
+        }
+
+        // Add IPv4 interface
+        result = CAAddInterfaceItem(iflist, ifindex, name, AF_INET, ipv4addr, flags);
+        if (CA_STATUS_OK != result)
+        {
+            goto exit;
+        }
 
+        // Add IPv6 interface
+        result = CAAddInterfaceItem(iflist, ifindex, name, AF_INET6, ipv4addr, flags);
+        if (CA_STATUS_OK != result)
+        {
+            goto exit;
+        }
+    }
     return iflist;
 
 exit:
@@ -107,3 +258,209 @@ exit:
     return NULL;
 }
 
+static CAResult_t CAAddInterfaceItem(u_arraylist_t *iflist, int index,
+                            const char *name, int family, uint32_t addr, int flags)
+{
+    CAInterface_t *ifitem = CANewInterfaceItem(index, name, family, addr, flags);
+    if (!ifitem)
+    {
+        return CA_STATUS_FAILED;
+    }
+    bool result = u_arraylist_add(iflist, ifitem);
+    if (!result)
+    {
+        OIC_LOG(ERROR, TAG, "u_arraylist_add failed.");
+        OICFree(ifitem);
+        return CA_STATUS_FAILED;
+    }
+
+    return CA_STATUS_OK;
+}
+
+static CAInterface_t *CANewInterfaceItem(int index, const char *name, int family,
+                                         uint32_t addr, int flags)
+{
+    CAInterface_t *ifitem = (CAInterface_t *)OICCalloc(1, sizeof (CAInterface_t));
+    if (!ifitem)
+    {
+        OIC_LOG(ERROR, TAG, "Malloc failed");
+        return NULL;
+    }
+
+    OICStrcpy(ifitem->name, sizeof (ifitem->name), name);
+    ifitem->index = index;
+    ifitem->family = family;
+    ifitem->ipv4addr = addr;
+    ifitem->flags = flags;
+
+    return ifitem;
+}
+
+CAResult_t CAIPJniInit()
+{
+    OIC_LOG(DEBUG, TAG, "CAIPJniInit_IN");
+
+    JavaVM *jvm = CANativeJNIGetJavaVM();
+    if (!jvm)
+    {
+        OIC_LOG(ERROR, TAG, "Could not get JavaVM pointer");
+        return CA_STATUS_FAILED;
+    }
+
+    jobject context = CANativeJNIGetContext();
+    if (!context)
+    {
+        OIC_LOG(ERROR, TAG, "unable to get application context");
+        return CA_STATUS_FAILED;
+    }
+
+    JNIEnv* env;
+    if ((*jvm)->GetEnv(jvm, (void**) &env, JNI_VERSION_1_6) != JNI_OK)
+    {
+        OIC_LOG(ERROR, TAG, "Could not get JNIEnv pointer");
+        return CA_STATUS_FAILED;
+    }
+
+    jclass cls_Context = (*env)->FindClass(env, "android/content/Context");
+    if (!cls_Context)
+    {
+        OIC_LOG(ERROR, TAG, "Could not get context object class");
+        return CA_STATUS_FAILED;
+    }
+
+    jmethodID mid_getApplicationContext = (*env)->GetMethodID(env, cls_Context,
+                                                                "getApplicationContext",
+                                                                "()Landroid/content/Context;");
+    if (!mid_getApplicationContext)
+    {
+        OIC_LOG(ERROR, TAG, "Could not get getApplicationContext method");
+        return CA_STATUS_FAILED;
+    }
+
+    jobject jApplicationContext = (*env)->CallObjectMethod(env, context,
+                                                           mid_getApplicationContext);
+    if (!jApplicationContext)
+    {
+        OIC_LOG(ERROR, TAG, "Could not get application context");
+        return CA_STATUS_FAILED;
+    }
+
+    jclass cls_CaIpInterface = (*env)->FindClass(env, "org/iotivity/ca/CaIpInterface");
+    if (!cls_CaIpInterface)
+    {
+        OIC_LOG(ERROR, TAG, "Could not get CaIpInterface class");
+        return CA_STATUS_FAILED;
+    }
+
+    jmethodID mid_CaIpInterface_ctor = (*env)->GetMethodID(env, cls_CaIpInterface, "<init>",
+                                                                   "(Landroid/content/Context;)V");
+    if (!mid_CaIpInterface_ctor)
+    {
+        OIC_LOG(ERROR, TAG, "Could not get CaIpInterface constructor method");
+        return CA_STATUS_FAILED;
+    }
+
+    (*env)->NewObject(env, cls_CaIpInterface, mid_CaIpInterface_ctor, jApplicationContext);
+    OIC_LOG(DEBUG, TAG, "Create CaIpInterface instance, success");
+
+    OIC_LOG(DEBUG, TAG, "CAIPJniInit_OUT");
+    return CA_STATUS_OK;
+}
+
+static CAResult_t CAIPDestroyJniInterface()
+{
+    OIC_LOG(DEBUG, TAG, "CAIPDestroyJniInterface");
+
+    JavaVM *jvm = CANativeJNIGetJavaVM();
+    if (!jvm)
+    {
+        OIC_LOG(ERROR, TAG, "Could not get JavaVM pointer");
+        return CA_STATUS_FAILED;
+    }
+
+    bool isAttached = false;
+    JNIEnv* env;
+    jint res = (*jvm)->GetEnv(jvm, (void**) &env, JNI_VERSION_1_6);
+    if (JNI_OK != res)
+    {
+        OIC_LOG(INFO, TAG, "Could not get JNIEnv pointer");
+        res = (*jvm)->AttachCurrentThread(jvm, &env, NULL);
+
+        if (JNI_OK != res)
+        {
+            OIC_LOG(ERROR, TAG, "AttachCurrentThread has failed");
+            return CA_STATUS_FAILED;
+        }
+        isAttached = true;
+    }
+
+    jclass jni_IpInterface = (*env)->FindClass(env, "org/iotivity/ca/CaIpInterface");
+    if (!jni_IpInterface)
+    {
+        OIC_LOG(ERROR, TAG, "Could not get CaIpInterface class");
+        goto error_exit;
+    }
+
+    jmethodID jni_InterfaceDestroyMethod = (*env)->GetStaticMethodID(env, jni_IpInterface,
+                                                                     "destroyIpInterface",
+                                                                     "()V");
+    if (!jni_InterfaceDestroyMethod)
+    {
+        OIC_LOG(ERROR, TAG, "Could not get CaIpInterface destroy method");
+        goto error_exit;
+    }
+
+    (*env)->CallStaticVoidMethod(env, jni_IpInterface, jni_InterfaceDestroyMethod);
+
+    if ((*env)->ExceptionCheck(env))
+    {
+        OIC_LOG(ERROR, TAG, "destroyIpInterface has failed");
+        (*env)->ExceptionDescribe(env);
+        (*env)->ExceptionClear(env);
+        goto error_exit;
+    }
+
+    OIC_LOG(DEBUG, TAG, "Destroy instance for CaIpInterface");
+
+    if (isAttached)
+    {
+        (*jvm)->DetachCurrentThread(jvm);
+    }
+
+    return CA_STATUS_OK;
+
+error_exit:
+
+    if (isAttached)
+    {
+        (*jvm)->DetachCurrentThread(jvm);
+    }
+
+    return CA_STATUS_FAILED;
+}
+
+JNIEXPORT void JNICALL
+Java_org_iotivity_ca_CaIpInterface_caIpStateEnabled(JNIEnv *env, jclass class)
+{
+    (void)env;
+    (void)class;
+    OIC_LOG(DEBUG, TAG, "caIpStateEnabled");
+
+    CAWakeUpForChange();
+}
+
+JNIEXPORT void JNICALL
+Java_org_iotivity_ca_CaIpInterface_caIpStateDisabled(JNIEnv *env, jclass class)
+{
+    (void)env;
+    (void)class;
+    OIC_LOG(DEBUG, TAG, "caIpStateDisabled");
+
+    u_arraylist_t *iflist = CAIPGetInterfaceInformation(0);
+    if (!iflist)
+    {
+        OIC_LOG_V(ERROR, TAG, "get interface info failed");
+        return;
+    }
+    u_arraylist_destroy(iflist);
+}