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_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); 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); 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); void ddsi_ipaddr_from_loc (os_sockaddr_storage *dst, const nn_locator_t *src);
#endif #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 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 */ /* 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 (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); 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))) #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); 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; return AFSR_INVALID;
if ((ipv4 && tmpaddr.ss_family != AF_INET) || (!ipv4 && tmpaddr.ss_family != AF_INET6)) if ((ipv4 && tmpaddr.ss_family != AF_INET) || (!ipv4 && tmpaddr.ss_family != AF_INET6))
return AFSR_MISMATCH; 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. /* 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 */ Without a guarantee that tmpaddr has port 0, best is to set it explicitly here */
loc->port = NN_LOCATOR_PORT_INVALID; 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; 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; dst->kind = kind;
switch (src->ss_family) switch (src->sa_family)
{ {
case AF_INET: case AF_INET:
{ {
@ -137,7 +137,7 @@ void ddsi_ipaddr_to_loc (nn_locator_t *dst, const os_sockaddr_storage *src, int3
} }
#endif #endif
default: 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; int cnt = 0;
os_ifaddrs_t *ifa;
os_ifaddr_filter_t filt = { .af_packet = 1 };
(void)factory; (void)factory;
if (getifaddrs (&ifaddr) == -1)
return -errno; if ((err = os_getifaddrs(interfs, &filt)) == 0) {
for (ifa = ifaddr; ifa && cnt < max; ifa = ifa->ifa_next) for (ifa = *interfs; ifa != NULL; ifa = ifa->next, cnt++) {
{ /* do nothing */
struct os_ifAttributes_s *f = &interfs[cnt]; }
struct sockaddr_ll *x; } else {
if (ifa->ifa_addr == NULL) return -err;
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++;
} }
freeifaddrs (ifaddr);
return cnt; 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) static char *sockaddr_to_string_with_port (char *dst, size_t sizeof_dst, const os_sockaddr_storage *src)
{ {
nn_locator_t loc; 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); ddsi_locator_to_string(dst, sizeof_dst, &loc);
return dst; return dst;
} }
@ -452,7 +452,7 @@ static ssize_t ddsi_tcp_conn_read (ddsi_tran_conn_t conn, unsigned char * buf, s
{ {
if (srcloc) 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; 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]; char buff[DDSI_LOCSTRLEN];
ddsi_tcp_conn_t tc = (ddsi_tcp_conn_t) conn; ddsi_tcp_conn_t tc = (ddsi_tcp_conn_t) conn;
assert (tc->m_sock != Q_INVALID_SOCKET); 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); ddsi_locator_to_string(buff, sizeof(buff), loc);
TRACE (("(%s EP:%s)", ddsi_name, buff)); 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); 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); 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); (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; loc.port = conn->m_peer_port;
purge_proxy_participants (&loc, conn->m_base.m_server); 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; 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 */ /* FIXME: HACK */
if (factory->m_enumerate_interfaces_fn == 0) if (factory->m_enumerate_interfaces_fn == 0)
return 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 (ret > 0)
{ {
if (srcloc) 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 */ /* Check for udp packet truncation */
if ((((size_t) ret) > len) 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]; char addrbuf[DDSI_LOCSTRLEN];
nn_locator_t tmp; 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); ddsi_locator_to_string(addrbuf, sizeof(addrbuf), &tmp);
NN_WARNING ("%s => %d truncated to %d\n", addrbuf, (int)ret, (int)len); 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 = " "; const char *sep = " ";
char last_if_name[80] = ""; char last_if_name[80] = "";
int quality = -1; int quality = -1;
os_result res;
int i; int i;
unsigned int nif; os_ifaddrs_t *ifa, *ifa_root = NULL;
os_ifAttributes *ifs;
int maxq_list[MAX_INTERFACES]; int maxq_list[MAX_INTERFACES];
int maxq_count = 0; int maxq_count = 0;
size_t maxq_strlen = 0; size_t maxq_strlen = 0;
int selected_idx = -1; int selected_idx = -1;
char addrbuf[DDSI_LOCSTRLEN]; char addrbuf[DDSI_LOCSTRLEN];
ifs = os_malloc (MAX_INTERFACES * sizeof (*ifs));
nn_log (LC_CONFIG, "interfaces:"); nn_log (LC_CONFIG, "interfaces:");
{ {
int retcode; int retcode;
nif = 0; retcode = ddsi_enumerate_interfaces(gv.m_factory, &ifa_root);
retcode = ddsi_enumerate_interfaces(gv.m_factory, (int)(MAX_INTERFACES - nif), ifs); if (retcode < 0) {
if (retcode > 0) NN_ERROR("ddsi_enumerate_interfaces(%s): %d\n", gv.m_factory->m_typename, retcode);
{ } else if (retcode == 0) {
nif = (unsigned)retcode; int err;
res = os_resultSuccess; const os_ifaddr_filter_t fltr = {
} .af_inet = (config.transport_selector == TRANS_TCP || config.transport_selector == TRANS_UDP),
else if (retcode < 0) .af_inet6 = (config.transport_selector == TRANS_TCP6 || config.transport_selector == TRANS_UDP6)
{ };
NN_ERROR ("ddsi_enumerate_interfaces(%s): %d\n", gv.m_factory->m_typename, retcode);
res = os_resultFail; if ((err = os_getifaddrs(&ifa_root, &fltr)) != 0) {
} NN_ERROR("os_getifaddrs: %s\n", os_strerror(err));
else retcode = -1;
{ } else if (ifa_root == NULL) {
if (config.transport_selector == TRANS_TCP6 || config.transport_selector == TRANS_UDP6) NN_ERROR("ddsi_enumerate_interfaces(%s): no go but neither UDP[46] nor TCP[46]\n", gv.m_factory->m_typename);
res = os_sockQueryIPv6Interfaces (ifs, MAX_INTERFACES, &nif); retcode = -1;
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;
} }
} }
if (res != os_resultSuccess)
{ if (retcode < 0) {
NN_ERROR ("os_sockQueryInterfaces: %d\n", (int) res); os_freeifaddrs(ifa_root);
os_free (ifs);
return 0; return 0;
} }
} }
gv.n_interfaces = 0; gv.n_interfaces = 0;
last_if_name[0] = 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)]; char if_name[sizeof (last_if_name)];
int q = 0; 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_name[sizeof (if_name) - 1] = 0;
if (strcmp (if_name, last_if_name)) 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); strcpy (last_if_name, if_name);
/* interface must be up */ /* interface must be up */
if ((ifs[i].flags & IFF_UP) == 0) if ((ifa->flags & IFF_UP) == 0)
{ {
nn_log (LC_CONFIG, " (interface down)"); nn_log (LC_CONFIG, " (interface down)");
continue; continue;
} }
tmpip = ifs[i].address;
tmpmask = ifs[i].network_mask;
#ifdef __linux #ifdef __linux
if (tmpip.ss_family == AF_PACKET) if (ifa->addr->sa_family == AF_PACKET)
{ {
/* FIXME: weirdo warning warranted */ /* FIXME: weirdo warning warranted */
nn_locator_t *l = &gv.interfaces[gv.n_interfaces].loc; nn_locator_t *l = &gv.interfaces[gv.n_interfaces].loc;
l->kind = NN_LOCATOR_KIND_RAWETH; l->kind = NN_LOCATOR_KIND_RAWETH;
l->port = NN_LOCATOR_PORT_INVALID; l->port = NN_LOCATOR_PORT_INVALID;
memset(l->address, 0, 10); 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 else
#endif #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); ddsi_locator_to_string_no_port(addrbuf, sizeof(addrbuf), &gv.interfaces[gv.n_interfaces].loc);
nn_log (LC_CONFIG, " %s(", addrbuf); 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:"); 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 /* Loopback device has the lowest priority of every interface
available, because the other interfaces at least in principle available, because the other interfaces at least in principle
allow communicating with other machines. */ allow communicating with other machines. */
q += 0; q += 0;
#if OS_SOCKET_HAS_IPV6 #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; q += 1;
#endif #endif
} }
@ -575,16 +561,16 @@ int find_own_ip (const char *requested_address)
which it was received. But that means proper multi-homing which it was received. But that means proper multi-homing
support and has quite an impact in various places, not least of support and has quite an impact in various places, not least of
which is the abstraction layer. */ 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; q += 5;
#endif #endif
/* We strongly prefer a multicast capable interface, if that's /* We strongly prefer a multicast capable interface, if that's
not available anything that's not point-to-point, or else we not available anything that's not point-to-point, or else we
hope IP routing will take care of the issues. */ hope IP routing will take care of the issues. */
if (ifs[i].flags & IFF_MULTICAST) if (ifa->flags & IFF_MULTICAST)
q += 4; q += 4;
else if (!(ifs[i].flags & IFF_POINTOPOINT)) else if (!(ifa->flags & IFF_POINTOPOINT))
q += 3; q += 3;
else else
q += 2; q += 2;
@ -604,10 +590,9 @@ int find_own_ip (const char *requested_address)
/* FIXME: HACK HACK */ /* FIXME: HACK HACK */
//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, &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, ifa->netmask, gv.m_factory->m_kind);
ddsi_ipaddr_to_loc(&gv.interfaces[gv.n_interfaces].netmask, &tmpmask, gv.m_factory->m_kind);
} }
else else
{ {
@ -615,14 +600,14 @@ int find_own_ip (const char *requested_address)
gv.interfaces[gv.n_interfaces].netmask.port = NN_LOCATOR_PORT_INVALID; 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)); 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].mc_capable = ((ifa->flags & IFF_MULTICAST) != 0);
gv.interfaces[gv.n_interfaces].point_to_point = ((ifs[i].flags & IFF_POINTOPOINT) != 0); gv.interfaces[gv.n_interfaces].point_to_point = ((ifa->flags & IFF_POINTOPOINT) != 0);
gv.interfaces[gv.n_interfaces].if_index = ifs[i].interfaceIndexNo; gv.interfaces[gv.n_interfaces].if_index = ifa->index;
gv.interfaces[gv.n_interfaces].name = os_strdup (if_name); gv.interfaces[gv.n_interfaces].name = os_strdup (if_name);
gv.n_interfaces++; gv.n_interfaces++;
} }
nn_log (LC_CONFIG, "\n"); nn_log (LC_CONFIG, "\n");
os_free (ifs); os_freeifaddrs (ifa_root);
if (requested_address == NULL) if (requested_address == NULL)
{ {

View file

@ -17,10 +17,10 @@ IF(${platform} IN_LIST posix_platforms)
set(platform posix) set(platform posix)
ENDIF() 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) 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}) add_library(OSAPI ${srcs_os})
configure_file( configure_file(

View file

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

View file

@ -262,6 +262,9 @@ extern "C" {
__attribute_returns_nonnull__ __attribute_returns_nonnull__
__attribute_warn_unused_result__; __attribute_warn_unused_result__;
void *
os_memdup(void *src, size_t n);
/** \brief os_strsep wrapper /** \brief os_strsep wrapper
* *
* See strsep() * See strsep()
@ -271,6 +274,14 @@ extern "C" {
char **stringp, char **stringp,
const char *delim); 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 /** \brief os_vsnprintf wrapper
* *
* Microsoft generates deprected warnings for vsnprintf, * Microsoft generates deprected warnings for vsnprintf,

View file

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

View file

@ -25,7 +25,6 @@ extern "C" {
/* Keep defines before common header */ /* Keep defines before common header */
#define OS_SOCKET_HAS_IPV6 1 #define OS_SOCKET_HAS_IPV6 1
#define OS_IFNAMESIZE 128
#define OS_SOCKET_HAS_SA_LEN 0 #define OS_SOCKET_HAS_SA_LEN 0
#define OS_NO_SIOCGIFINDEX 1 #define OS_NO_SIOCGIFINDEX 1
#define OS_NO_NETLINK 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; 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 <ctype.h>
#include "os_stdlib_strsep.c" #include "os_stdlib_strsep.c"
#include "os_stdlib_memdup.c"
#include "os_stdlib_rindex.c" #include "os_stdlib_rindex.c"
#include "os_stdlib_asprintf.c"
#include "os_stdlib_strcasecmp.c" #include "os_stdlib_strcasecmp.c"
#include "os_stdlib_strncasecmp.c" #include "os_stdlib_strncasecmp.c"
#include "os_stdlib_strdup.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; 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_strtok_r.c"
#include "../snippets/code/os_stdlib_strsep.c" #include "../snippets/code/os_stdlib_strsep.c"
#include "../snippets/code/os_stdlib_strdup.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_rindex.c"
#include "../snippets/code/os_stdlib_strcasecmp.c" #include "../snippets/code/os_stdlib_strcasecmp.c"
#include "../snippets/code/os_stdlib_strncasecmp.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 */