#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
-#include <sys/types.h>
#include <sys/select.h>
#include <ifaddrs.h>
#include <unistd.h>
#ifdef __linux__
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
-#include <arpa/inet.h>
-#include <netinet/in.h>
#endif
-#include "camutex.h"
+#include "octhread.h"
+#include "caipnwmonitor.h"
#include "caadapterutils.h"
#include "logger.h"
#include "oic_malloc.h"
#include "oic_string.h"
+#include <coap/utlist.h>
#define TAG "OIC_CA_IP_MONITOR"
/**
* Mutex for synchronizing access to cached interface and IP address information.
*/
-static ca_mutex g_networkMonitorContextMutex = NULL;
+static oc_mutex g_networkMonitorContextMutex = NULL;
/**
* Used to storing network interface.
*/
static u_arraylist_t *g_netInterfaceList = NULL;
-static CAIPConnectionStateChangeCallback g_networkChangeCallback = NULL;
+/**
+ * Used to storing adapter changes callback interface.
+ */
+static struct CAIPCBData_t *g_adapterCallbackList = NULL;
+/**
+ * Initialize the network interface monitoring list.
+ */
static CAResult_t CAIPInitializeNetworkMonitorList();
+
+/**
+ * Destroy the network interface monitoring list.
+ */
static void CAIPDestroyNetworkMonitorList();
+
+/**
+ * Compare the interface with the already added interface in list.
+ */
+static bool CACmpNetworkList(uint32_t ifiindex);
+
+/**
+ * Add new network interface in list.
+ */
+static CAResult_t CAAddNetworkMonitorList(CAInterface_t *ifitem);
+
+/**
+ * Remove network interace from list.
+ */
+static void CARemoveNetworkMonitorList(int ifiindex);
+
+/**
+ * Pass the changed network status through the stored callback.
+ */
+static void CAIPPassNetworkChangesToAdapter(CANetworkStatus_t status);
+
+/**
+ * Create new interface item.
+ */
static CAInterface_t *CANewInterfaceItem(int index, const char *name, int family,
- uint32_t addr, int flags);
+ const char *addr, int flags);
static CAResult_t CAIPInitializeNetworkMonitorList()
{
if (!g_networkMonitorContextMutex)
{
- g_networkMonitorContextMutex = ca_mutex_new();
+ g_networkMonitorContextMutex = oc_mutex_new();
if (!g_networkMonitorContextMutex)
{
- OIC_LOG(ERROR, TAG, "ca_mutex_new has failed");
+ OIC_LOG(ERROR, TAG, "oc_mutex_new has failed");
return CA_STATUS_FAILED;
}
}
if (g_networkMonitorContextMutex)
{
- ca_mutex_free(g_networkMonitorContextMutex);
+ oc_mutex_free(g_networkMonitorContextMutex);
g_networkMonitorContextMutex = NULL;
}
}
return false;
}
- ca_mutex_lock(g_networkMonitorContextMutex);
+ oc_mutex_lock(g_networkMonitorContextMutex);
uint32_t list_length = u_arraylist_length(g_netInterfaceList);
for (uint32_t list_index = 0; list_index < list_length; list_index++)
{
- CAInterface_t *currItem = (CAInterface_t *) u_arraylist_get(g_netInterfaceList, list_index);
+ CAInterface_t *currItem = (CAInterface_t *) u_arraylist_get(g_netInterfaceList,
+ list_index);
if (currItem->index == ifiindex)
{
- ca_mutex_unlock(g_networkMonitorContextMutex);
+ oc_mutex_unlock(g_networkMonitorContextMutex);
return true;
}
}
- ca_mutex_unlock(g_networkMonitorContextMutex);
+ oc_mutex_unlock(g_networkMonitorContextMutex);
return false;
}
VERIFY_NON_NULL(g_netInterfaceList, TAG, "g_netInterfaceList is NULL");
VERIFY_NON_NULL(ifitem, TAG, "ifitem is NULL");
- ca_mutex_lock(g_networkMonitorContextMutex);
+ oc_mutex_lock(g_networkMonitorContextMutex);
bool result = u_arraylist_add(g_netInterfaceList, (void *) ifitem);
if (!result)
{
OIC_LOG(ERROR, TAG, "u_arraylist_add failed.");
- ca_mutex_unlock(g_networkMonitorContextMutex);
+ oc_mutex_unlock(g_networkMonitorContextMutex);
return CA_STATUS_FAILED;
}
- ca_mutex_unlock(g_networkMonitorContextMutex);
+ oc_mutex_unlock(g_networkMonitorContextMutex);
return CA_STATUS_OK;
}
{
VERIFY_NON_NULL_VOID(g_netInterfaceList, TAG, "g_netInterfaceList is NULL");
- ca_mutex_lock(g_networkMonitorContextMutex);
+ oc_mutex_lock(g_networkMonitorContextMutex);
uint32_t list_length = u_arraylist_length(g_netInterfaceList);
for (uint32_t list_index = 0; list_index < list_length; list_index++)
if (u_arraylist_remove(g_netInterfaceList, list_index))
{
OICFree(removedifitem);
- ca_mutex_unlock(g_networkMonitorContextMutex);
+ oc_mutex_unlock(g_networkMonitorContextMutex);
return;
}
continue;
}
}
- ca_mutex_unlock(g_networkMonitorContextMutex);
+ oc_mutex_unlock(g_networkMonitorContextMutex);
return;
}
-CAResult_t CAIPStartNetworkMonitor()
+CAResult_t CAIPStartNetworkMonitor(CAIPAdapterStateChangeCallback callback,
+ CATransportAdapter_t adapter)
{
- return CAIPInitializeNetworkMonitorList();
+ CAResult_t res = CAIPInitializeNetworkMonitorList();
+ if (CA_STATUS_OK == res)
+ {
+ return CAIPSetNetworkMonitorCallback(callback, adapter);
+ }
+ return res;
}
-CAResult_t CAIPStopNetworkMonitor()
+CAResult_t CAIPStopNetworkMonitor(CATransportAdapter_t adapter)
{
CAIPDestroyNetworkMonitorList();
- return CA_STATUS_OK;
+ return CAIPUnSetNetworkMonitorCallback(adapter);
}
int CAGetPollingInterval(int interval)
return interval;
}
-void CAIPSetNetworkMonitorCallback(CAIPConnectionStateChangeCallback callback)
+static void CAIPPassNetworkChangesToAdapter(CANetworkStatus_t status)
+{
+ CAIPCBData_t *cbitem = NULL;
+ LL_FOREACH(g_adapterCallbackList, cbitem)
+ {
+ if (cbitem && cbitem->adapter)
+ {
+ cbitem->callback(cbitem->adapter, status);
+ CALogAdapterStateInfo(cbitem->adapter, status);
+ }
+ }
+}
+
+CAResult_t CAIPSetNetworkMonitorCallback(CAIPAdapterStateChangeCallback callback,
+ CATransportAdapter_t adapter)
+{
+ if (!callback)
+ {
+ OIC_LOG(ERROR, TAG, "callback is null");
+ return CA_STATUS_INVALID_PARAM;
+ }
+
+ CAIPCBData_t *cbitem = NULL;
+ LL_FOREACH(g_adapterCallbackList, cbitem)
+ {
+ if (cbitem && adapter == cbitem->adapter && callback == cbitem->callback)
+ {
+ OIC_LOG(DEBUG, TAG, "this callback is already added");
+ return CA_STATUS_OK;
+ }
+ }
+
+ cbitem = (CAIPCBData_t *)OICCalloc(1, sizeof(*cbitem));
+ if (!cbitem)
+ {
+ OIC_LOG(ERROR, TAG, "Malloc failed");
+ return CA_STATUS_FAILED;
+ }
+
+ cbitem->adapter = adapter;
+ cbitem->callback = callback;
+ LL_APPEND(g_adapterCallbackList, cbitem);
+
+ return CA_STATUS_OK;
+}
+
+CAResult_t CAIPUnSetNetworkMonitorCallback(CATransportAdapter_t adapter)
{
- g_networkChangeCallback = callback;
+ CAIPCBData_t *cbitem = NULL;
+ CAIPCBData_t *tmpCbitem = NULL;
+ LL_FOREACH_SAFE(g_adapterCallbackList, cbitem, tmpCbitem)
+ {
+ if (cbitem && adapter == cbitem->adapter)
+ {
+ OIC_LOG(DEBUG, TAG, "remove specific callback");
+ LL_DELETE(g_adapterCallbackList, cbitem);
+ OICFree(cbitem);
+ return CA_STATUS_OK;
+ }
+ }
+ return CA_STATUS_OK;
}
static CAInterface_t *CANewInterfaceItem(int index, const char *name, int family,
- uint32_t addr, int flags)
+ const char *addr, int flags)
{
CAInterface_t *ifitem = (CAInterface_t *)OICCalloc(1, sizeof (CAInterface_t));
if (!ifitem)
OICStrcpy(ifitem->name, sizeof (ifitem->name), name);
ifitem->index = index;
ifitem->family = family;
- ifitem->ipv4addr = addr;
+ OICStrcpy(ifitem->addr, sizeof (ifitem->addr), addr);
ifitem->flags = flags;
return ifitem;
}
-CAInterface_t *CAFindInterfaceChange()
+u_arraylist_t *CAFindInterfaceChange()
{
- CAInterface_t *foundNewInterface = NULL;
+ u_arraylist_t *iflist = NULL;
#ifdef __linux__
char buf[4096] = { 0 };
struct nlmsghdr *nh = NULL;
.msg_iov = &iov,
.msg_iovlen = 1 };
- size_t len = recvmsg(caglobals.ip.netlinkFd, &msg, 0);
+ ssize_t len = recvmsg(caglobals.ip.netlinkFd, &msg, 0);
for (nh = (struct nlmsghdr *)buf; NLMSG_OK(nh, len); nh = NLMSG_NEXT(nh, len))
{
- if (nh != NULL && nh->nlmsg_type != RTM_NEWLINK)
+ if (nh != NULL && (nh->nlmsg_type != RTM_DELADDR && nh->nlmsg_type != RTM_NEWADDR))
{
continue;
}
- struct ifinfomsg *ifi = (struct ifinfomsg *)NLMSG_DATA(nh);
-
- int ifiIndex = ifi->ifi_index;
- u_arraylist_t *iflist = CAIPGetInterfaceInformation(ifiIndex);
-
- if ((!ifi || (ifi->ifi_flags & IFF_LOOPBACK) || !(ifi->ifi_flags & IFF_RUNNING)))
+ if (RTM_DELADDR == nh->nlmsg_type)
{
+ struct ifaddrmsg *ifa = (struct ifaddrmsg *)NLMSG_DATA (nh);
+ int ifiIndex = ifa->ifa_index;
bool isFound = CACmpNetworkList(ifiIndex);
if (isFound)
{
CARemoveNetworkMonitorList(ifiIndex);
- if (g_networkChangeCallback)
- {
- g_networkChangeCallback(CA_ADAPTER_IP ,CA_INTERFACE_DOWN);
- }
+ CAIPPassNetworkChangesToAdapter(CA_INTERFACE_DOWN);
}
continue;
}
+ // Netlink message type is RTM_NEWADDR.
+ struct ifaddrmsg *ifa = (struct ifaddrmsg *)NLMSG_DATA (nh);
+ int ifiIndex = ifa->ifa_index;
+
+ iflist = CAIPGetInterfaceInformation(ifiIndex);
if (!iflist)
{
OIC_LOG_V(ERROR, TAG, "get interface info failed: %s", strerror(errno));
return NULL;
}
-
- 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)
- {
- continue;
- }
-
- if ((int)ifitem->index != ifiIndex)
- {
- continue;
- }
-
- foundNewInterface = CANewInterfaceItem(ifitem->index, ifitem->name, ifitem->family,
- ifitem->ipv4addr, ifitem->flags);
- break; // we found the one we were looking for
- }
- u_arraylist_destroy(iflist);
}
#endif
- return foundNewInterface;
+ return iflist;
}
u_arraylist_t *CAIPGetInterfaceInformation(int desiredIndex)
u_arraylist_destroy(iflist);
return NULL;
}
- OIC_LOG(DEBUG, TAG, "Got ifaddrs");
struct ifaddrs *ifa = NULL;
for (ifa = ifp; ifa; ifa = ifa->ifa_next)
OICStrcpy(ifitem->name, INTERFACE_NAME_MAX, ifa->ifa_name);
ifitem->index = ifindex;
ifitem->family = family;
- ifitem->ipv4addr = ((struct sockaddr_in *)(ifa->ifa_addr))->sin_addr.s_addr;
ifitem->flags = ifa->ifa_flags;
+ if (ifitem->family == AF_INET6)
+ {
+ struct sockaddr_in6 *in6 = (struct sockaddr_in6*) ifa->ifa_addr;
+ inet_ntop(ifitem->family, (void *)&(in6->sin6_addr), ifitem->addr,
+ sizeof(ifitem->addr));
+ }
+ else if (ifitem->family == AF_INET)
+ {
+ struct sockaddr_in *in = (struct sockaddr_in*) ifa->ifa_addr;
+ inet_ntop(ifitem->family, (void *)&(in->sin_addr), ifitem->addr,
+ sizeof(ifitem->addr));
+ }
+
bool result = u_arraylist_add(iflist, ifitem);
if (!result)
{
if (!isFound)
{
CAInterface_t *newifitem = CANewInterfaceItem(ifitem->index, ifitem->name, ifitem->family,
- ifitem->ipv4addr, ifitem->flags);
+ ifitem->addr, ifitem->flags);
CAResult_t ret = CAAddNetworkMonitorList(newifitem);
if (CA_STATUS_OK != ret)
{
OICFree(newifitem);
goto exit;
}
- if (g_networkChangeCallback)
- {
- g_networkChangeCallback(CA_ADAPTER_IP, CA_INTERFACE_UP);
- }
+ CAIPPassNetworkChangesToAdapter(CA_INTERFACE_UP);
OIC_LOG_V(DEBUG, TAG, "Added interface: %s (%d)", ifitem->name, ifitem->family);
}
}
+#ifndef __TIZENRT__
freeifaddrs(ifp);
+#endif
return iflist;
exit:
+#ifndef __TIZENRT__
freeifaddrs(ifp);
+#endif
u_arraylist_destroy(iflist);
return NULL;
}