aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRaimo Niskanen <[email protected]>2010-10-14 16:56:43 +0200
committerRaimo Niskanen <[email protected]>2010-11-09 12:14:57 +0100
commitce4c78512fccda58e75c4846ced1c3a4e10d7454 (patch)
tree91249b26f7b2c6e2d3962a019e2d74a9d9451c89
parentff7a4dbd6881e2434ed2619df541c113281cf0a0 (diff)
downloadotp-ce4c78512fccda58e75c4846ced1c3a4e10d7454.tar.gz
otp-ce4c78512fccda58e75c4846ced1c3a4e10d7454.tar.bz2
otp-ce4c78512fccda58e75c4846ced1c3a4e10d7454.zip
Implement inet:getifaddrs/0 on Windows
-rw-r--r--erts/aclocal.m414
-rwxr-xr-xerts/autoconf/win32.config.cache.static1
-rw-r--r--erts/emulator/drivers/common/inet_drv.c686
-rw-r--r--erts/etc/common/inet_gethost.c1
-rwxr-xr-xerts/etc/win32/cygwin_tools/vc/ld.sh2
-rw-r--r--erts/preloaded/ebin/prim_inet.beambin64188 -> 65184 bytes
-rw-r--r--erts/preloaded/src/prim_inet.erl39
7 files changed, 699 insertions, 44 deletions
diff --git a/erts/aclocal.m4 b/erts/aclocal.m4
index 3b1edd7605..0d7914fbb8 100644
--- a/erts/aclocal.m4
+++ b/erts/aclocal.m4
@@ -386,14 +386,24 @@ AC_DEFUN(LM_SYS_IPV6,
AC_CACHE_VAL(ac_cv_sys_ipv6_support,
[ok_so_far=yes
AC_TRY_COMPILE([#include <sys/types.h>
-#include <netinet/in.h>],
+#ifdef __WIN32__
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#else
+#include <netinet/in.h>
+#endif],
[struct in6_addr a6; struct sockaddr_in6 s6;], ok_so_far=yes, ok_so_far=no)
if test $ok_so_far = yes; then
ac_cv_sys_ipv6_support=yes
else
AC_TRY_COMPILE([#include <sys/types.h>
-#include <netinet/in.h>],
+#ifdef __WIN32__
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#else
+#include <netinet/in.h>
+#endif],
[struct in_addr6 a6; struct sockaddr_in6 s6;],
ac_cv_sys_ipv6_support=in_addr6, ac_cv_sys_ipv6_support=no)
fi
diff --git a/erts/autoconf/win32.config.cache.static b/erts/autoconf/win32.config.cache.static
index 31dfe510cd..cc33fc09b3 100755
--- a/erts/autoconf/win32.config.cache.static
+++ b/erts/autoconf/win32.config.cache.static
@@ -212,7 +212,6 @@ ac_cv_sizeof_void_p=${ac_cv_sizeof_void_p=4}
ac_cv_struct_exception=${ac_cv_struct_exception=no}
ac_cv_struct_sockaddr_sa_len=${ac_cv_struct_sockaddr_sa_len=no}
ac_cv_struct_tm=${ac_cv_struct_tm=time.h}
-ac_cv_sys_ipv6_support=${ac_cv_sys_ipv6_support=no}
ac_cv_sys_multicast_support=${ac_cv_sys_multicast_support=no}
ac_cv_type_char=${ac_cv_type_char=yes}
ac_cv_type_int=${ac_cv_type_int=yes}
diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c
index 4ee0e968d7..70439ba3f4 100644
--- a/erts/emulator/drivers/common/inet_drv.c
+++ b/erts/emulator/drivers/common/inet_drv.c
@@ -88,6 +88,7 @@
#include <winsock2.h>
#endif
#include <windows.h>
+#include <iphlpapi.h>
#include <Ws2tcpip.h> /* NEED VC 6.0 !!! */
@@ -3864,7 +3865,6 @@ static char* sockaddr_to_buf(struct sockaddr* addr, char* ptr, char* end)
return ptr;
error:
return NULL;
-
}
static char* buf_to_sockaddr(char* ptr, char* end, struct sockaddr* addr)
@@ -3891,6 +3891,19 @@ static char* buf_to_sockaddr(char* ptr, char* end, struct sockaddr* addr)
}
+#if defined (IFF_POINTOPOINT)
+#define IFGET_FLAGS(cflags) IFGET_FLAGS_P2P(cflags, IFF_POINTOPOINT)
+#elif defined IFF_POINTTOPOINT
+#define IFGET_FLAGS(cflags) IFGET_FLAGS_P2P(cflags, IFF_POINTTOPOINT)
+#endif
+
+#define IFGET_FLAGS_P2P(cflags, iff_ptp) \
+ ((((cflags) & IFF_UP) ? INET_IFF_UP : 0) | \
+ (((cflags) & IFF_BROADCAST) ? INET_IFF_BROADCAST : 0) | \
+ (((cflags) & IFF_LOOPBACK) ? INET_IFF_LOOPBACK : 0) | \
+ (((cflags) & iff_ptp) ? INET_IFF_POINTTOPOINT : 0) | \
+ (((cflags) & IFF_UP) ? INET_IFF_RUNNING : 0) | /* emulate running ? */ \
+ (((cflags) & IFF_MULTICAST) ? INET_IFF_MULTICAST : 0))
#if defined(__WIN32__) && defined(SIO_GET_INTERFACE_LIST)
@@ -4125,14 +4138,6 @@ static int inet_ctl_getiflist(inet_descriptor* desc, char** rbuf, int rsize)
#define IFHWADDRLEN 6
#endif
-#define IFGET_FLAGS(cflags) \
- ((((cflags) & IFF_UP) ? INET_IFF_UP : 0) | \
- (((cflags) & IFF_BROADCAST) ? INET_IFF_BROADCAST : 0) | \
- (((cflags) & IFF_LOOPBACK) ? INET_IFF_LOOPBACK : 0) | \
- (((cflags) & IFF_POINTOPOINT) ? INET_IFF_POINTTOPOINT : 0) | \
- (((cflags) & IFF_UP) ? INET_IFF_RUNNING : 0) | /* emulate running ? */ \
- (((cflags) & IFF_MULTICAST) ? INET_IFF_MULTICAST : 0))
-
static int inet_ctl_ifget(inet_descriptor* desc, char* buf, int len,
char** rbuf, int rsize)
{
@@ -4456,7 +4461,619 @@ static int inet_ctl_ifset(inet_descriptor* desc, char* buf, int len,
-#if defined(HAVE_GETIFADDRS)
+static int utf8_len(const char *c, int m) {
+ int l;
+ for (l = 0; m; c++, l++, m--) {
+ if (*c == '\0') break;
+ if ((*c & 0x7f) != *c) l++;
+ }
+ return l;
+}
+
+static void utf8_encode(const char *c, int m, char *p) {
+ for (; m; c++, m--) {
+ if (*c == '\0') break;
+ if ((*c & 0x7f) != *c) {
+ *p++ = (char) (0xC0 | (0x03 & (*c >> 6)));
+ *p++ = (char) (0x80 | (0x3F & *c));
+ } else {
+ *p++ = (char) *c;
+ }
+ }
+}
+
+#if defined(__WIN32__)
+
+#if 0
+static void print_addr(char *f, char *g, char *h, char *b, int len) {
+ unsigned char *p = (unsigned char *)b;
+ for (; len > 0; len--, p++) {
+ erts_printf(len == 1 ? h : len & 1 ? g : f, *p);
+ }
+}
+
+static void print_ipv4_address(char *b) {
+ print_addr("%d.","%d.","%d", b, 4);
+}
+
+static void print_hwaddr(char *b, int len) {
+ print_addr("%02x:","%02x:","%02x", b, len);
+}
+
+static void print_sockaddr(struct sockaddr *sa_p) {
+ if (sa_p->sa_family == AF_INET) {
+ struct sockaddr_in *sin_p =
+ (struct sockaddr_in *) sa_p;
+ print_ipv4_address((char *) &sin_p->sin_addr);
+ } else if(sa_p->sa_family == AF_INET6) {
+ struct sockaddr_in6 *sin6_p =
+ (struct sockaddr_in6 *) sa_p;
+ print_addr("%02x","%02x:","%02x", (char *) &sin6_p->sin6_addr, 16);
+ }
+}
+
+static void print_flags(MIB_IFROW *ifrow_p) {
+ /* Interface flags */
+ switch (ifrow_p->dwType) {
+ case IF_TYPE_ETHERNET_CSMACD:
+ /* Fake broadcast and multicast flag */
+ erts_printf("broadcast multicast ");
+ break;
+ case IF_TYPE_SOFTWARE_LOOPBACK:
+ erts_printf("loopback ");
+ break;
+ }
+ if (ifrow_p->dwAdminStatus) {
+ erts_printf("up ");
+ switch (ifrow_p->dwOperStatus) {
+ case IF_OPER_STATUS_CONNECTING:
+ erts_printf("pointtopoint ");
+ break;
+ case IF_OPER_STATUS_CONNECTED:
+ erts_printf("running pointtopoint ");
+ break;
+ case IF_OPER_STATUS_OPERATIONAL:
+ erts_printf("running ");
+ break;
+ }
+ }
+}
+#endif
+
+static void set_netmask_bytes(char *c, int len, int pref_len) {
+ int i, m;
+ for (i = 0, m = pref_len >> 3; i < m && i < len; i++) c[i] = '\xFF';
+ if (i < len) c[i++] = 0xFF << (8 - (pref_len & 7));
+ for (; i < len; i++) c[i] = '\0';
+}
+
+
+int eq_masked_bytes(char *a, char *b, int pref_len) {
+ int i, m;
+ for (i = 0, m = pref_len >> 3; i < m; i++) {
+ if (a[i] != b[i]) return 0;
+ }
+ m = pref_len & 7;
+ if (m) {
+ m = 0xFF & (0xFF << (8 - m));
+ if ((a[i] & m) != (b[i] & m)) return 0;
+ }
+ return !0;
+}
+
+#if 0
+static void set_netmask(struct sockaddr *sa_p, int pref_len) {
+ switch (sa_p->sa_family) {
+ case AF_INET: {
+ struct sockaddr_in *sin_p = (struct sockaddr_in *) sa_p;
+ set_netmask_bytes((char *) &sin_p->sin_addr, 4, pref_len);
+ break;
+ }
+ case AF_INET6: {
+ struct sockaddr_in6 *sin6_p = (struct sockaddr_in6 *) sa_p;
+ set_netmask_bytes((char *) &sin6_p->sin6_addr, 16, pref_len);
+ break;
+ }
+ }
+}
+#endif
+
+static int inet_ctl_getifaddrs(inet_descriptor* desc_p,
+ char **rbuf_pp, int rsize)
+{
+ int i;
+ DWORD ret, n;
+ IP_INTERFACE_INFO *info_p;
+ MIB_IPADDRTABLE *ip_addrs_p;
+ IP_ADAPTER_ADDRESSES *ip_adaddrs_p, *ia_p;
+
+ char *buf_p;
+ char *buf_alloc_p;
+ int buf_size =512;
+# define BUF_ENSURE(Size) \
+ do { \
+ int NEED_, GOT_ = buf_p - buf_alloc_p; \
+ NEED_ = GOT_ + (Size); \
+ if (NEED_ > buf_size) { \
+ buf_size = NEED_ + 512; \
+ buf_alloc_p = REALLOC(buf_alloc_p, buf_size); \
+ buf_p = buf_alloc_p + GOT_; \
+ } \
+ } while(0)
+# define SOCKADDR_TO_BUF(opt, sa) \
+ do { \
+ if (sa) { \
+ char *P_; \
+ *buf_p++ = (opt); \
+ while (! (P_ = sockaddr_to_buf((sa), buf_p, \
+ buf_alloc_p+buf_size))) { \
+ int GOT_ = buf_p - buf_alloc_p; \
+ buf_size += 512; \
+ buf_alloc_p = REALLOC(buf_alloc_p, buf_size); \
+ buf_p = buf_alloc_p + GOT_; \
+ } \
+ if (P_ == buf_p) { \
+ buf_p--; \
+ } else { \
+ buf_p = P_; \
+ } \
+ } \
+ } while (0)
+
+ {
+ /* Try GetAdaptersAddresses, if it is available */
+ unsigned long ip_adaddrs_size = 16 * 1024;
+ ULONG family = AF_UNSPEC;
+ ULONG flags =
+ GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_SKIP_ANYCAST |
+ GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME |
+ GAA_FLAG_SKIP_MULTICAST;
+ ULONG (WINAPI *fpGetAdaptersAddresses)
+ (ULONG, ULONG, PVOID, PIP_ADAPTER_ADDRESSES, PULONG);
+ HMODULE iphlpapi = GetModuleHandle("iphlpapi");
+ /*iphlpapi = NULL*/;
+ fpGetAdaptersAddresses = (void *)
+ (iphlpapi ?
+ GetProcAddress(iphlpapi, "GetAdaptersAddresses") :
+ NULL);
+ if (fpGetAdaptersAddresses) {
+ ip_adaddrs_p = ALLOC(ip_adaddrs_size);
+ for (i = 17; i; i--) {
+ ret = fpGetAdaptersAddresses(
+ family, flags, NULL, ip_adaddrs_p, &ip_adaddrs_size);
+ ip_adaddrs_p = REALLOC(ip_adaddrs_p, ip_adaddrs_size);
+ if (ret == NO_ERROR) break;
+ if (ret == ERROR_BUFFER_OVERFLOW) continue;
+ i = 0;
+ }
+ if (! i) {
+ FREE(ip_adaddrs_p);
+ ip_adaddrs_p = NULL;
+ }
+ } else ip_adaddrs_p = NULL;
+ }
+
+ {
+ /* Load the IP_INTERFACE_INFO table (only IPv4 interfaces),
+ * reliable source of interface names on XP
+ */
+ unsigned long info_size = 4 * 1024;
+ info_p = ALLOC(info_size);
+ for (i = 17; i; i--) {
+ ret = GetInterfaceInfo(info_p, &info_size);
+ info_p = REALLOC(info_p, info_size);
+ if (ret == NO_ERROR) break;
+ if (ret == ERROR_INSUFFICIENT_BUFFER) continue;
+ i = 0;
+ }
+ if (! i) {
+ FREE(info_p);
+ info_p = NULL;
+ }
+ }
+
+ if (! ip_adaddrs_p) {
+ /* If GetAdaptersAddresses gave nothing we fall back to
+ * MIB_IPADDRTABLE (only IPv4 interfaces)
+ */
+ unsigned long ip_addrs_size = 16 * sizeof(*ip_addrs_p);
+ ip_addrs_p = ALLOC(ip_addrs_size);
+ for (i = 17; i; i--) {
+ ret = GetIpAddrTable(ip_addrs_p, &ip_addrs_size, FALSE);
+ ip_addrs_p = REALLOC(ip_addrs_p, ip_addrs_size);
+ if (ret == NO_ERROR) break;
+ if (ret == ERROR_INSUFFICIENT_BUFFER) continue;
+ i = 0;
+ }
+ if (! i) {
+ if (info_p) FREE(info_p);
+ FREE(ip_addrs_p);
+ return ctl_reply(INET_REP_OK, NULL, 0, rbuf_pp, rsize);
+ }
+ } else ip_addrs_p = NULL;
+
+#if 0
+ /* Debug printout of what GetAdaptersAddresses returned */
+ if (ip_adaddrs_p) {
+ IP_ADAPTER_ADDRESSES *p = ip_adaddrs_p;
+ printf("* GetAdaptersAddresses:\n");
+ for (; p; p = p->Next) {
+ IP_ADAPTER_UNICAST_ADDRESS *iaua_p;
+ IP_ADAPTER_ANYCAST_ADDRESS *iaaa_p;
+ IP_ADAPTER_PREFIX *iap_p;
+ MIB_IFROW ifrow;
+ erts_printf("AdapterName: %s\n", p->AdapterName);
+ if (p->Flags & IP_ADAPTER_NO_MULTICAST) {
+ erts_printf("AdapterFlags: -multicast\n");
+ }
+ for (iaua_p = p->FirstUnicastAddress;
+ iaua_p;
+ iaua_p = iaua_p->Next) {
+ erts_printf("UnicastAddress: ");
+ print_sockaddr(iaua_p->Address.lpSockaddr);
+ erts_printf("\n");
+ }
+ for (iaaa_p = p->FirstAnycastAddress;
+ iaaa_p;
+ iaaa_p = iaaa_p->Next) {
+ erts_printf("AnycastAddress: ");
+ print_sockaddr(iaaa_p->Address.lpSockaddr);
+ erts_printf("\n");
+ }
+ for (iap_p = p->FirstPrefix;
+ iap_p;
+ iap_p = iap_p->Next) {
+ erts_printf("AddressPrefix: ");
+ print_sockaddr(iap_p->Address.lpSockaddr);
+ erts_printf("/%lu\n", iap_p->PrefixLength);
+ }
+ erts_printf("PhysicalAddress: ");
+ print_hwaddr(p->PhysicalAddress, p->PhysicalAddressLength);
+ erts_printf("\n");
+ if (p->IfIndex) {
+ erts_printf(
+ "IPv4AdapterIndex: %lu\n", (unsigned long) p->IfIndex);
+ sys_memzero(&ifrow, sizeof(ifrow));
+ ifrow.dwIndex = p->IfIndex;
+ if (GetIfEntry(&ifrow) == NO_ERROR) {
+ printf("InterfaceName: %ws\n", ifrow.wszName);
+ printf("InterfaceFlags: ");
+ print_flags(&ifrow);
+ erts_printf("\n");
+ }
+ }
+ if (p->Ipv6IfIndex) {
+ erts_printf(
+ "IPv6AdapterIndex: %lu\n", (unsigned long) p->Ipv6IfIndex);
+ sys_memzero(&ifrow, sizeof(ifrow));
+ ifrow.dwIndex = p->Ipv6IfIndex;
+ if (GetIfEntry(&ifrow) == NO_ERROR) {
+ printf("InterfaceName: %ws\n", ifrow.wszName);
+ printf("InterfaceFlags: ");
+ print_flags(&ifrow);
+ erts_printf("\n");
+ }
+ }
+ }
+ }
+#endif
+
+#if 0
+ /* Debug printout of what GetInterfaceInfo returned */
+ if (info_p) {
+ printf("* GetInterfaceInfo:\n");
+ for (i = 0; i < info_p->NumAdapters; i++) {
+ printf("AdapterIndex[%d]: %ld\n", i, info_p->Adapter[i].Index);
+ printf("AdapterName[%d]: %lws\n", i, info_p->Adapter[i].Name);
+ }
+ }
+#endif
+
+ buf_p = buf_alloc_p = ALLOC(buf_size);
+ *buf_p++ = INET_REP_OK;
+
+ /* Iterate over MIB_IPADDRTABLE or IP_ADAPTER_ADDRESSES */
+ for (ia_p = NULL, ip_addrs_p ? ((void *)(i = 0)) : (ia_p = ip_adaddrs_p);
+ ip_addrs_p ? (i < ip_addrs_p->dwNumEntries) : (ia_p != NULL);
+ ip_addrs_p ? ((void *)(i++)) : (ia_p = ia_p->Next)) {
+ MIB_IPADDRROW *ipaddrrow_p = NULL;
+ DWORD flags = INET_IFF_MULTICAST;
+ DWORD index = 0;
+ WCHAR *wname_p = NULL;
+ MIB_IFROW ifrow;
+
+ if (ip_addrs_p) {
+ ipaddrrow_p = ip_addrs_p->table + i;
+ index = ipaddrrow_p->dwIndex;
+ } else {
+ index = ia_p->IfIndex;
+ if (ia_p->Flags & IP_ADAPTER_NO_MULTICAST) {
+ flags &= ~INET_IFF_MULTICAST;
+ }
+ }
+index:
+ if (! index) goto done;
+ sys_memzero(&ifrow, sizeof(ifrow));
+ ifrow.dwIndex = index;
+ if (GetIfEntry(&ifrow) != NO_ERROR) break;
+/* printf("Index[%d]: %ld\n", i, (long) ifrow.dwIndex);*/
+ /* Find the interface name - first try MIB_IFROW.wzname */
+ if (ifrow.wszName[0] != 0) {
+ wname_p = ifrow.wszName;
+ } else {
+ /* Then try IP_ADAPTER_INDEX_MAP.Name (only IPv4 adapters) */
+ int j;
+ for (j = 0; j < info_p->NumAdapters; j++) {
+ if (info_p->Adapter[j].Index == (ULONG) ifrow.dwIndex) {
+ if (info_p->Adapter[j].Name[0] != 0) {
+ wname_p = info_p->Adapter[j].Name;
+ }
+ break;
+ }
+ }
+ }
+ if (wname_p) {
+ int len;
+/* printf("InterfaceName [%d]: %ws\n", i, ifrow.wszName);*/
+ /* Convert interface name to UTF-8 */
+ len =
+ WideCharToMultiByte(
+ CP_UTF8, 0, wname_p, -1, NULL, 0, NULL, NULL);
+ if (! len) break;
+ BUF_ENSURE(len);
+ WideCharToMultiByte(
+ CP_UTF8, 0, wname_p, -1, buf_p, len, NULL, NULL);
+ buf_p += len;
+ } else {
+ /* Found no name -
+ * use "MIB_IFROW.dwIndex: MIB_IFROW.bDescr" as name instead */
+ int l;
+ l = utf8_len(ifrow.bDescr, ifrow.dwDescrLen);
+/* printf("Adapter Name[%d]: ", i);*/
+ BUF_ENSURE(9 + l+1);
+ buf_p +=
+ erts_sprintf(
+ buf_p, "%lu: ", (unsigned long) ifrow.dwIndex);
+ utf8_encode(ifrow.bDescr, ifrow.dwDescrLen, buf_p);
+ buf_p += l;
+ *buf_p++ = '\0';
+ }
+ /* Interface flags, often make up broadcast and multicast flags */
+ switch (ifrow.dwType) {
+ case IF_TYPE_ETHERNET_CSMACD:
+ flags |= INET_IFF_BROADCAST;
+ break;
+ case IF_TYPE_SOFTWARE_LOOPBACK:
+ flags |= INET_IFF_LOOPBACK;
+ flags &= ~INET_IFF_MULTICAST;
+ break;
+ default:
+ flags &= ~INET_IFF_MULTICAST;
+ break;
+ }
+ if (ifrow.dwAdminStatus) {
+ flags |= INET_IFF_UP;
+ switch (ifrow.dwOperStatus) {
+ case IF_OPER_STATUS_CONNECTING:
+ flags |= INET_IFF_POINTTOPOINT;
+ break;
+ case IF_OPER_STATUS_CONNECTED:
+ flags |= INET_IFF_RUNNING | INET_IFF_POINTTOPOINT;
+ break;
+ case IF_OPER_STATUS_OPERATIONAL:
+ flags |= INET_IFF_RUNNING;
+ break;
+ }
+ }
+ BUF_ENSURE(1 + 4);
+ *buf_p++ = INET_IFOPT_FLAGS;
+ put_int32(flags, buf_p); buf_p += 4;
+ if (ipaddrrow_p) {
+ /* Legacy implementation through GetIpAddrTable */
+ struct sockaddr_in sin;
+ /* IP Address */
+ sys_memzero(&sin, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = ipaddrrow_p->dwAddr;
+/* erts_printf("IP Address: ");
+ * print_sockaddr((struct sockaddr *) &sin);
+ * erts_printf("\n");*/
+ BUF_ENSURE(1);
+ /* Netmask */
+ SOCKADDR_TO_BUF(INET_IFOPT_ADDR, (struct sockaddr *) &sin);
+ sin.sin_addr.s_addr = ipaddrrow_p->dwMask;
+/* erts_printf("IP Mask: ");
+ * print_sockaddr((struct sockaddr *) &sin);
+ * erts_printf("\n");*/
+ BUF_ENSURE(1);
+ SOCKADDR_TO_BUF(INET_IFOPT_NETMASK, (struct sockaddr *) &sin);
+ if (flags & INET_IFF_BROADCAST) {
+ /* Broadcast address - fake it*/
+ sin.sin_addr.s_addr = ipaddrrow_p->dwAddr;
+ sin.sin_addr.s_addr |= ~ipaddrrow_p->dwMask;
+/* erts_printf("IP Broadcast: ");
+ * print_sockaddr((struct sockaddr *) &sin);
+ * erts_printf("\n");*/
+ BUF_ENSURE(1);
+ SOCKADDR_TO_BUF(
+ INET_IFOPT_BROADADDR, (struct sockaddr *) &sin);
+ }
+ } else {
+ IP_ADAPTER_UNICAST_ADDRESS *p;
+ /* IP Address(es) */
+ for (p = ia_p->FirstUnicastAddress;
+ p;
+ p = p->Next)
+ {
+ IP_ADAPTER_PREFIX *q;
+ ULONG shortest_length;
+ struct sockaddr *shortest_p, *sa_p = p->Address.lpSockaddr;
+/* erts_printf("UnicastAddress: ");
+ * print_sockaddr(sa_p);
+ * erts_printf("\n");*/
+ BUF_ENSURE(1);
+ SOCKADDR_TO_BUF(INET_IFOPT_ADDR, sa_p);
+ shortest_p = NULL;
+ shortest_length = 0;
+ for (q = ia_p->FirstPrefix;
+ q;
+ q = q->Next) {
+ struct sockaddr *sp_p = q->Address.lpSockaddr;
+ if (sa_p->sa_family != sp_p->sa_family) continue;
+ switch (sa_p->sa_family) {
+ case AF_INET: {
+ struct sockaddr_in sin;
+ DWORD sa, sp, mask;
+ sa = ntohl((DWORD)
+ ((struct sockaddr_in *)
+ sa_p)->sin_addr.s_addr);
+ sp = ntohl((DWORD)
+ ((struct sockaddr_in *)
+ sp_p)->sin_addr.s_addr);
+ mask = 0xFFFFFFFF << (32 - q->PrefixLength);
+ if ((sa & mask) != (sp & mask)) continue;
+ if ((! shortest_p)
+ || q->PrefixLength < shortest_length) {
+ shortest_p = sp_p;
+ shortest_length = q->PrefixLength;
+ }
+ } break;
+ case AF_INET6: {
+ struct sockaddr_in6 sin6;
+ if (!eq_masked_bytes((char *)
+ &((struct sockaddr_in6 *)
+ sa_p)->sin6_addr,
+ (char *)
+ &((struct sockaddr_in6 *)
+ sp_p)->sin6_addr,
+ q->PrefixLength)) {
+ continue;
+ }
+ if ((! shortest_p)
+ || q->PrefixLength < shortest_length) {
+ shortest_p = sp_p;
+ shortest_length = q->PrefixLength;
+ }
+ } break;
+ }
+ }
+ if (! shortest_p) {
+ /* Found no shortest prefix */
+ shortest_p = sa_p;
+ switch (shortest_p->sa_family) {
+ case AF_INET: {
+ /* Fall back to old classfull network addresses */
+/* erts_printf("! shortest_p: ");
+ * print_sockaddr(shortest_p);
+ * erts_printf("\n");*/
+ DWORD addr = ntohl(((struct sockaddr_in *)shortest_p)
+ ->sin_addr.s_addr);
+ if (! (addr & 0x800000)) {
+ /* Class A */
+ shortest_length = 8;
+ } else if (! (addr & 0x400000)) {
+ /* Class B */
+ shortest_length = 16;
+ } else if (! (addr & 0x200000)) {
+ /* Class C */
+ shortest_length = 24;
+ } else {
+ shortest_length = 32;
+ }
+ } break;
+ case AF_INET6: {
+ /* Just play it safe */
+ shortest_length = 128;
+ } break;
+ }
+ } else {
+/* erts_printf("shortest_p: ");
+ * print_sockaddr(shortest_p);
+ * erts_printf("\n");*/
+ }
+ switch (shortest_p->sa_family) {
+ case AF_INET: {
+ struct sockaddr_in sin;
+ DWORD mask = 0xFFFFFFFF << (32 - shortest_length);
+ sys_memzero(&sin, sizeof(sin));
+ sin.sin_family = shortest_p->sa_family;
+ sin.sin_addr.s_addr = htonl(mask);
+/* erts_printf("IP Mask: ");
+ * print_sockaddr((struct sockaddr *) &sin);
+ * erts_printf("\n");*/
+ BUF_ENSURE(1);
+ SOCKADDR_TO_BUF(INET_IFOPT_NETMASK,
+ (struct sockaddr *) &sin);
+ if (flags & INET_IFF_BROADCAST) {
+ DWORD sp =
+ ntohl((DWORD)
+ ((struct sockaddr_in *)shortest_p)
+ -> sin_addr.s_addr);
+ sin.sin_addr.s_addr = htonl(sp | ~mask);
+/* erts_printf("IP Broadcast: ");
+ * print_sockaddr((struct sockaddr *) &sin);
+ * erts_printf("\n");*/
+ BUF_ENSURE(1);
+ SOCKADDR_TO_BUF(INET_IFOPT_BROADADDR,
+ (struct sockaddr *) &sin);
+ }
+ } break;
+ case AF_INET6: {
+ struct sockaddr_in6 sin6;
+ sys_memzero(&sin6, sizeof(sin6));
+ sin6.sin6_family = shortest_p->sa_family;
+ set_netmask_bytes((char *) &sin6.sin6_addr,
+ 16,
+ shortest_length);
+/* erts_printf("IP Mask: ");
+ * print_sockaddr((struct sockaddr *) &sin6);
+ * erts_printf("\n");*/
+ BUF_ENSURE(1);
+ SOCKADDR_TO_BUF(INET_IFOPT_NETMASK,
+ (struct sockaddr *) &sin6);
+ } break;
+ }
+ }
+ }
+ if (ifrow.dwPhysAddrLen) {
+ /* Hardware Address */
+/* printf("Physical Addr:");
+ * print_hwaddr(ifrow.bPhysAddr, ifrow.dwPhysAddrLen);
+ * erts_printf("\n");*/
+ BUF_ENSURE(1 + 2 + ifrow.dwPhysAddrLen);
+ *buf_p++ = INET_IFOPT_HWADDR;
+ put_int16(ifrow.dwPhysAddrLen, buf_p); buf_p += 2;
+ sys_memcpy(buf_p, ifrow.bPhysAddr, ifrow.dwPhysAddrLen);
+ buf_p += ifrow.dwPhysAddrLen;
+ }
+
+done:
+ /* That is all for this interface */
+ BUF_ENSURE(1);
+ *buf_p++ = '\0';
+ if (ia_p &&
+ ia_p->Ipv6IfIndex &&
+ ia_p->Ipv6IfIndex != index)
+ {
+ /* Oops, there was an other interface for IPv6. Possible? XXX */
+ index = ia_p->Ipv6IfIndex;
+ goto index;
+ }
+ }
+
+ if (ip_adaddrs_p) FREE(ip_adaddrs_p);
+ if (info_p) FREE(info_p);
+ if (ip_addrs_p) FREE(ip_addrs_p);
+
+ buf_size = buf_p - buf_alloc_p;
+ buf_alloc_p = REALLOC(buf_alloc_p, buf_size);
+ /* buf_p is now unreliable */
+ *rbuf_pp = buf_alloc_p;
+ return buf_size;
+# undef BUF_ENSURE
+}
+
+#elif defined(HAVE_GETIFADDRS)
static int inet_ctl_getifaddrs(inet_descriptor* desc_p,
char **rbuf_pp, int rsize)
@@ -4470,31 +5087,32 @@ static int inet_ctl_getifaddrs(inet_descriptor* desc_p,
buf_size = 512;
buf_alloc_p = ALLOC(buf_size);
buf_p = buf_alloc_p;
-# define BUF_ENSURE(Size) \
- do { \
- int need, got = buf_p - buf_alloc_p; \
- need = got + (Size); \
- if (need > buf_size) { \
- buf_size = need + 512; \
- buf_alloc_p = REALLOC(buf_alloc_p, buf_size); \
- buf_p = buf_alloc_p + got; \
- } \
- } while(0)
+# define BUF_ENSURE(Size) \
+ do { \
+ int NEED_, GOT_ = buf_p - buf_alloc_p; \
+ NEED_ = GOT_ + (Size); \
+ if (NEED_ > buf_size) { \
+ buf_size = NEED_ + 512; \
+ buf_alloc_p = REALLOC(buf_alloc_p, buf_size); \
+ buf_p = buf_alloc_p + GOT_; \
+ } \
+ } while (0)
# define SOCKADDR_TO_BUF(opt, sa) \
do { \
if (sa) { \
- char *p; \
+ char *P_; \
*buf_p++ = (opt); \
- while (! (p = sockaddr_to_buf((sa), buf_p, \
- buf_alloc_p+buf_size))) { \
- int got = buf_p - buf_alloc_p; \
- buf_alloc_p = REALLOC(buf_alloc_p, buf_size+512); \
- buf_p = buf_alloc_p + got; \
+ while (! (P_ = sockaddr_to_buf((sa), buf_p, \
+ buf_alloc_p+buf_size))) { \
+ int GOT_ = buf_p - buf_alloc_p; \
+ buf_size += 512; \
+ buf_alloc_p = REALLOC(buf_alloc_p, buf_size); \
+ buf_p = buf_alloc_p + GOT_; \
} \
- if (p == buf_p) { \
+ if (P_ == buf_p) { \
buf_p--; \
} else { \
- buf_p = p; \
+ buf_p = P_; \
} \
} \
} while (0)
@@ -4505,13 +5123,13 @@ static int inet_ctl_getifaddrs(inet_descriptor* desc_p,
ifa_free_p = ifa_p;
*buf_p++ = INET_REP_OK;
for (; ifa_p; ifa_p = ifa_p->ifa_next) {
- int len = strlen(ifa_p->ifa_name) + 1;
- BUF_ENSURE(len + 1+4 + 1);
- sys_memcpy(buf_p, ifa_p->ifa_name, len);
+ int len = utf8_len(ifa_p->ifa_name, -1);
+ BUF_ENSURE(len+1 + 1+4 + 1);
+ utf8_encode(ifa_p->ifa_name, -1, buf_p);
buf_p += len;
+ *buf_p++ = '\0';
*buf_p++ = INET_IFOPT_FLAGS;
- put_int32(IFGET_FLAGS(ifa_p->ifa_flags), buf_p);
- buf_p += 4;
+ put_int32(IFGET_FLAGS(ifa_p->ifa_flags), buf_p); buf_p += 4;
if (ifa_p->ifa_addr->sa_family == AF_INET
#if defined(AF_INET6)
|| ifa_p->ifa_addr->sa_family == AF_INET6
@@ -4539,8 +5157,10 @@ static int inet_ctl_getifaddrs(inet_descriptor* desc_p,
|| ifa_p->ifa_addr->sa_family == AF_PACKET
#endif
) {
+ char *bp = buf_p;
BUF_ENSURE(1);
SOCKADDR_TO_BUF(INET_IFOPT_HWADDR, ifa_p->ifa_addr);
+ if (buf_p - bp < 4) buf_p = bp; /* Empty hwaddr */
}
#endif
BUF_ENSURE(1);
diff --git a/erts/etc/common/inet_gethost.c b/erts/etc/common/inet_gethost.c
index d3ff4874ac..e095836258 100644
--- a/erts/etc/common/inet_gethost.c
+++ b/erts/etc/common/inet_gethost.c
@@ -59,6 +59,7 @@
#define WIN32_LEAN_AND_MEAN
#include <winsock2.h>
#include <windows.h>
+#include <ws2tcpip.h>
#include <process.h>
#include <stdio.h>
#include <stdlib.h>
diff --git a/erts/etc/win32/cygwin_tools/vc/ld.sh b/erts/etc/win32/cygwin_tools/vc/ld.sh
index b04935ed9b..d3b53eb5bc 100755
--- a/erts/etc/win32/cygwin_tools/vc/ld.sh
+++ b/erts/etc/win32/cygwin_tools/vc/ld.sh
@@ -53,7 +53,7 @@ while test -n "$1" ; do
STDLIB_FORCED=true;
STDLIB=LIBCMTD.LIB;;
-lsocket)
- DEFAULT_LIBRARIES="$DEFAULT_LIBRARIES WS2_32.LIB";;
+ DEFAULT_LIBRARIES="$DEFAULT_LIBRARIES WS2_32.LIB IPHLPAPI.LIB";;
-l*)
y=`echo $x | sed 's,^-l\(.*\),\1,g'`;
MPATH=`cygpath -m $y`;
diff --git a/erts/preloaded/ebin/prim_inet.beam b/erts/preloaded/ebin/prim_inet.beam
index 8f0b1e3faa..3f53f35273 100644
--- a/erts/preloaded/ebin/prim_inet.beam
+++ b/erts/preloaded/ebin/prim_inet.beam
Binary files differ
diff --git a/erts/preloaded/src/prim_inet.erl b/erts/preloaded/src/prim_inet.erl
index 00ce26dfb3..446656e45f 100644
--- a/erts/preloaded/src/prim_inet.erl
+++ b/erts/preloaded/src/prim_inet.erl
@@ -658,7 +658,7 @@ getifaddrs(S) when is_port(S) ->
{error,enotsup} ->
case getiflist(S) of
{ok, IFs} ->
- getifaddrs_ifget(S, IFs);
+ {ok, getifaddrs_ifget(S, IFs)};
Err1 -> Err1
end;
Err2 -> Err2
@@ -674,14 +674,18 @@ comp_ifaddrs([{If,Opts}|IfOpts], T) ->
false ->
OptSet = comp_ifaddrs_add(ktree_empty(), Opts),
comp_ifaddrs(IfOpts, ktree_insert(If, OptSet, T))
- end;
+ end;
comp_ifaddrs([], T) ->
[{If,ktree_keys(ktree_get(If, T))} || If <- ktree_keys(T)].
comp_ifaddrs_add(OptSet, [Opt|Opts]) ->
case ktree_is_defined(Opt, OptSet) of
- true -> comp_ifaddrs_add(OptSet, Opts);
- false -> comp_ifaddrs_add(ktree_insert(Opt, undefined, OptSet), Opts)
+ true
+ when element(1, Opt) =:= flags;
+ element(1, Opt) =:= hwaddr ->
+ comp_ifaddrs_add(OptSet, Opts);
+ _ ->
+ comp_ifaddrs_add(ktree_insert(Opt, undefined, OptSet), Opts)
end;
comp_ifaddrs_add(OptSet, []) -> OptSet.
@@ -2018,9 +2022,9 @@ build_ifaddrs(Cs) ->
build_ifaddrs([], []) ->
[];
build_ifaddrs([0|Cs], Acc) ->
- Name = rev(Acc),
+ Name = utf8_to_characters(rev(Acc)),
{Opts,Rest} = build_ifaddrs_opts(Cs, []),
- [{Name,rev(Opts)}|build_ifaddrs(Rest)];
+ [{Name,Opts}|build_ifaddrs(Rest)];
build_ifaddrs([C|Cs], Acc) ->
build_ifaddrs(Cs, [C|Acc]).
@@ -2029,7 +2033,7 @@ build_ifaddrs_opts([0|Cs], Acc) ->
build_ifaddrs_opts([C|Cs]=CCs, Acc) ->
case dec_ifopt(C) of
undefined ->
- erlang:error([CCs,Acc]);
+ erlang:error(badarg, [CCs,Acc]);
Opt ->
Type = type_ifopt(Opt),
{Val,Rest} = dec_value(Type, Cs),
@@ -2112,6 +2116,27 @@ tree({K0,V0,L,R}, K, Op, H) ->
+utf8_to_characters([]) -> [];
+utf8_to_characters([B|Bs]=Arg) when (B band 16#FF) =:= B ->
+ if 16#F8 =< B ->
+ erlang:error(badarg, [Arg]);
+ 16#F0 =< B ->
+ utf8_to_characters(Bs, B band 16#07, 3);
+ 16#E0 =< B ->
+ utf8_to_characters(Bs, B band 16#0F, 2);
+ 16#C0 =< B ->
+ utf8_to_characters(Bs, B band 16#1F, 1);
+ 16#80 =< B ->
+ erlang:error(badarg, [Arg]);
+ true ->
+ [B|utf8_to_characters(Bs)]
+ end.
+%%
+utf8_to_characters(Bs, U, 0) ->
+ [U|utf8_to_characters(Bs)];
+utf8_to_characters([B|Bs], U, N) when ((B band 16#3F) bor 16#80) =:= B ->
+ utf8_to_characters(Bs, (U bsl 6) bor (B band 16#3F), N-1).
+
ip_to_bytes(IP) when tuple_size(IP) =:= 4 -> ip4_to_bytes(IP);
ip_to_bytes(IP) when tuple_size(IP) =:= 8 -> ip6_to_bytes(IP).