#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();
+
+#define MAX_INTERFACE_INFO_LENGTH 1024 // allows 32 interfaces from SIOCGIFCONF
+
+CAResult_t CAIPInitializeNetworkMonitor()
+{
+ return CAIPJniInit();
+}
+
+CAResult_t CAIPTerminateNetworkMonitor()
+{
+ return CA_STATUS_OK;
+}
+
+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;
-}
-u_arraylist_t *CAIPGetInterfaceInformation(int desiredIndex)
-{
- if (desiredIndex < 0)
+ memcpy(previous, caglobals.ip.nm.ifItems, ifreqsize);
+ size_t numprevious = caglobals.ip.nm.numIfItems;
+
+ if (ifreqsize > caglobals.ip.nm.sizeIfItems)
{
- OIC_LOG_V(ERROR, TAG, "invalid index : %d", desiredIndex);
- return NULL;
+
+ 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)
+{
u_arraylist_t *iflist = u_arraylist_create();
if (!iflist)
{
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:
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;
+ }
+ CAResult_t result = u_arraylist_add(iflist, ifitem);
+ if (CA_STATUS_OK != 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;
+}
+
+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");
+
+ CAIPGetInterfaceInformation(0);
+}
#include "caipinterface.h"
-#ifndef __APPLE__
-#include <asm/types.h>
-#else
- #ifndef IPV6_ADD_MEMBERSHIP
- #define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
- #endif
-#endif
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
static void CAApplyInterfaces();
static void CAFindReadyMessage();
static void CASelectReturned(fd_set *readFds, int ret);
+static void CAProcessNewInterface(CAInterface_t *ifchanged);
static CAResult_t CAReceiveMessage(int fd, CATransportFlags_t flags);
#define SET(TYPE, FDS) \
}
else
{
+ CAInterface_t *ifchanged = CAFindInterfaceChange();
+ if (ifchanged)
+ {
+ CAProcessNewInterface(ifchanged);
+ }
break;
}
// create source of network interface change notifications
CAInitializeNetlink();
+ caglobals.ip.selectTimeout = CAGetPollingInterval(caglobals.ip.selectTimeout);
+
CAApplyInterfaces();
caglobals.ip.terminate = false;
OIC_LOG(DEBUG, TAG, "OUT");
}
+void CAWakeUpForChange()
+{
+ if (caglobals.ip.shutdownFds[1] != -1)
+ {
+ write(caglobals.ip.shutdownFds[1], "w", 1);
+ }
+}
+
static void applyMulticastToInterface4(struct in_addr inaddr)
{
if (!caglobals.ip.ipv4enabled)
struct ipv6_mreq mreq;
mreq.ipv6mr_multiaddr = *addr;
mreq.ipv6mr_interface = interface;
- if (setsockopt(fd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof (mreq)))
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof (mreq)))
{
if (EADDRINUSE != errno)
{
u_arraylist_destroy(iflist);
}
+static void CAProcessNewInterface(CAInterface_t *ifitem)
+{
+ applyMulticastToInterface6(ifitem->index);
+ struct in_addr inaddr;
+ inaddr.s_addr = ifitem->ipv4addr;
+ applyMulticastToInterface4(inaddr);
+}
+
static void CAHandleNetlink()
{
#ifdef __linux__
char buf[4096];
struct nlmsghdr *nh;
struct sockaddr_nl sa;
- struct iovec iov = { buf, sizeof(buf) };
- struct msghdr msg = { (void *)&sa, sizeof(sa), &iov, 1, NULL, 0, 0 };
+ struct iovec iov = { buf, sizeof (buf) };
+ struct msghdr msg = { (void *)&sa, sizeof (sa), &iov, 1, NULL, 0, 0 };
size_t len = recvmsg(caglobals.ip.netlinkFd, &msg, 0);
for (nh = (struct nlmsghdr *)buf; NLMSG_OK(nh, len); nh = NLMSG_NEXT(nh, len))
{
- if (nh->nlmsg_type == RTM_NEWLINK)
+ if (nh->nlmsg_type != RTM_NEWLINK)
{
- struct ifinfomsg *ifi = (struct ifinfomsg *)NLMSG_DATA(nh);
- if ((ifi->ifi_flags & IFF_LOOPBACK) || !(ifi->ifi_flags & IFF_RUNNING))
- {
- continue;
- }
+ continue;
+ }
- int newIndex = ifi->ifi_index;
+ struct ifinfomsg *ifi = (struct ifinfomsg *)NLMSG_DATA(nh);
+ if (!ifi || (ifi->ifi_flags & IFF_LOOPBACK) || !(ifi->ifi_flags & IFF_RUNNING))
+ {
+ continue;
+ }
- u_arraylist_t *iflist = CAIPGetInterfaceInformation(newIndex);
- if (!iflist)
+ int newIndex = ifi->ifi_index;
+
+ u_arraylist_t *iflist = CAIPGetInterfaceInformation(newIndex);
+ if (!iflist)
+ {
+ OIC_LOG_V(ERROR, TAG, "get interface info failed: %s", strerror(errno));
+ return;
+ }
+
+ uint32_t listLength = u_arraylist_length(iflist);
+ for (uint32_t i = 0; i < listLength; i++)
+ {
+ CAInterface_t *ifitem = (CAInterface_t *)u_arraylist_get(iflist, i);
+ if (!ifitem)
{
- OIC_LOG_V(ERROR, TAG, "get interface info failed: %s", strerror(errno));
- return;
+ continue;
}
- uint32_t listLength = u_arraylist_length(iflist);
- for (uint32_t i = 0; i < listLength; i++)
+ if ((int)ifitem->index != newIndex)
{
- CAInterface_t *ifitem = (CAInterface_t *)u_arraylist_get(iflist, i);
- if (!ifitem)
- {
- continue;
- }
-
- if ((int)ifitem->index != newIndex)
- {
- continue;
- }
-
- applyMulticastToInterface6(newIndex);
- struct in_addr inaddr;
- inaddr.s_addr = ifitem->ipv4addr;
- applyMulticastToInterface4(inaddr);
- break; // we found the one we were looking for
+ continue;
}
- u_arraylist_destroy(iflist);
+
+ CAProcessNewInterface(ifitem);
+ break; // we found the one we were looking for
}
+ u_arraylist_destroy(iflist);
}
#endif // __linux__
}