Replace os_sockQueryInterfaces by os_getifaddrs

Signed-off-by: Jeroen Koekkoek <jeroen@koekkoek.nl>
This commit is contained in:
Jeroen Koekkoek 2018-09-19 19:25:58 +02:00
parent 2fc4cac1a7
commit 458b1df3f7
23 changed files with 696 additions and 597 deletions

View file

@ -17,7 +17,7 @@
enum ddsi_nearby_address_result ddsi_ipaddr_is_nearby_address (ddsi_tran_factory_t tran, const nn_locator_t *loc, size_t ninterf, const struct nn_interface interf[]);
enum ddsi_locator_from_string_result ddsi_ipaddr_from_string (ddsi_tran_factory_t tran, nn_locator_t *loc, const char *str, int32_t kind);
char *ddsi_ipaddr_to_string (ddsi_tran_factory_t tran, char *dst, size_t sizeof_dst, const nn_locator_t *loc, int with_port);
void ddsi_ipaddr_to_loc (nn_locator_t *dst, const os_sockaddr_storage *src, int32_t kind);
void ddsi_ipaddr_to_loc (nn_locator_t *dst, const os_sockaddr *src, int32_t kind);
void ddsi_ipaddr_from_loc (os_sockaddr_storage *dst, const nn_locator_t *src);
#endif

View file

@ -75,7 +75,7 @@ typedef enum ddsi_locator_from_string_result (*ddsi_locator_from_string_fn_t) (d
typedef char * (*ddsi_locator_to_string_fn_t) (ddsi_tran_factory_t tran, char *dst, size_t sizeof_dst, const nn_locator_t *loc, int with_port);
typedef int (*ddsi_enumerate_interfaces_fn_t) (ddsi_tran_factory_t tran, int max, struct os_ifAttributes_s *interfs);
typedef int (*ddsi_enumerate_interfaces_fn_t) (ddsi_tran_factory_t tran, os_ifaddrs_t **interfs);
/* Data types */
@ -237,7 +237,7 @@ enum ddsi_locator_from_string_result ddsi_locator_from_string (nn_locator_t *loc
char *ddsi_locator_to_string (char *dst, size_t sizeof_dst, const nn_locator_t *loc);
char *ddsi_locator_to_string_no_port (char *dst, size_t sizeof_dst, const nn_locator_t *loc);
int ddsi_enumerate_interfaces (ddsi_tran_factory_t factory, int max, struct os_ifAttributes_s *interfs);
int ddsi_enumerate_interfaces (ddsi_tran_factory_t factory, os_ifaddrs_t **interfs);
#define ddsi_listener_locator(s,l) (ddsi_tran_locator (&(s)->m_base,(l)))
ddsi_tran_conn_t ddsi_listener_accept (ddsi_tran_listener_t listener);

View file

@ -49,7 +49,7 @@ enum ddsi_locator_from_string_result ddsi_ipaddr_from_string (ddsi_tran_factory_
return AFSR_INVALID;
if ((ipv4 && tmpaddr.ss_family != AF_INET) || (!ipv4 && tmpaddr.ss_family != AF_INET6))
return AFSR_MISMATCH;
ddsi_ipaddr_to_loc (loc, &tmpaddr, kind);
ddsi_ipaddr_to_loc (loc, (os_sockaddr *)&tmpaddr, kind);
/* This is just an address, so there is no valid value for port, other than INVALID.
Without a guarantee that tmpaddr has port 0, best is to set it explicitly here */
loc->port = NN_LOCATOR_PORT_INVALID;
@ -94,10 +94,10 @@ char *ddsi_ipaddr_to_string (ddsi_tran_factory_t tran, char *dst, size_t sizeof_
return dst;
}
void ddsi_ipaddr_to_loc (nn_locator_t *dst, const os_sockaddr_storage *src, int32_t kind)
void ddsi_ipaddr_to_loc (nn_locator_t *dst, const os_sockaddr *src, int32_t kind)
{
dst->kind = kind;
switch (src->ss_family)
switch (src->sa_family)
{
case AF_INET:
{
@ -137,7 +137,7 @@ void ddsi_ipaddr_to_loc (nn_locator_t *dst, const os_sockaddr_storage *src, int3
}
#endif
default:
NN_FATAL ("nn_address_to_loc: family %d unsupported\n", (int) src->ss_family);
NN_FATAL ("nn_address_to_loc: family %d unsupported\n", (int) src->sa_family);
}
}

View file

@ -347,42 +347,23 @@ static void ddsi_raweth_deinit(void)
}
}
static int ddsi_raweth_enumerate_interfaces (ddsi_tran_factory_t factory, int max, struct os_ifAttributes_s *interfs)
static int ddsi_raweth_enumerate_interfaces (ddsi_tran_factory_t factory, os_ifaddrs_t **interfs)
{
struct ifaddrs *ifaddr, *ifa;
int err = 0;
int cnt = 0;
os_ifaddrs_t *ifa;
os_ifaddr_filter_t filt = { .af_packet = 1 };
(void)factory;
if (getifaddrs (&ifaddr) == -1)
return -errno;
for (ifa = ifaddr; ifa && cnt < max; ifa = ifa->ifa_next)
{
struct os_ifAttributes_s *f = &interfs[cnt];
struct sockaddr_ll *x;
if (ifa->ifa_addr == NULL)
continue;
if (ifa->ifa_addr->sa_family != AF_PACKET)
continue;
if ((ifa->ifa_flags & (IFF_UP | IFF_BROADCAST)) != (IFF_UP | IFF_BROADCAST))
continue;
strncpy(f->name, ifa->ifa_name, sizeof(f->name));
f->name[sizeof(f->name)-1] = 0;
f->flags = ifa->ifa_flags;
f->interfaceIndexNo = if_nametoindex(f->name);
x = (struct sockaddr_ll *)&f->address;
memcpy(x, ifa->ifa_addr, sizeof (*x));
x = (struct sockaddr_ll *)&f->network_mask;
if (ifa->ifa_netmask)
memcpy(x, ifa->ifa_netmask, sizeof (*x));
else
memset(x, 0, sizeof(*x));
x = (struct sockaddr_ll *)&f->broadcast_address;
if (ifa->ifa_broadaddr)
memcpy(x, ifa->ifa_broadaddr, sizeof (*x));
else
memset(x, 0, sizeof(*x));
cnt++;
if ((err = os_getifaddrs(interfs, &filt)) == 0) {
for (ifa = *interfs; ifa != NULL; ifa = ifa->next, cnt++) {
/* do nothing */
}
freeifaddrs (ifaddr);
} else {
return -err;
}
return cnt;
}

View file

@ -145,7 +145,7 @@ static ddsi_tcp_conn_t ddsi_tcp_new_conn (os_socket, bool, os_sockaddr_storage *
static char *sockaddr_to_string_with_port (char *dst, size_t sizeof_dst, const os_sockaddr_storage *src)
{
nn_locator_t loc;
ddsi_ipaddr_to_loc(&loc, src, src->ss_family == AF_INET ? NN_LOCATOR_KIND_TCPv4 : NN_LOCATOR_KIND_TCPv6);
ddsi_ipaddr_to_loc(&loc, (const os_sockaddr *)src, src->ss_family == AF_INET ? NN_LOCATOR_KIND_TCPv4 : NN_LOCATOR_KIND_TCPv6);
ddsi_locator_to_string(dst, sizeof_dst, &loc);
return dst;
}
@ -452,7 +452,7 @@ static ssize_t ddsi_tcp_conn_read (ddsi_tran_conn_t conn, unsigned char * buf, s
{
if (srcloc)
{
ddsi_ipaddr_to_loc(srcloc, &tcp->m_peer_addr, tcp->m_peer_addr.ss_family == AF_INET ? NN_LOCATOR_KIND_TCPv4 : NN_LOCATOR_KIND_TCPv6);
ddsi_ipaddr_to_loc(srcloc, (os_sockaddr *)&tcp->m_peer_addr, tcp->m_peer_addr.ss_family == AF_INET ? NN_LOCATOR_KIND_TCPv4 : NN_LOCATOR_KIND_TCPv6);
}
return (ssize_t) pos;
}
@ -869,7 +869,7 @@ static void ddsi_tcp_conn_peer_locator (ddsi_tran_conn_t conn, nn_locator_t * lo
char buff[DDSI_LOCSTRLEN];
ddsi_tcp_conn_t tc = (ddsi_tcp_conn_t) conn;
assert (tc->m_sock != Q_INVALID_SOCKET);
ddsi_ipaddr_to_loc (loc, &tc->m_peer_addr, tc->m_peer_addr.ss_family == AF_INET ? NN_LOCATOR_KIND_TCPv4 : NN_LOCATOR_KIND_TCPv6);
ddsi_ipaddr_to_loc (loc, (os_sockaddr *)&tc->m_peer_addr, tc->m_peer_addr.ss_family == AF_INET ? NN_LOCATOR_KIND_TCPv4 : NN_LOCATOR_KIND_TCPv6);
ddsi_locator_to_string(buff, sizeof(buff), loc);
TRACE (("(%s EP:%s)", ddsi_name, buff));
}
@ -976,7 +976,7 @@ static void ddsi_tcp_close_conn (ddsi_tran_conn_t tc)
sockaddr_to_string_with_port(buff, sizeof(buff), &conn->m_peer_addr);
nn_log (LC_INFO, "%s close %s connnection on socket %"PRIsock" to %s\n", ddsi_name, conn->m_base.m_server ? "server" : "client", conn->m_sock, buff);
(void) shutdown (conn->m_sock, 2);
ddsi_ipaddr_to_loc(&loc, &conn->m_peer_addr, conn->m_peer_addr.ss_family == AF_INET ? NN_LOCATOR_KIND_TCPv4 : NN_LOCATOR_KIND_TCPv6);
ddsi_ipaddr_to_loc(&loc, (os_sockaddr *)&conn->m_peer_addr, conn->m_peer_addr.ss_family == AF_INET ? NN_LOCATOR_KIND_TCPv4 : NN_LOCATOR_KIND_TCPv6);
loc.port = conn->m_peer_port;
purge_proxy_participants (&loc, conn->m_base.m_server);
}

View file

@ -332,10 +332,10 @@ char *ddsi_locator_to_string_no_port (char *dst, size_t sizeof_dst, const nn_loc
return dst;
}
int ddsi_enumerate_interfaces (ddsi_tran_factory_t factory, int max, struct os_ifAttributes_s *interfs)
int ddsi_enumerate_interfaces (ddsi_tran_factory_t factory, os_ifaddrs_t **interfs)
{
/* FIXME: HACK */
if (factory->m_enumerate_interfaces_fn == 0)
return 0;
return factory->m_enumerate_interfaces_fn (factory, max, interfs);
return factory->m_enumerate_interfaces_fn (factory, interfs);
}

View file

@ -79,7 +79,7 @@ static ssize_t ddsi_udp_conn_read (ddsi_tran_conn_t conn, unsigned char * buf, s
if (ret > 0)
{
if (srcloc)
ddsi_ipaddr_to_loc(srcloc, &src, src.ss_family == AF_INET ? NN_LOCATOR_KIND_UDPv4 : NN_LOCATOR_KIND_UDPv6);
ddsi_ipaddr_to_loc(srcloc, (os_sockaddr *)&src, src.ss_family == AF_INET ? NN_LOCATOR_KIND_UDPv4 : NN_LOCATOR_KIND_UDPv6);
/* Check for udp packet truncation */
if ((((size_t) ret) > len)
@ -90,7 +90,7 @@ static ssize_t ddsi_udp_conn_read (ddsi_tran_conn_t conn, unsigned char * buf, s
{
char addrbuf[DDSI_LOCSTRLEN];
nn_locator_t tmp;
ddsi_ipaddr_to_loc(&tmp, &src, src.ss_family == AF_INET ? NN_LOCATOR_KIND_UDPv4 : NN_LOCATOR_KIND_UDPv6);
ddsi_ipaddr_to_loc(&tmp, (os_sockaddr *)&src, src.ss_family == AF_INET ? NN_LOCATOR_KIND_UDPv4 : NN_LOCATOR_KIND_UDPv6);
ddsi_locator_to_string(addrbuf, sizeof(addrbuf), &tmp);
NN_WARNING ("%s => %d truncated to %d\n", addrbuf, (int)ret, (int)len);
}

View file

@ -455,63 +455,51 @@ int find_own_ip (const char *requested_address)
const char *sep = " ";
char last_if_name[80] = "";
int quality = -1;
os_result res;
int i;
unsigned int nif;
os_ifAttributes *ifs;
os_ifaddrs_t *ifa, *ifa_root = NULL;
int maxq_list[MAX_INTERFACES];
int maxq_count = 0;
size_t maxq_strlen = 0;
int selected_idx = -1;
char addrbuf[DDSI_LOCSTRLEN];
ifs = os_malloc (MAX_INTERFACES * sizeof (*ifs));
nn_log (LC_CONFIG, "interfaces:");
{
int retcode;
nif = 0;
retcode = ddsi_enumerate_interfaces(gv.m_factory, (int)(MAX_INTERFACES - nif), ifs);
if (retcode > 0)
{
nif = (unsigned)retcode;
res = os_resultSuccess;
}
else if (retcode < 0)
{
NN_ERROR ("ddsi_enumerate_interfaces(%s): %d\n", gv.m_factory->m_typename, retcode);
res = os_resultFail;
}
else
{
if (config.transport_selector == TRANS_TCP6 || config.transport_selector == TRANS_UDP6)
res = os_sockQueryIPv6Interfaces (ifs, MAX_INTERFACES, &nif);
else if (config.transport_selector == TRANS_TCP || config.transport_selector == TRANS_UDP)
res = os_sockQueryInterfaces (ifs, MAX_INTERFACES, &nif);
else
{
NN_ERROR ("ddsi_enumerate_interfaces(%s): no go but neither UDP[46] nor TCP[46]\n", gv.m_factory->m_typename);
res = os_resultFail;
retcode = ddsi_enumerate_interfaces(gv.m_factory, &ifa_root);
if (retcode < 0) {
NN_ERROR("ddsi_enumerate_interfaces(%s): %d\n", gv.m_factory->m_typename, retcode);
} else if (retcode == 0) {
int err;
const os_ifaddr_filter_t fltr = {
.af_inet = (config.transport_selector == TRANS_TCP || config.transport_selector == TRANS_UDP),
.af_inet6 = (config.transport_selector == TRANS_TCP6 || config.transport_selector == TRANS_UDP6)
};
if ((err = os_getifaddrs(&ifa_root, &fltr)) != 0) {
NN_ERROR("os_getifaddrs: %s\n", os_strerror(err));
retcode = -1;
} else if (ifa_root == NULL) {
NN_ERROR("ddsi_enumerate_interfaces(%s): no go but neither UDP[46] nor TCP[46]\n", gv.m_factory->m_typename);
retcode = -1;
}
}
if (res != os_resultSuccess)
{
NN_ERROR ("os_sockQueryInterfaces: %d\n", (int) res);
os_free (ifs);
if (retcode < 0) {
os_freeifaddrs(ifa_root);
return 0;
}
}
gv.n_interfaces = 0;
last_if_name[0] = 0;
for (i = 0; i < (int) nif; i++, sep = ", ")
for (ifa = ifa_root; ifa != NULL; ifa = ifa->next)
{
os_sockaddr_storage tmpip, tmpmask;
char if_name[sizeof (last_if_name)];
int q = 0;
strncpy (if_name, ifs[i].name, sizeof (if_name) - 1);
strncpy (if_name, ifa->name, sizeof (if_name) - 1);
if_name[sizeof (if_name) - 1] = 0;
if (strcmp (if_name, last_if_name))
@ -519,46 +507,44 @@ int find_own_ip (const char *requested_address)
strcpy (last_if_name, if_name);
/* interface must be up */
if ((ifs[i].flags & IFF_UP) == 0)
if ((ifa->flags & IFF_UP) == 0)
{
nn_log (LC_CONFIG, " (interface down)");
continue;
}
tmpip = ifs[i].address;
tmpmask = ifs[i].network_mask;
#ifdef __linux
if (tmpip.ss_family == AF_PACKET)
if (ifa->addr->sa_family == AF_PACKET)
{
/* FIXME: weirdo warning warranted */
nn_locator_t *l = &gv.interfaces[gv.n_interfaces].loc;
l->kind = NN_LOCATOR_KIND_RAWETH;
l->port = NN_LOCATOR_PORT_INVALID;
memset(l->address, 0, 10);
memcpy(l->address + 10, ((struct sockaddr_ll *)&tmpip)->sll_addr, 6);
memcpy(l->address + 10, ((struct sockaddr_ll *)ifa->addr)->sll_addr, 6);
}
else
#endif
{
ddsi_ipaddr_to_loc(&gv.interfaces[gv.n_interfaces].loc, &tmpip, gv.m_factory->m_kind);
ddsi_ipaddr_to_loc(&gv.interfaces[gv.n_interfaces].loc, ifa->addr, gv.m_factory->m_kind);
}
ddsi_locator_to_string_no_port(addrbuf, sizeof(addrbuf), &gv.interfaces[gv.n_interfaces].loc);
nn_log (LC_CONFIG, " %s(", addrbuf);
if (!(ifs[i].flags & IFF_MULTICAST) && multicast_override (if_name))
if (!(ifa->flags & IFF_MULTICAST) && multicast_override (if_name))
{
nn_log (LC_CONFIG, "assume-mc:");
ifs[i].flags |= IFF_MULTICAST;
ifa->flags |= IFF_MULTICAST;
}
if (ifs[i].flags & IFF_LOOPBACK)
if (ifa->flags & IFF_LOOPBACK)
{
/* Loopback device has the lowest priority of every interface
available, because the other interfaces at least in principle
allow communicating with other machines. */
q += 0;
#if OS_SOCKET_HAS_IPV6
if (!(tmpip.ss_family == AF_INET6 && IN6_IS_ADDR_LINKLOCAL (&((os_sockaddr_in6 *) &tmpip)->sin6_addr)))
if (!(ifa->addr->sa_family == AF_INET6 && IN6_IS_ADDR_LINKLOCAL (&((os_sockaddr_in6 *)ifa->addr)->sin6_addr)))
q += 1;
#endif
}
@ -575,16 +561,16 @@ int find_own_ip (const char *requested_address)
which it was received. But that means proper multi-homing
support and has quite an impact in various places, not least of
which is the abstraction layer. */
if (!(tmpip.ss_family == AF_INET6 && IN6_IS_ADDR_LINKLOCAL (&((os_sockaddr_in6 *) &tmpip)->sin6_addr)))
if (!(ifa->addr->sa_family == AF_INET6 && IN6_IS_ADDR_LINKLOCAL (&((os_sockaddr_in6 *)ifa->addr)->sin6_addr)))
q += 5;
#endif
/* We strongly prefer a multicast capable interface, if that's
not available anything that's not point-to-point, or else we
hope IP routing will take care of the issues. */
if (ifs[i].flags & IFF_MULTICAST)
if (ifa->flags & IFF_MULTICAST)
q += 4;
else if (!(ifs[i].flags & IFF_POINTOPOINT))
else if (!(ifa->flags & IFF_POINTOPOINT))
q += 3;
else
q += 2;
@ -604,10 +590,9 @@ int find_own_ip (const char *requested_address)
/* FIXME: HACK HACK */
//ddsi_ipaddr_to_loc(&gv.interfaces[gv.n_interfaces].loc, &tmpip, gv.m_factory->m_kind);
if (tmpip.ss_family == AF_INET || tmpip.ss_family == AF_INET6)
if (ifa->addr->sa_family == AF_INET || ifa->addr->sa_family == AF_INET6)
{
tmpmask.ss_family = tmpip.ss_family;
ddsi_ipaddr_to_loc(&gv.interfaces[gv.n_interfaces].netmask, &tmpmask, gv.m_factory->m_kind);
ddsi_ipaddr_to_loc(&gv.interfaces[gv.n_interfaces].netmask, ifa->netmask, gv.m_factory->m_kind);
}
else
{
@ -615,14 +600,14 @@ int find_own_ip (const char *requested_address)
gv.interfaces[gv.n_interfaces].netmask.port = NN_LOCATOR_PORT_INVALID;
memset(&gv.interfaces[gv.n_interfaces].netmask.address, 0, sizeof(gv.interfaces[gv.n_interfaces].netmask.address));
}
gv.interfaces[gv.n_interfaces].mc_capable = ((ifs[i].flags & IFF_MULTICAST) != 0);
gv.interfaces[gv.n_interfaces].point_to_point = ((ifs[i].flags & IFF_POINTOPOINT) != 0);
gv.interfaces[gv.n_interfaces].if_index = ifs[i].interfaceIndexNo;
gv.interfaces[gv.n_interfaces].mc_capable = ((ifa->flags & IFF_MULTICAST) != 0);
gv.interfaces[gv.n_interfaces].point_to_point = ((ifa->flags & IFF_POINTOPOINT) != 0);
gv.interfaces[gv.n_interfaces].if_index = ifa->index;
gv.interfaces[gv.n_interfaces].name = os_strdup (if_name);
gv.n_interfaces++;
}
nn_log (LC_CONFIG, "\n");
os_free (ifs);
os_freeifaddrs (ifa_root);
if (requested_address == NULL)
{

View file

@ -17,10 +17,10 @@ IF(${platform} IN_LIST posix_platforms)
set(platform posix)
ENDIF()
PREPEND(srcs_platform ${platform} os_platform_errno.c os_platform_heap.c os_platform_init.c os_platform_process.c os_platform_socket.c os_platform_stdlib.c os_platform_sync.c os_platform_thread.c os_platform_time.c)
PREPEND(srcs_platform ${platform} os_platform_errno.c os_platform_heap.c os_platform_init.c os_platform_process.c os_platform_ifaddrs.c os_platform_socket.c os_platform_stdlib.c os_platform_sync.c os_platform_thread.c os_platform_time.c)
include (GenerateExportHeader)
PREPEND(srcs_os "${CMAKE_CURRENT_SOURCE_DIR}/src" os_atomics.c os_init.c os_report.c os_socket.c os_thread.c os_time.c os_errno.c os_iter.c ${srcs_platform})
PREPEND(srcs_os "${CMAKE_CURRENT_SOURCE_DIR}/src" os_atomics.c os_init.c os_report.c os_ifaddrs.c os_socket.c os_thread.c os_time.c os_errno.c os_iter.c ${srcs_platform})
add_library(OSAPI ${srcs_os})
configure_file(

View file

@ -15,12 +15,6 @@
#ifndef OS_SOCKET_HAS_IPV6
#error "OS_SOCKET_HAS_IPV6 should have been defined by os_platform_socket.h"
#endif
#ifndef OS_IFNAMESIZE
#error "OS_IFNAMESIZE should have been defined by os_platform_socket.h"
#endif
#ifndef OS_SOCKET_HAS_SA_LEN
#error "OS_SOCKET_HAS_SA_LEN should have been defined by os_platform_socket.h"
#endif
#ifndef OS_NO_SIOCGIFINDEX
#error "OS_NO_SIOCGIFINDEX should have been defined by os_platform_socket.h"
#endif
@ -94,11 +88,7 @@ extern "C" {
typedef struct ipv6_mreq os_ipv6_mreq;
typedef struct in6_addr os_in6_addr;
#if defined (OSPL_VXWORKS653)
typedef struct sockaddr_in os_sockaddr_storage;
#else
typedef struct sockaddr_storage os_sockaddr_storage;
#endif
typedef struct sockaddr_in6 os_sockaddr_in6;
#endif
@ -120,59 +110,50 @@ extern "C" {
#define SD_FLAG_IS_SET(flags, flag) ((((uint32_t)(flags) & (uint32_t)(flag))) != 0U)
/**
* Structure to hold a network interface's attributes
*/
typedef struct os_ifAttributes_s {
/**
* The network interface name (or at least OS_IFNAMESIZE - 1 charcaters thereof)
*/
char name[OS_IFNAMESIZE];
/**
* Iff the interface is IPv4 holds the ioctl query result flags for this interface.
*/
typedef struct {
uint8_t af_inet : 1;
uint8_t af_inet6 : 1;
uint8_t af_packet : 1;
} os_ifaddr_filter_t;
/** Network interface attributes */
typedef struct os_ifaddrs_s {
struct os_ifaddrs_s *next;
char *name;
uint32_t index;
uint32_t flags;
/**
* The network interface address of this interface.
*/
os_sockaddr_storage address;
/**
* Iff this is an IPv4 interface, holds the broadcast address for the sub-network this
* interface is connected to.
*/
os_sockaddr_storage broadcast_address;
/**
* Iff this is an IPv4 interface, holds the subnet mast for this interface
*/
os_sockaddr_storage network_mask;
/**
* Holds the interface index for this interface.
*/
unsigned interfaceIndexNo;
} os_ifAttributes;
OSAPI_EXPORT os_result
os_sockQueryInterfaces(
os_ifAttributes *ifList,
uint32_t listSize,
uint32_t *validElements);
os_sockaddr *addr;
os_sockaddr *netmask;
os_sockaddr *broadaddr;
} os_ifaddrs_t;
/**
* Fill-in a pre-allocated list of os_ifAttributes_s with details of
* the available IPv6 network interfaces.
* @param listSize Number of elements there is space for in the list.
* @param ifList Pointer to head of list
* @param validElements Out param to hold the number of interfaces found
* whose detauils have been returned.
* @return os_resultSuccess if 0 or more interfaces were found, os_resultFail if
* an error occurred.
* @see os_sockQueryInterfaces
* @brief Get interface addresses
*
* Retrieve network interfaces available on the local system and store
* them in a linked list of os_ifaddrs_t structures.
*
* The data returned by os_getifaddrs() is dynamically allocated and should
* be freed using os_freeifaddrs when no longer needed.
*
* @param[in,out] ifap Address of first os_ifaddrs_t structure in the list.
* @param[in] ifilt FIXME: comment
*
* @returns Returns zero on success or a valid errno value on error.
*/
OSAPI_EXPORT os_result
os_sockQueryIPv6Interfaces(
os_ifAttributes *ifList,
uint32_t listSize,
uint32_t *validElements);
OSAPI_EXPORT _Success_(return == 0) int
os_getifaddrs(
_Inout_ os_ifaddrs_t **ifap,
_In_ const os_ifaddr_filter_t *ifilt);
/**
* @brief Free os_ifaddrs_t structure list allocated by os_getifaddrs()
*
* @param[in] Address of first os_ifaddrs_t structure in the list.
*/
OSAPI_EXPORT void
os_freeifaddrs(
_Pre_maybenull_ _Post_ptr_invalid_ os_ifaddrs_t *ifa);
OSAPI_EXPORT os_socket
os_sockNew(

View file

@ -262,6 +262,9 @@ extern "C" {
__attribute_returns_nonnull__
__attribute_warn_unused_result__;
void *
os_memdup(void *src, size_t n);
/** \brief os_strsep wrapper
*
* See strsep()
@ -271,6 +274,14 @@ extern "C" {
char **stringp,
const char *delim);
/** \brief write a formatted string to a newly allocated buffer
*/
OSAPI_EXPORT int
os_asprintf(
char **strp,
const char *fmt,
...);
/** \brief os_vsnprintf wrapper
*
* Microsoft generates deprected warnings for vsnprintf,

View file

@ -39,7 +39,6 @@ extern "C" {
/* Keep defines before common header */
#define OS_SOCKET_HAS_IPV6 1
#define OS_IFNAMESIZE IF_NAMESIZE
#define OS_SOCKET_HAS_SA_LEN 1
#define OS_NO_SIOCGIFINDEX 1
#define OS_NO_NETLINK 1

View file

@ -25,7 +25,6 @@ extern "C" {
/* Keep defines before common header */
#define OS_SOCKET_HAS_IPV6 1
#define OS_IFNAMESIZE 128
#define OS_SOCKET_HAS_SA_LEN 0
#define OS_NO_SIOCGIFINDEX 1
#define OS_NO_NETLINK 1

29
src/os/src/os_ifaddrs.c Normal file
View file

@ -0,0 +1,29 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include "os/os.h"
void
os_freeifaddrs(os_ifaddrs_t *ifa)
{
os_ifaddrs_t *next;
while (ifa != NULL) {
next = ifa->next;
os_free(ifa->name);
os_free(ifa->addr);
os_free(ifa->netmask);
os_free(ifa->broadaddr);
os_free(ifa);
ifa = next;
}
}

View file

@ -0,0 +1,128 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include <assert.h>
#include <string.h>
#if defined(__linux)
#include <linux/if_packet.h> /* sockaddr_ll */
#endif /* __linux */
#include "os/os.h"
static int
copy_ifaddrs(os_ifaddrs_t **ifap, const struct ifaddrs *sys_ifa)
{
int err = 0;
os_ifaddrs_t *ifa;
size_t size;
assert(ifap != NULL);
assert(sys_ifa != NULL);
assert(sys_ifa->ifa_addr->sa_family == AF_INET ||
sys_ifa->ifa_addr->sa_family == AF_INET6 ||
sys_ifa->ifa_addr->sa_family == AF_PACKET);
ifa = os_malloc(sizeof(*ifa));
if (ifa == NULL) {
err = errno;
} else {
(void)memset(ifa, 0, sizeof(*ifa));
ifa->index = if_nametoindex(sys_ifa->ifa_name);
ifa->flags = sys_ifa->ifa_flags;
if ((ifa->name = os_strdup(sys_ifa->ifa_name)) == NULL) {
err = errno;
} else if (sys_ifa->ifa_addr->sa_family == AF_INET6) {
size = sizeof(struct sockaddr_in6);
if (!(ifa->addr = os_memdup(sys_ifa->ifa_addr, size))) {
err = errno;
}
} else {
if (sys_ifa->ifa_addr->sa_family == AF_INET) {
size = sizeof(struct sockaddr_in);
} else {
assert(sys_ifa->ifa_addr->sa_family == AF_PACKET);
size = sizeof(struct sockaddr_ll);
}
if (!(ifa->addr = os_memdup(sys_ifa->ifa_addr, size)) ||
(sys_ifa->ifa_netmask &&
!(ifa->netmask = os_memdup(sys_ifa->ifa_netmask, size))) ||
(sys_ifa->ifa_broadaddr &&
!(ifa->broadaddr = os_memdup(sys_ifa->ifa_broadaddr, size))))
{
err = errno;
}
}
}
if (err == 0) {
*ifap = ifa;
} else {
os_freeifaddrs(ifa);
}
return err;
}
_Success_(return == 0) int
os_getifaddrs(
_Inout_ os_ifaddrs_t **ifap,
_In_opt_ const os_ifaddr_filter_t *ifltr)
{
int err = 0;
os_ifaddrs_t *ifa, *ifa_root, *ifa_next;
struct ifaddrs *sys_ifa, *sys_ifa_root;
struct sockaddr *addr;
assert(ifap != NULL);
assert(ifltr != NULL);
if (getifaddrs(&sys_ifa_root) == -1) {
err = errno;
} else {
ifa = ifa_root = NULL;
for (sys_ifa = sys_ifa_root;
sys_ifa != NULL && err == 0;
sys_ifa = sys_ifa->ifa_next)
{
addr = sys_ifa->ifa_addr;
if ((addr->sa_family == AF_PACKET && ifltr->af_packet)
|| (addr->sa_family == AF_INET && ifltr->af_inet)
|| (addr->sa_family == AF_INET6 && ifltr->af_inet6 &&
!IN6_IS_ADDR_UNSPECIFIED(
&((struct sockaddr_in6 *)addr)->sin6_addr)))
{
err = copy_ifaddrs(&ifa_next, sys_ifa);
if (err == 0) {
if (ifa == NULL) {
ifa = ifa_root = ifa_next;
} else {
ifa->next = ifa_next;
ifa = ifa_next;
}
}
}
}
freeifaddrs(sys_ifa_root);
if (err == 0) {
*ifap = ifa_root;
} else {
os_freeifaddrs(ifa_root);
}
}
return err;
}

View file

@ -230,98 +230,3 @@ os_sockSelect(
return r;
}
_Check_return_
static os_result
os_queryInterfaceAttributesIPv4 (_In_ const struct ifaddrs *ifa, _Inout_ os_ifAttributes *ifElement)
{
os_result result = os_resultSuccess;
strncpy (ifElement->name, ifa->ifa_name, OS_IFNAMESIZE);
ifElement->name[OS_IFNAMESIZE - 1] = '\0';
memcpy (&ifElement->address, ifa->ifa_addr, sizeof (os_sockaddr_in));
ifElement->flags = ifa->ifa_flags;
if (ifElement->flags & IFF_BROADCAST)
memcpy (&ifElement->broadcast_address, ifa->ifa_broadaddr, sizeof (os_sockaddr_in));
else
memset (&ifElement->broadcast_address, 0, sizeof (ifElement->broadcast_address));
memcpy (&ifElement->network_mask, ifa->ifa_netmask, sizeof (os_sockaddr_in));
ifElement->interfaceIndexNo = (unsigned) if_nametoindex (ifa->ifa_name);
return result;
}
_Check_return_
static os_result
os_queryInterfaceAttributesIPv6 (_In_ const struct ifaddrs *ifa, _Inout_ os_ifAttributes *ifElement)
{
os_result result = os_resultSuccess;
strncpy (ifElement->name, ifa->ifa_name, OS_IFNAMESIZE);
ifElement->name[OS_IFNAMESIZE - 1] = '\0';
memcpy (&ifElement->address, ifa->ifa_addr, sizeof (os_sockaddr_in6));
ifElement->flags = ifa->ifa_flags;
memset (&ifElement->broadcast_address, 0, sizeof (ifElement->broadcast_address));
memset (&ifElement->network_mask, 0, sizeof (ifElement->network_mask));
ifElement->interfaceIndexNo = (unsigned) if_nametoindex (ifa->ifa_name);
return result;
}
os_result os_sockQueryInterfaces (os_ifAttributes *ifList, uint32_t listSize, uint32_t *validElements)
{
os_result result = os_resultSuccess;
unsigned int listIndex;
struct ifaddrs *ifa_first, *ifa;
if (getifaddrs (&ifa_first) != 0)
{
perror ("getifaddrs");
return os_resultFail;
}
listIndex = 0;
for (ifa = ifa_first; ifa && listIndex < listSize; ifa = ifa->ifa_next)
{
if (ifa->ifa_addr && ((struct sockaddr_in *) ifa->ifa_addr)->sin_family == AF_INET)
{
/* Get other interface attributes */
result = os_queryInterfaceAttributesIPv4 (ifa, &ifList[listIndex]);
if (result == os_resultSuccess)
listIndex++;
}
if (result == os_resultSuccess)
*validElements = listIndex;
}
freeifaddrs (ifa_first);
return result;
}
os_result os_sockQueryIPv6Interfaces (os_ifAttributes *ifList, uint32_t listSize, uint32_t *validElements)
{
struct ifaddrs* interfaceList = NULL;
struct ifaddrs* nextInterface = NULL;
unsigned int listIndex = 0;
*validElements = 0;
if (getifaddrs (&interfaceList) != 0)
{
return os_resultFail;
}
nextInterface = interfaceList;
while (nextInterface != NULL && listIndex < listSize)
{
if (nextInterface->ifa_addr && nextInterface->ifa_addr->sa_family == AF_INET6)
{
os_sockaddr_in6 *v6Address = (os_sockaddr_in6 *) nextInterface->ifa_addr;
if (!IN6_IS_ADDR_UNSPECIFIED (&v6Address->sin6_addr))
{
os_result result = os_resultSuccess;
result = os_queryInterfaceAttributesIPv6 (nextInterface, &ifList[listIndex]);
if (result == os_resultSuccess)
listIndex++;
}
}
nextInterface = nextInterface->ifa_next;
}
*validElements = listIndex;
freeifaddrs(interfaceList);
return os_resultSuccess;
}

View file

@ -22,7 +22,9 @@
#include <ctype.h>
#include "os_stdlib_strsep.c"
#include "os_stdlib_memdup.c"
#include "os_stdlib_rindex.c"
#include "os_stdlib_asprintf.c"
#include "os_stdlib_strcasecmp.c"
#include "os_stdlib_strncasecmp.c"
#include "os_stdlib_strdup.c"

View file

@ -0,0 +1,48 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include "os/os.h"
int
os_asprintf(
char **strp,
const char *fmt,
...)
{
int ret;
unsigned int len;
char buf[1] = { '\0' };
char *str = NULL;
va_list args1, args2;
assert(strp != NULL);
assert(fmt != NULL);
va_start(args1, fmt);
va_copy(args2, args1); /* va_list cannot be reused */
if ((ret = os_vsnprintf(buf, sizeof(buf), fmt, args1)) >= 0) {
len = (unsigned int)ret; /* +1 for null byte */
if ((str = os_malloc(len + 1)) == NULL) {
ret = -1;
} else if ((ret = os_vsnprintf(str, len + 1, fmt, args2)) >= 0) {
assert(((unsigned int)ret) == len);
*strp = str;
} else {
os_free(str);
}
}
va_end(args1);
va_end(args2);
return ret;
}

View file

@ -0,0 +1,24 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include "os/os.h"
void *
os_memdup(void *src, size_t n)
{
void *dest;
if ((dest = os_malloc_s(n)) != NULL) {
memcpy(dest, src, n);
}
return dest;
}

View file

@ -0,0 +1,260 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include <assert.h>
#include <errno.h>
#include "os/os.h"
static int
getifaces(PIP_ADAPTER_ADDRESSES *ptr)
{
int err = ERANGE;
PIP_ADAPTER_ADDRESSES buf = NULL;
ULONG bufsz = 0; /* Size is determined on first iteration. */
ULONG ret;
size_t i;
static const size_t max = 3;
static const ULONG filter = GAA_FLAG_INCLUDE_PREFIX |
GAA_FLAG_SKIP_ANYCAST |
GAA_FLAG_SKIP_MULTICAST |
GAA_FLAG_SKIP_DNS_SERVER;
assert(ptr != NULL);
for (i = 0; err == ERANGE && i < max; i++) {
ret = GetAdaptersAddresses(AF_UNSPEC, filter, NULL, buf, &bufsz);
assert(ret != ERROR_INVALID_PARAMETER);
switch (ret) {
case ERROR_BUFFER_OVERFLOW:
err = ERANGE;
os_free(buf);
if ((buf = (IP_ADAPTER_ADDRESSES *)os_malloc(bufsz)) == NULL) {
err = ENOMEM;
}
break;
case ERROR_NOT_ENOUGH_MEMORY:
err = ENOMEM;
break;
case ERROR_SUCCESS:
case ERROR_ADDRESS_NOT_ASSOCIATED: /* No address associated yet. */
case ERROR_NO_DATA: /* No adapters that match the filter. */
default:
err = 0;
break;
}
}
if (err == 0) {
*ptr = buf;
}
return err;
}
static int
getaddrtable(PMIB_IPADDRTABLE *ptr)
{
int err = ERANGE;
PMIB_IPADDRTABLE buf = NULL;
ULONG bufsz = 0;
DWORD ret;
size_t i;
static const size_t max = 2;
assert(ptr != NULL);
for (i = 0; err == ERANGE && i < max; i++) {
ret = GetIpAddrTable(buf, &bufsz, 0);
assert(ret != ERROR_INVALID_PARAMETER &&
ret != ERROR_NOT_SUPPORTED);
switch (ret) {
case ERROR_INSUFFICIENT_BUFFER:
err = ERANGE;
os_free(buf);
if ((buf = (PMIB_IPADDRTABLE)os_malloc(bufsz)) == NULL) {
err = ENOMEM;
}
break;
case ERROR_SUCCESS:
default:
err = GetLastError();
break;
}
}
if (err == 0) {
*ptr = buf;
} else {
os_free(buf);
}
return err;
}
static uint32_t
getflags(const PIP_ADAPTER_ADDRESSES iface)
{
uint32_t flags = 0;
if (iface->OperStatus == IfOperStatusUp) {
flags |= IFF_UP;
}
if (iface->IfType == IF_TYPE_SOFTWARE_LOOPBACK) {
flags |= IFF_LOOPBACK;
}
if (!(iface->Flags & IP_ADAPTER_NO_MULTICAST)) {
flags |= IFF_MULTICAST;
}
/* FIXME: Shouldn't IFF_LOOPBACK be included here? */
switch (iface->IfType) {
case IF_TYPE_ETHERNET_CSMACD:
case IF_TYPE_IEEE80211:
case IF_TYPE_IEEE1394:
case IF_TYPE_ISO88025_TOKENRING:
flags |= IFF_BROADCAST;
break;
default:
flags |= IFF_POINTTOPOINT;
break;
}
return flags;
}
static int
copyaddr(
os_ifaddrs_t **ifap,
const PIP_ADAPTER_ADDRESSES iface,
const PMIB_IPADDRTABLE addrtable,
const PIP_ADAPTER_UNICAST_ADDRESS addr)
{
int err = 0;
int eq = 0;
os_ifaddrs_t *ifa;
DWORD i;
struct sockaddr *sa = (struct sockaddr *)addr->Address.lpSockaddr;
size_t size;
assert(iface != NULL);
assert(addrtable != NULL);
assert(addr != NULL);
if ((ifa = os_calloc_s(1, sizeof(*ifa))) == NULL) {
err = ENOMEM;
} else {
ifa->flags = getflags(iface);
(void)os_asprintf(&ifa->name, "%wS", iface->FriendlyName);
if (ifa->name == NULL) {
err = ENOMEM;
} else if (ifa->flags & IFF_UP) {
ifa->addr = os_memdup(sa, addr->Address.iSockaddrLength);
if (ifa->addr == NULL) {
err = ENOMEM;
} else if (ifa->addr->sa_family == AF_INET) {
size = sizeof(struct sockaddr_in);
struct sockaddr_in netmask, broadaddr;
memset(&netmask, 0, size);
memset(&broadaddr, 0, size);
netmask.sin_family = broadaddr.sin_family = AF_INET;
for (i = 0; !eq && i < addrtable->dwNumEntries; i++) {
eq = (((struct sockaddr_in *)sa)->sin_addr.s_addr ==
addrtable->table[i].dwAddr);
if (eq) {
ifa->index = addrtable->table[i].dwIndex;
netmask.sin_addr.s_addr = addrtable->table[i].dwMask;
broadaddr.sin_addr.s_addr =
((struct sockaddr_in *)sa)->sin_addr.s_addr | ~(netmask.sin_addr.s_addr);
}
}
assert(eq != 0);
if ((ifa->netmask = os_memdup(&netmask, size)) == NULL ||
(ifa->broadaddr = os_memdup(&broadaddr, size)) == NULL)
{
err = ENOMEM;
}
} else {
ifa->index = iface->Ipv6IfIndex;
}
}
}
if (err == 0) {
*ifap = ifa;
} else {
os_free(ifa);
}
return err;
}
_Success_(return == 0) int
os_getifaddrs(
_Inout_ os_ifaddrs_t **ifap,
_In_opt_ const os_ifaddr_filter_t *ifltr)
{
int err = 0;
PIP_ADAPTER_ADDRESSES ifaces = NULL, iface;
PIP_ADAPTER_UNICAST_ADDRESS addr = NULL;
PMIB_IPADDRTABLE addrtable = NULL;
os_ifaddrs_t *ifa, *ifa_root, *ifa_next;
struct sockaddr *sa;
assert(ifap != NULL);
assert(ifltr != NULL);
ifa = ifa_root = ifa_next = NULL;
if ((err = getifaces(&ifaces)) == 0 &&
(err = getaddrtable(&addrtable)) == 0)
{
for (iface = ifaces; !err && iface != NULL; iface = iface->Next) {
for (addr = iface->FirstUnicastAddress;
addr != NULL;
addr = addr->Next)
{
sa = (struct sockaddr *)addr->Address.lpSockaddr;
if ((sa->sa_family == AF_INET && ifltr->af_inet) ||
(sa->sa_family == AF_INET6 && ifltr->af_inet6))
{
err = copyaddr(&ifa_next, iface, addrtable, addr);
if (err == 0) {
if (ifa == NULL) {
ifa = ifa_root = ifa_next;
} else {
ifa->next = ifa_next;
ifa = ifa_next;
}
}
}
}
}
}
os_free(ifaces);
os_free(addrtable);
if (err == 0) {
*ifap = ifa_root;
} else {
os_freeifaddrs(ifa_root);
}
return err;
}

View file

@ -558,341 +558,3 @@ os__sockSelect(
return r;
}
static unsigned int
getInterfaceFlags(PIP_ADAPTER_ADDRESSES pAddr)
{
unsigned int flags = 0;
if (pAddr->OperStatus == IfOperStatusUp) {
flags |= IFF_UP;
}
if (pAddr->IfType == IF_TYPE_SOFTWARE_LOOPBACK) {
flags |= IFF_LOOPBACK;
}
if (!(pAddr->Flags & IP_ADAPTER_NO_MULTICAST)) {
flags |= IFF_MULTICAST;
}
switch (pAddr->IfType) {
case IF_TYPE_ETHERNET_CSMACD:
case IF_TYPE_IEEE80211:
case IF_TYPE_IEEE1394:
case IF_TYPE_ISO88025_TOKENRING:
flags |= IFF_BROADCAST;
break;
default:
flags |= IFF_POINTTOPOINT;
break;
}
return flags;
}
static os_result
addressToIndexAndMask(struct sockaddr *addr, unsigned int *ifIndex, struct sockaddr *mask )
{
os_result result = os_resultSuccess;
bool found = FALSE;
PMIB_IPADDRTABLE pIPAddrTable = NULL;
DWORD dwSize = 0;
DWORD i;
int errNo;
if (GetIpAddrTable(pIPAddrTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) {
pIPAddrTable = (MIB_IPADDRTABLE *) os_malloc(dwSize);
if (pIPAddrTable != NULL) {
if (GetIpAddrTable(pIPAddrTable, &dwSize, 0) != NO_ERROR) {
errNo = os_getErrno();
OS_ERROR("addressToIndexAndMask", 0, "GetIpAddrTable failed: %d", errNo);
result = os_resultFail;
}
} else {
OS_ERROR("addressToIndexAndMask", 0, "Failed to allocate %lu bytes for IP address table", dwSize);
result = os_resultFail;
}
} else {
errNo = os_getErrno();
OS_ERROR("addressToIndexAndMask", 0, "GetIpAddrTable failed: %d", errNo);
result = os_resultFail;
}
if (result == os_resultSuccess) {
for (i = 0; !found && i < pIPAddrTable->dwNumEntries; i++ ) {
if (((struct sockaddr_in* ) addr )->sin_addr.s_addr == pIPAddrTable->table[i].dwAddr) {
*ifIndex = pIPAddrTable->table[i].dwIndex;
((struct sockaddr_in*) mask)->sin_addr.s_addr= pIPAddrTable->table[i].dwMask;
found = TRUE;
}
}
}
if (pIPAddrTable) {
os_free(pIPAddrTable);
}
if (!found) {
result = os_resultFail;
}
return result;
}
#define MAX_INTERFACES 64
#define INTF_MAX_NAME_LEN 16
os_result
os_sockQueryInterfaces(
os_ifAttributes *ifList,
unsigned int listSize,
unsigned int *validElements)
{
os_result result = os_resultSuccess;
DWORD filter;
PIP_ADAPTER_ADDRESSES pAddresses = NULL;
PIP_ADAPTER_ADDRESSES pCurrAddress = NULL;
PIP_ADAPTER_UNICAST_ADDRESS pUnicast = NULL;
unsigned long outBufLen = WORKING_BUFFER_SIZE;
int retVal;
int iterations = 0;
int listIndex = 0;
filter = GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER;
do {
pAddresses = (IP_ADAPTER_ADDRESSES *) os_malloc(outBufLen);
if (!pAddresses) {
OS_ERROR("os_sockQueryInterfaces", 0, "Failed to allocate %lu bytes for Adapter addresses", outBufLen);
return os_resultFail;
}
retVal = GetAdaptersAddresses(AF_INET, filter, NULL, pAddresses, &outBufLen);
if (retVal == ERROR_BUFFER_OVERFLOW) {
os_free(pAddresses);
pAddresses = NULL;
outBufLen <<= 1; /* double the buffer just to be save.*/
} else {
break;
}
iterations++;
} while ((retVal == ERROR_BUFFER_OVERFLOW) && (iterations < MAX_TRIES));
if (retVal != ERROR_SUCCESS) {
if (pAddresses) {
os_free(pAddresses);
pAddresses = NULL;
}
OS_ERROR("os_sockQueryInterfaces", 0, "Failed to GetAdaptersAddresses");
return os_resultFail;
}
for (pCurrAddress = pAddresses; pCurrAddress; pCurrAddress = pCurrAddress->Next) {
IP_ADAPTER_PREFIX *firstPrefix = NULL;
if (pCurrAddress->Length >= sizeof(IP_ADAPTER_ADDRESSES)) {
firstPrefix = pCurrAddress->FirstPrefix;
}
if (pCurrAddress->OperStatus != IfOperStatusUp) {
continue;
}
for (pUnicast = pCurrAddress->FirstUnicastAddress; pUnicast; pUnicast = pUnicast->Next) {
unsigned int ipv4Index;
struct sockaddr_in ipv4Netmask;
if (pUnicast->Address.lpSockaddr->sa_family != AF_INET) {
continue;
}
ipv4Index = 0;
memset(&ipv4Netmask, 0, sizeof(ipv4Netmask));
if (addressToIndexAndMask((struct sockaddr *) pUnicast->Address.lpSockaddr,
&ipv4Index, (struct sockaddr *) &ipv4Netmask) != os_resultSuccess) {
continue;
}
(void)snprintf(ifList[listIndex].name, OS_IFNAMESIZE, "%wS", pCurrAddress->FriendlyName);
/* Get interface flags. */
ifList[listIndex].flags = getInterfaceFlags(pCurrAddress);
ifList[listIndex].interfaceIndexNo = ipv4Index;
memcpy(&ifList[listIndex].address, pUnicast->Address.lpSockaddr, pUnicast->Address.iSockaddrLength);
memcpy(&ifList[listIndex].broadcast_address, pUnicast->Address.lpSockaddr, pUnicast->Address.iSockaddrLength);
memcpy(&ifList[listIndex].network_mask, pUnicast->Address.lpSockaddr, pUnicast->Address.iSockaddrLength);
((struct sockaddr_in *)(&(ifList[listIndex].broadcast_address)))->sin_addr.s_addr =
((struct sockaddr_in *)(&(ifList[listIndex].address)))->sin_addr.s_addr | ~(ipv4Netmask.sin_addr.s_addr);
((struct sockaddr_in *)&(ifList[listIndex].network_mask))->sin_addr.s_addr = ipv4Netmask.sin_addr.s_addr;
listIndex++;
}
}
for (pCurrAddress = pAddresses; pCurrAddress; pCurrAddress = pCurrAddress->Next) {
if (pCurrAddress->OperStatus != IfOperStatusUp) {
(void)snprintf(ifList[listIndex].name, OS_IFNAMESIZE, "%wS", pCurrAddress->FriendlyName);
/* Get interface flags. */
ifList[listIndex].flags = getInterfaceFlags(pCurrAddress);
ifList[listIndex].interfaceIndexNo = 0;
memset (&ifList[listIndex].address, 0, sizeof(ifList[listIndex].address));
memset (&ifList[listIndex].broadcast_address, 0, sizeof (ifList[listIndex].broadcast_address));
memset (&ifList[listIndex].network_mask, 0, sizeof (ifList[listIndex].network_mask));
listIndex++;
}
}
if (pAddresses) {
os_free(pAddresses);
}
*validElements = listIndex;
return result;
}
os_result
os_sockQueryIPv6Interfaces (
os_ifAttributes *ifList,
unsigned int listSize,
unsigned int *validElements)
{
os_result result = os_resultSuccess;
ULONG filter;
PIP_ADAPTER_ADDRESSES pAddresses = NULL;
PIP_ADAPTER_ADDRESSES pCurrAddress = NULL;
PIP_ADAPTER_UNICAST_ADDRESS pUnicast = NULL;
ULONG outBufLen = WORKING_BUFFER_SIZE;
ULONG retVal;
int iterations = 0;
int listIndex = 0;
filter = GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER;
do {
pAddresses = (IP_ADAPTER_ADDRESSES *) os_malloc(outBufLen);
if (!pAddresses) {
OS_ERROR("os_sockQueryIPv6Interfaces", 0, "Failed to allocate %lu bytes for Adapter addresses", outBufLen);
return os_resultFail;
}
retVal = GetAdaptersAddresses(AF_INET6, filter, NULL, pAddresses, &outBufLen);
if (retVal == ERROR_BUFFER_OVERFLOW) {
os_free(pAddresses);
pAddresses = NULL;
outBufLen <<= 1; /* double the buffer just to be save.*/
} else {
break;
}
iterations++;
} while ((retVal == ERROR_BUFFER_OVERFLOW) && (iterations < MAX_TRIES));
if (retVal != ERROR_SUCCESS) {
if (pAddresses) {
os_free(pAddresses);
pAddresses = NULL;
}
OS_ERROR("os_sockQueryIPv6Interfaces", 0, "Failed to GetAdaptersAddresses");
return os_resultFail;
}
for (pCurrAddress = pAddresses; pCurrAddress; pCurrAddress = pCurrAddress->Next) {
DWORD ipv6IfIndex = 0;
IP_ADAPTER_PREFIX *firstPrefix = NULL;
if (pCurrAddress->Length >= sizeof(IP_ADAPTER_ADDRESSES)) {
ipv6IfIndex = pCurrAddress->Ipv6IfIndex;
firstPrefix = pCurrAddress->FirstPrefix;
}
if (((ipv6IfIndex == 1) && (pCurrAddress->IfType != IF_TYPE_SOFTWARE_LOOPBACK)) || (pCurrAddress->IfType == IF_TYPE_TUNNEL)) {
continue;
}
if (pCurrAddress->OperStatus != IfOperStatusUp) {
continue;
}
for (pUnicast = pCurrAddress->FirstUnicastAddress; pUnicast; pUnicast = pUnicast->Next) {
IP_ADAPTER_PREFIX *prefix;
IN6_ADDR mask;
struct sockaddr_in6 *sa6;
struct sockaddr_in6 ipv6Netmask;
if (pUnicast->Address.lpSockaddr->sa_family != AF_INET6) {
continue;
}
(void)snprintf(ifList[listIndex].name, OS_IFNAMESIZE, "%wS", pCurrAddress->FriendlyName);
/* Get interface flags. */
ifList[listIndex].flags = getInterfaceFlags(pCurrAddress);
ifList[listIndex].interfaceIndexNo = (uint32_t) pCurrAddress->Ipv6IfIndex;
memcpy(&ifList[listIndex].address, pUnicast->Address.lpSockaddr, pUnicast->Address.iSockaddrLength);
memcpy(&ifList[listIndex].broadcast_address, pUnicast->Address.lpSockaddr, pUnicast->Address.iSockaddrLength);
memcpy(&ifList[listIndex].network_mask, pUnicast->Address.lpSockaddr, pUnicast->Address.iSockaddrLength);
sa6 = (struct sockaddr_in6 *)&ifList[listIndex].network_mask;
memset(&sa6->sin6_addr.s6_addr, 0xFF, sizeof(sa6->sin6_addr.s6_addr));
for (prefix = firstPrefix; prefix; prefix = prefix->Next) {
unsigned int l, i;
if ((prefix->PrefixLength == 0) || (prefix->PrefixLength > 128) ||
(pUnicast->Address.iSockaddrLength != prefix->Address.iSockaddrLength) ||
(memcmp(pUnicast->Address.lpSockaddr, prefix->Address.lpSockaddr, pUnicast->Address.iSockaddrLength) == 0)){
continue;
}
memset(&ipv6Netmask, 0, sizeof(ipv6Netmask));
ipv6Netmask.sin6_family = AF_INET6;
l = prefix->PrefixLength;
for (i = 0; l > 0; l -= 8, i++) {
ipv6Netmask.sin6_addr.s6_addr[i] = (l >= 8) ? 0xFF : ((0xFF << (8-l)) & 0xFF);
}
for (i = 0; i < 16; i++) {
mask.s6_addr[i] =
((struct sockaddr_in6 *)pUnicast->Address.lpSockaddr)->sin6_addr.s6_addr[i] & ipv6Netmask.sin6_addr.s6_addr[i];
}
if (memcmp(((struct sockaddr_in6 *)prefix->Address.lpSockaddr)->sin6_addr.s6_addr,
mask.s6_addr, sizeof(ipv6Netmask.sin6_addr)) == 0) {
memcpy(&sa6->sin6_addr.s6_addr, &ipv6Netmask.sin6_addr.s6_addr, sizeof(sa6->sin6_addr.s6_addr));
}
}
listIndex++;
}
}
for (pCurrAddress = pAddresses; pCurrAddress; pCurrAddress = pCurrAddress->Next) {
if (pCurrAddress->OperStatus != IfOperStatusUp) {
(void) snprintf(ifList[listIndex].name, OS_IFNAMESIZE, "%wS", pCurrAddress->FriendlyName);
/* Get interface flags. */
ifList[listIndex].flags = getInterfaceFlags(pCurrAddress);
ifList[listIndex].interfaceIndexNo = 0;
memset (&ifList[listIndex].address, 0, sizeof(ifList[listIndex].address));
memset (&ifList[listIndex].broadcast_address, 0, sizeof (ifList[listIndex].broadcast_address));
memset (&ifList[listIndex].network_mask, 0, sizeof (ifList[listIndex].network_mask));
listIndex++;
}
}
if (pAddresses) {
os_free(pAddresses);
}
*validElements = listIndex;
return result;
}
#undef MAX_INTERFACES

View file

@ -20,6 +20,8 @@
#include "../snippets/code/os_stdlib_strtok_r.c"
#include "../snippets/code/os_stdlib_strsep.c"
#include "../snippets/code/os_stdlib_strdup.c"
#include "../snippets/code/os_stdlib_memdup.c"
#include "../snippets/code/os_stdlib_asprintf.c"
#include "../snippets/code/os_stdlib_rindex.c"
#include "../snippets/code/os_stdlib_strcasecmp.c"
#include "../snippets/code/os_stdlib_strncasecmp.c"

83
src/os/tests/ifaddrs.c Normal file
View file

@ -0,0 +1,83 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include "CUnit/Runner.h"
#include "os/os.h"
/* FIXME: It's not possible to predict what network interfaces are available
on a given host. To properly test all combinations the abstracted
operating system functions must be mocked. */
CUnit_Suite_Initialize(os_getifaddrs)
{
os_osInit();
return 0;
}
CUnit_Suite_Cleanup(os_getifaddrs)
{
os_osExit();
return 0;
}
/* Assume every test machine has at least one non-loopback IPv4 address. This
simple test verifies an interface can at least be found and that the
IFF_LOOPBACK flags are properly set. */
CUnit_Test(os_getifaddrs, ipv4)
{
int err;
int seen = 0;
os_ifaddrs_t *ifa_root, *ifa;
os_ifaddr_filter_t ifltr = { .af_inet = 1 };
err = os_getifaddrs(&ifa_root, &ifltr);
CU_ASSERT_EQUAL_FATAL(err, 0);
for (ifa = ifa_root; ifa; ifa = ifa->next) {
CU_ASSERT_EQUAL(ifa->addr->sa_family, AF_INET);
if (ifa->addr->sa_family == AF_INET) {
if (ifa->flags & IFF_LOOPBACK) {
CU_ASSERT(os_sockaddrIsLoopback(ifa->addr));
} else {
CU_ASSERT(!os_sockaddrIsLoopback(ifa->addr));
}
seen = 1;
}
}
CU_ASSERT_EQUAL(seen, 1);
os_freeifaddrs(ifa_root);
}
#ifdef OS_SOCKET_HAS_IPV6
CUnit_Test(os_getifaddrs, non_local_ipv6)
{
int err;
os_ifaddrs_t *ifa_root, *ifa;
os_ifaddr_filter_t ifltr = { .af_inet6 = 1 };
err = os_getifaddrs(&ifa_root, &ifltr);
CU_ASSERT_EQUAL_FATAL(err, 0);
for (ifa = ifa_root; ifa; ifa = ifa->next) {
CU_ASSERT_EQUAL(ifa->addr->sa_family, AF_INET6);
if (ifa->addr->sa_family == AF_INET6) {
if (ifa->flags & IFF_LOOPBACK) {
CU_ASSERT(os_sockaddrIsLoopback(ifa->addr));
} else {
CU_ASSERT(!os_sockaddrIsLoopback(ifa->addr));
}
}
}
os_freeifaddrs(ifa_root);
}
#endif /* OS_SOCKET_HAS_IPV6 */