From 989fa5de1889c3fd09e9b5e25c244e2a855bf0b5 Mon Sep 17 00:00:00 2001 From: Kenji Rikitake Date: Wed, 10 Feb 2010 22:44:30 +0859 Subject: Fix building error of SCTP in FreeBSD 7.1 and later This patch fixes building error of SCTP in FreeBSD 7.1 and later. See http://www.erlang.org/cgi-bin/ezmlm-cgi?2:mss:1257:200904:hppnfialjjdlgecdiehe for the details. R13A patch for solving a compilation error when building erts/emulator/drivers/common/inet_drv.c by Kenji Rikitake 12-APR-2009 Symptom solved by this patch: When building R13A in FreeBSD 7.1-RELEASE, the compiler flag HAVE_STRUCT_SCTP_PADDRPARAMS_SPP_SACKDELAY is NOT enabled. Some code in erts/emulator/drivers/common/inet_drv.c incorrectly assumes HAVE_STRUCT_SCTP_PADDRPARAMS_SPP_SACKDELAY is always true when HAVE_STRUCT_SCTP_PADDRPARAMS_SPP_FLAGS is true in config.h. This assumption causes a compilation error. --- erts/emulator/drivers/common/inet_drv.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index 3de48194fb..493ebec6b9 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -5293,12 +5293,15 @@ static int sctp_set_opts(inet_descriptor* desc, char* ptr, int len) if (pmtud_enable) cflags |= SPP_PMTUD_ENABLE; if (pmtud_disable) cflags |= SPP_PMTUD_DISABLE; +# ifdef HAVE_STRUCT_SCTP_PADDRPARAMS_SPP_SACKDELAY + /* The followings are missing in FreeBSD 7.1 */ sackdelay_enable =eflags& SCTP_FLAG_SACDELAY_ENABLE; sackdelay_disable=eflags& SCTP_FLAG_SACDELAY_DISABLE; if (sackdelay_enable && sackdelay_disable) return -1; if (sackdelay_enable) cflags |= SPP_SACKDELAY_ENABLE; if (sackdelay_disable) cflags |= SPP_SACKDELAY_DISABLE; +# endif arg.pap.spp_flags = cflags; # endif @@ -6199,12 +6202,14 @@ static int sctp_fill_opts(inet_descriptor* desc, char* buf, int buflen, if (ap.spp_flags & SPP_PMTUD_DISABLE) { i = LOAD_ATOM (spec, i, am_pmtud_disable); n++; } - +# ifdef HAVE_STRUCT_SCTP_PADDRPARAMS_SPP_SACKDELAY + /* SPP_SACKDELAY_* not in FreeBSD 7.1 */ if (ap.spp_flags & SPP_SACKDELAY_ENABLE) { i = LOAD_ATOM (spec, i, am_sackdelay_enable); n++; } if (ap.spp_flags & SPP_SACKDELAY_DISABLE) { i = LOAD_ATOM (spec, i, am_sackdelay_disable); n++; } +# endif # endif PLACE_FOR(spec, i, -- cgit v1.2.3 From ff7a4dbd6881e2434ed2619df541c113281cf0a0 Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Mon, 4 Oct 2010 15:12:10 +0200 Subject: Implement basic inet:getifaddrs/0 --- erts/configure.in | 2 +- erts/emulator/drivers/common/inet_drv.c | 387 ++++++++++++++++++++++---------- erts/preloaded/ebin/prim_inet.beam | Bin 57268 -> 64188 bytes erts/preloaded/src/prim_inet.erl | 225 +++++++++++++++++-- lib/kernel/src/inet.erl | 12 + lib/kernel/src/inet_int.hrl | 3 +- 6 files changed, 493 insertions(+), 136 deletions(-) diff --git a/erts/configure.in b/erts/configure.in index 8c6f2ac076..c279161a29 100644 --- a/erts/configure.in +++ b/erts/configure.in @@ -1788,7 +1788,7 @@ AC_CHECK_FUNCS([fdatasync]) dnl Find which C libraries are required to use fdatasync AC_SEARCH_LIBS(fdatasync, [rt]) -AC_CHECK_HEADERS(net/if_dl.h ifaddrs.h) +AC_CHECK_HEADERS(net/if_dl.h ifaddrs.h netpacket/packet.h) AC_CHECK_FUNCS([getifaddrs]) dnl ---------------------------------------------------------------------- diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index 493ebec6b9..4ee0e968d7 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -54,6 +54,9 @@ #ifdef HAVE_IFADDRS_H #include #endif +#ifdef HAVE_NETPACKET_PACKET_H +#include +#endif /* All platforms fail on malloc errors. */ #define FATAL_MALLOC @@ -467,6 +470,7 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n) #define INET_REQ_IFGET 22 #define INET_REQ_IFSET 23 #define INET_REQ_SUBSCRIBE 24 +#define INET_REQ_GETIFADDRS 25 /* TCP requests */ #define TCP_REQ_ACCEPT 40 #define TCP_REQ_LISTEN 41 @@ -3824,21 +3828,40 @@ do { if ((end)-(ptr) < (n)) goto error; } while(0) static char* sockaddr_to_buf(struct sockaddr* addr, char* ptr, char* end) { if (addr->sa_family == AF_INET || addr->sa_family == 0) { - struct in_addr a; - buf_check(ptr,end,sizeof(struct in_addr)); - a = ((struct sockaddr_in*) addr)->sin_addr; - sys_memcpy(ptr, (char*)&a, sizeof(struct in_addr)); - return ptr + sizeof(struct in_addr); + struct in_addr *p = &(((struct sockaddr_in*) addr)->sin_addr); + buf_check(ptr, end, 1 + sizeof(struct in_addr)); + *ptr = INET_AF_INET; + sys_memcpy(ptr+1, (char*)p, sizeof(struct in_addr)); + return ptr + 1 + sizeof(struct in_addr); } #if defined(HAVE_IN6) && defined(AF_INET6) else if (addr->sa_family == AF_INET6) { - struct in6_addr a; - buf_check(ptr,end,sizeof(struct in6_addr)); - a = ((struct sockaddr_in6*) addr)->sin6_addr; - sys_memcpy(ptr, (char*)&a, sizeof(struct in6_addr)); - return ptr + sizeof(struct in6_addr); + struct in6_addr *p = &(((struct sockaddr_in6*) addr)->sin6_addr); + buf_check(ptr, end, 1 + sizeof(struct in6_addr)); + *ptr = INET_AF_INET6; + sys_memcpy(ptr+1, (char*)p, sizeof(struct in6_addr)); + return ptr + 1 + sizeof(struct in6_addr); + } +#endif +#if defined(AF_LINK) + else if (addr->sa_family == AF_LINK) { + struct sockaddr_dl *sdl_p = (struct sockaddr_dl*) addr; + buf_check(ptr, end, 2 + sdl_p->sdl_alen); + put_int16(sdl_p->sdl_alen, ptr); ptr += 2; + sys_memcpy(ptr, sdl_p->sdl_data + sdl_p->sdl_nlen, sdl_p->sdl_alen); + return ptr + sdl_p->sdl_alen; } #endif +#if defined(AF_PACKET) && defined(HAVE_NETPACKET_PACKET_H) + else if(addr->sa_family == AF_PACKET) { + struct sockaddr_ll *sll_p = (struct sockaddr_ll*) addr; + buf_check(ptr, end, 2 + sll_p->sll_halen); + put_int16(sll_p->sll_halen, ptr); ptr += 2; + sys_memcpy(ptr, sll_p->sll_addr, sll_p->sll_halen); + return ptr + sll_p->sll_halen; + } +#endif + return ptr; error: return NULL; @@ -3846,12 +3869,23 @@ static char* sockaddr_to_buf(struct sockaddr* addr, char* ptr, char* end) static char* buf_to_sockaddr(char* ptr, char* end, struct sockaddr* addr) { - buf_check(ptr,end,sizeof(struct in_addr)); - sys_memcpy((char*) &((struct sockaddr_in*)addr)->sin_addr, ptr, - sizeof(struct in_addr)); - addr->sa_family = AF_INET; - return ptr + sizeof(struct in_addr); - + buf_check(ptr,end,1); + switch (*ptr++) { + case INET_AF_INET: { + struct in_addr *p = &((struct sockaddr_in*)addr)->sin_addr; + buf_check(ptr,end,sizeof(struct in_addr)); + sys_memcpy((char*) p, ptr, sizeof(struct in_addr)); + addr->sa_family = AF_INET; + return ptr + sizeof(struct in_addr); + } + case INET_AF_INET6: { + struct in6_addr *p = &((struct sockaddr_in6*)addr)->sin6_addr; + buf_check(ptr,end,sizeof(struct in6_addr)); + sys_memcpy((char*) p, ptr, sizeof(struct in6_addr)); + addr->sa_family = AF_INET6; + return ptr + sizeof(struct in6_addr); + } + } error: return NULL; } @@ -3894,7 +3928,6 @@ static int inet_ctl_getiflist(inet_descriptor* desc, char** rbuf, int rsize) return ctl_reply(INET_REP_OK, sbuf, sptr - sbuf, rbuf, rsize); } - /* input is an ip-address in string format i.e A.B.C.D ** scan the INTERFACE_LIST to get the options */ @@ -3980,27 +4013,12 @@ static int inet_ctl_ifget(inet_descriptor* desc, char* buf, int len, break; case INET_IFOPT_FLAGS: { - long eflags = 0; int flags = ifp->iiFlags; /* just enumerate the interfaces (no names) */ - /* translate flags */ - if (flags & IFF_UP) - eflags |= INET_IFF_UP; - if (flags & IFF_BROADCAST) - eflags |= INET_IFF_BROADCAST; - if (flags & IFF_LOOPBACK) - eflags |= INET_IFF_LOOPBACK; - if (flags & IFF_POINTTOPOINT) - eflags |= INET_IFF_POINTTOPOINT; - if (flags & IFF_UP) /* emulate runnign ? */ - eflags |= INET_IFF_RUNNING; - if (flags & IFF_MULTICAST) - eflags |= INET_IFF_MULTICAST; - buf_check(sptr, s_end, 5); *sptr++ = INET_IFOPT_FLAGS; - put_int32(eflags, sptr); + put_int32(IFGET_FLAGS(flags), sptr); sptr += 4; break; } @@ -4021,7 +4039,6 @@ static int inet_ctl_ifset(inet_descriptor* desc, char* buf, int len, return ctl_reply(INET_REP_OK, NULL, 0, rbuf, rsize); } - #elif defined(SIOCGIFCONF) && defined(SIOCSIFFLAGS) /* cygwin has SIOCGIFCONF but not SIOCSIFFLAGS (Nov 2002) */ @@ -4032,74 +4049,90 @@ static int inet_ctl_ifset(inet_descriptor* desc, char* buf, int len, #define SIZEA(p) (sizeof (p)) #endif - -static int inet_ctl_getiflist(inet_descriptor* desc, char** rbuf, int rsize) -{ - struct ifconf ifc; - struct ifreq *ifr; - char *buf; - int buflen, ifc_len, i; - char *sbuf, *sp; - - /* Courtesy of Per Bergqvist and W. Richard Stevens */ - - ifc_len = 0; - buflen = 100 * sizeof(struct ifreq); - buf = ALLOC(buflen); +static int get_ifconf(SOCKET s, struct ifconf *ifcp) { + int ifc_len = 0; + int buflen = 100 * sizeof(struct ifreq); + char *buf = ALLOC(buflen); for (;;) { - ifc.ifc_len = buflen; - ifc.ifc_buf = buf; - if (ioctl(desc->s, SIOCGIFCONF, (char *)&ifc) < 0) { + ifcp->ifc_len = buflen; + ifcp->ifc_buf = buf; + if (ioctl(s, SIOCGIFCONF, (char *)ifcp) < 0) { int res = sock_errno(); if (res != EINVAL || ifc_len) { FREE(buf); - return ctl_error(res, rbuf, rsize); + return -1; } } else { - if (ifc.ifc_len == ifc_len) break; /* buf large enough */ - ifc_len = ifc.ifc_len; + if (ifcp->ifc_len == ifc_len) break; /* buf large enough */ + ifc_len = ifcp->ifc_len; } buflen += 10 * sizeof(struct ifreq); buf = (char *)REALLOC(buf, buflen); } - - sp = sbuf = ALLOC(ifc_len+1); + return 0; +} + +static void free_ifconf(struct ifconf *ifcp) { + FREE(ifcp->ifc_buf); +} + +static int inet_ctl_getiflist(inet_descriptor* desc, char** rbuf, int rsize) +{ + struct ifconf ifc; + struct ifreq *ifrp; + char *sbuf, *sp; + int i; + + /* Courtesy of Per Bergqvist and W. Richard Stevens */ + + if (get_ifconf(desc->s, &ifc) < 0) { + return ctl_error(sock_errno(), rbuf, rsize); + } + + sp = sbuf = ALLOC(ifc.ifc_len+1); *sp++ = INET_REP_OK; i = 0; for (;;) { int n; - - ifr = (struct ifreq *) VOIDP(buf + i); - n = sizeof(ifr->ifr_name) + SIZEA(ifr->ifr_addr); - if (n < sizeof(*ifr)) n = sizeof(*ifr); - if (i+n > ifc_len) break; + + ifrp = (struct ifreq *) VOIDP(ifc.ifc_buf + i); + n = sizeof(ifrp->ifr_name) + SIZEA(ifrp->ifr_addr); + if (n < sizeof(*ifrp)) n = sizeof(*ifrp); + if (i+n > ifc.ifc_len) break; i += n; - - switch (ifr->ifr_addr.sa_family) { + + switch (ifrp->ifr_addr.sa_family) { #if defined(HAVE_IN6) && defined(AF_INET6) case AF_INET6: #endif case AF_INET: - ASSERT(sp+IFNAMSIZ+1 < sbuf+buflen+1) - strncpy(sp, ifr->ifr_name, IFNAMSIZ); + ASSERT(sp+IFNAMSIZ+1 < sbuf+ifc.ifc_len+1) + strncpy(sp, ifrp->ifr_name, IFNAMSIZ); sp[IFNAMSIZ] = '\0'; sp += strlen(sp), ++sp; } - - if (i >= ifc_len) break; + + if (i >= ifc.ifc_len) break; } - FREE(buf); + free_ifconf(&ifc); *rbuf = sbuf; return sp - sbuf; } - /* FIXME: temporary hack */ #ifndef IFHWADDRLEN #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) { @@ -4133,37 +4166,52 @@ static int inet_ctl_ifget(inet_descriptor* desc, char* buf, int len, #ifdef SIOCGIFHWADDR if (ioctl(desc->s, SIOCGIFHWADDR, (char *)&ifreq) < 0) break; - buf_check(sptr, s_end, 1+IFHWADDRLEN); + buf_check(sptr, s_end, 1+2+IFHWADDRLEN); *sptr++ = INET_IFOPT_HWADDR; + put_int16(IFHWADDRLEN, sptr); sptr += 2; /* raw memcpy (fix include autoconf later) */ sys_memcpy(sptr, (char*)(&ifreq.ifr_hwaddr.sa_data), IFHWADDRLEN); sptr += IFHWADDRLEN; -#elif defined(HAVE_GETIFADDRS) - struct ifaddrs *ifa, *ifp; - int found = 0; - - if (getifaddrs(&ifa) == -1) - goto error; - - for (ifp = ifa; ifp; ifp = ifp->ifa_next) { - if ((ifp->ifa_addr->sa_family == AF_LINK) && - (sys_strcmp(ifp->ifa_name, ifreq.ifr_name) == 0)) { - found = 1; - break; - } - } +#elif defined(SIOCGENADDR) + if (ioctl(desc->s, SIOCGENADDR, (char *)&ifreq) < 0) + break; + buf_check(sptr, s_end, 1+2+sizeof(ifreq.ifr_enaddr)); + *sptr++ = INET_IFOPT_HWADDR; + put_int16(sizeof(ifreq.ifr_enaddr), sptr); sptr += 2; + /* raw memcpy (fix include autoconf later) */ + sys_memcpy(sptr, (char*)(&ifreq.ifr_enaddr), + sizeof(ifreq.ifr_enaddr)); + sptr += sizeof(ifreq.ifr_enaddr); +#elif defined(HAVE_GETIFADDRS) && defined(AF_LINK) + struct ifaddrs *ifa, *ifp; + struct sockaddr_dl *sdlp; + int found = 0; + + if (getifaddrs(&ifa) == -1) + goto error; - if (found == 0) { - freeifaddrs(ifa); - break; - } + for (ifp = ifa; ifp; ifp = ifp->ifa_next) { + if ((ifp->ifa_addr->sa_family == AF_LINK) && + (sys_strcmp(ifp->ifa_name, ifreq.ifr_name) == 0)) { + found = 1; + break; + } + } + + if (found == 0) { + freeifaddrs(ifa); + break; + } + sdlp = (struct sockaddr_dl *)ifp->ifa_addr; - buf_check(sptr, s_end, 1+IFHWADDRLEN); - *sptr++ = INET_IFOPT_HWADDR; - sys_memcpy(sptr, ((struct sockaddr_dl *)ifp->ifa_addr)->sdl_data + - ((struct sockaddr_dl *)ifp->ifa_addr)->sdl_nlen, IFHWADDRLEN); - freeifaddrs(ifa); - sptr += IFHWADDRLEN; + buf_check(sptr, s_end, 1+2+sdlp->sdl_alen); + *sptr++ = INET_IFOPT_HWADDR; + put_int16(sdlp->sdl_alen, sptr); sptr += 2; + sys_memcpy(sptr, + sdlp->sdl_data + sdlp->sdl_nlen, + sdlp->sdl_alen); + freeifaddrs(ifa); + sptr += sdlp->sdl_alen; #endif break; } @@ -4240,29 +4288,15 @@ static int inet_ctl_ifget(inet_descriptor* desc, char* buf, int len, case INET_IFOPT_FLAGS: { int flags; - int eflags = 0; if (ioctl(desc->s, SIOCGIFFLAGS, (char*)&ifreq) < 0) flags = 0; else flags = ifreq.ifr_flags; - /* translate flags */ - if (flags & IFF_UP) - eflags |= INET_IFF_UP; - if (flags & IFF_BROADCAST) - eflags |= INET_IFF_BROADCAST; - if (flags & IFF_LOOPBACK) - eflags |= INET_IFF_LOOPBACK; - if (flags & IFF_POINTOPOINT) - eflags |= INET_IFF_POINTTOPOINT; - if (flags & IFF_RUNNING) - eflags |= INET_IFF_RUNNING; - if (flags & IFF_MULTICAST) - eflags |= INET_IFF_MULTICAST; buf_check(sptr, s_end, 5); *sptr++ = INET_IFOPT_FLAGS; - put_int32(eflags, sptr); + put_int32(IFGET_FLAGS(flags), sptr); sptr += 4; break; } @@ -4300,17 +4334,22 @@ static int inet_ctl_ifset(inet_descriptor* desc, char* buf, int len, (void) ioctl(desc->s, SIOCSIFADDR, (char*)&ifreq); break; - case INET_IFOPT_HWADDR: - buf_check(buf, b_end, IFHWADDRLEN); + case INET_IFOPT_HWADDR: { + unsigned int len; + buf_check(buf, b_end, 2); + len = get_int16(buf); buf += 2; + buf_check(buf, b_end, len); #ifdef SIOCSIFHWADDR /* raw memcpy (fix include autoconf later) */ - sys_memcpy((char*)(&ifreq.ifr_hwaddr.sa_data), buf, IFHWADDRLEN); + sys_memset((char*)(&ifreq.ifr_hwaddr.sa_data), + '\0', sizeof(ifreq.ifr_hwaddr.sa_data)); + sys_memcpy((char*)(&ifreq.ifr_hwaddr.sa_data), buf, len); (void) ioctl(desc->s, SIOCSIFHWADDR, (char *)&ifreq); #endif - buf += IFHWADDRLEN; + buf += len; break; - + } case INET_IFOPT_BROADADDR: #ifdef SIOCSIFBRDADDR @@ -4415,6 +4454,119 @@ static int inet_ctl_ifset(inet_descriptor* desc, char* buf, int len, #endif + + +#if defined(HAVE_GETIFADDRS) + +static int inet_ctl_getifaddrs(inet_descriptor* desc_p, + char **rbuf_pp, int rsize) +{ + struct ifaddrs *ifa_p, *ifa_free_p; + + int buf_size; + char *buf_p; + char *buf_alloc_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 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_alloc_p = REALLOC(buf_alloc_p, buf_size+512); \ + buf_p = buf_alloc_p + got; \ + } \ + if (p == buf_p) { \ + buf_p--; \ + } else { \ + buf_p = p; \ + } \ + } \ + } while (0) + + if (getifaddrs(&ifa_p) < 0) { + return ctl_error(sock_errno(), rbuf_pp, rsize); + } + 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); + buf_p += len; + *buf_p++ = INET_IFOPT_FLAGS; + 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 +#endif + ) { + SOCKADDR_TO_BUF(INET_IFOPT_ADDR, ifa_p->ifa_addr); + BUF_ENSURE(1); + SOCKADDR_TO_BUF(INET_IFOPT_NETMASK, ifa_p->ifa_netmask); + if (ifa_p->ifa_flags & IFF_POINTOPOINT) { + BUF_ENSURE(1); + SOCKADDR_TO_BUF(INET_IFOPT_DSTADDR, ifa_p->ifa_dstaddr); + } else if (ifa_p->ifa_flags & IFF_BROADCAST) { + BUF_ENSURE(1); + SOCKADDR_TO_BUF(INET_IFOPT_BROADADDR, ifa_p->ifa_broadaddr); + } + } +#if defined(AF_LINK) || defined(AF_PACKET) + else if ( +#if defined(AF_LINK) + ifa_p->ifa_addr->sa_family == AF_LINK +#else + 0 +#endif +#if defined(AF_PACKET) + || ifa_p->ifa_addr->sa_family == AF_PACKET +#endif + ) { + BUF_ENSURE(1); + SOCKADDR_TO_BUF(INET_IFOPT_HWADDR, ifa_p->ifa_addr); + } +#endif + BUF_ENSURE(1); + *buf_p++ = '\0'; + } + buf_size = buf_p - buf_alloc_p; + buf_alloc_p = REALLOC(buf_alloc_p, buf_size); + /* buf_p is now unreliable */ + freeifaddrs(ifa_free_p); + *rbuf_pp = buf_alloc_p; + return buf_size; +# undef BUF_ENSURE +} + +#else + +static int inet_ctl_getifaddrs(inet_descriptor* desc_p, + char **rbuf_pp, int rsize) +{ + return ctl_error(ENOTSUP, rbuf_pp, rsize); +} + +#endif + + + #ifdef VXWORKS /* ** THIS is a terrible creature, a bug in the TCP part @@ -6681,6 +6833,13 @@ static int inet_ctl(inet_descriptor* desc, int cmd, char* buf, int len, return inet_ctl_getiflist(desc, rbuf, rsize); } + case INET_REQ_GETIFADDRS: { + DEBUGF(("inet_ctl(%ld): GETIFADDRS\r\n", (long)desc->port)); + if (!IS_OPEN(desc)) + return ctl_xerror(EXBADPORT, rbuf, rsize); + return inet_ctl_getifaddrs(desc, rbuf, rsize); + } + case INET_REQ_IFGET: { DEBUGF(("inet_ctl(%ld): IFGET\r\n", (long)desc->port)); if (!IS_OPEN(desc)) diff --git a/erts/preloaded/ebin/prim_inet.beam b/erts/preloaded/ebin/prim_inet.beam index a777971b32..8f0b1e3faa 100644 Binary files a/erts/preloaded/ebin/prim_inet.beam and b/erts/preloaded/ebin/prim_inet.beam differ diff --git a/erts/preloaded/src/prim_inet.erl b/erts/preloaded/src/prim_inet.erl index 91d39c6a73..00ce26dfb3 100644 --- a/erts/preloaded/src/prim_inet.erl +++ b/erts/preloaded/src/prim_inet.erl @@ -37,7 +37,7 @@ -export([setopt/3, setopts/2, getopt/2, getopts/2, is_sockopt_val/2]). -export([chgopt/3, chgopts/2]). -export([getstat/2, getfd/1, getindex/1, getstatus/1, gettype/1, - getiflist/1, ifget/3, ifset/3, + getifaddrs/1, getiflist/1, ifget/3, ifset/3, gethostname/1]). -export([getservbyname/3, getservbyport/3]). -export([peername/1, setpeername/2]). @@ -216,9 +216,10 @@ bindx(S, AddFlag, Addrs) -> sctp -> %% Really multi-homed "bindx". Stringified args: %% [AddFlag, (Port, IP)+]: - Args = ?int8(AddFlag) ++ - lists:concat([?int16(Port)++ip_to_bytes(IP) || - {IP, Port} <- Addrs]), + Args = + [?int8(AddFlag)| + [[?int16(Port)|ip_to_bytes(IP)] || + {IP, Port} <- Addrs]], case ctl_cmd(S, ?SCTP_REQ_BINDX, Args) of {ok,_} -> {ok, S}; Error -> Error @@ -623,7 +624,7 @@ chgopt(S, Opt, Value) when is_port(S) -> chgopts(S, [{Opt,Value}]). chgopts(S, Opts) when is_port(S), is_list(Opts) -> - case inet:getopts(S, need_template(Opts)) of + case getopts(S, need_template(Opts)) of {ok,Templates} -> try merge_options(Opts, Templates) of NewOpts -> @@ -636,7 +637,90 @@ chgopts(S, Opts) when is_port(S), is_list(Opts) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% -%% IFLIST(insock()) -> {ok,IfNameList} | {error, Reason} +%% getifaddrs(insock()) -> {ok,IfAddrsList} | {error, Reason} +%% +%% IfAddrsList = [{Name,[Opts]}] +%% Name = string() +%% Opts = {flags,[Flag]} | {addr,Addr} | {netmask,Addr} | {broadaddr,Addr} +%% | {dstaddr,Addr} | {hwaddr,HwAddr} | {mtu,integer()} +%% Flag = up | broadcast | loopback | running | multicast +%% Addr = ipv4addr() | ipv6addr() +%% HwAddr = ethernet_addr() +%% +%% get interface name and addresses list +%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +getifaddrs(S) when is_port(S) -> + case ctl_cmd(S, ?INET_REQ_GETIFADDRS, []) of + {ok, Data} -> + {ok, comp_ifaddrs(build_ifaddrs(Data), ktree_empty())}; + {error,enotsup} -> + case getiflist(S) of + {ok, IFs} -> + getifaddrs_ifget(S, IFs); + Err1 -> Err1 + end; + Err2 -> Err2 + end. + +%% Restructure interface properties per interface and remove duplicates + +comp_ifaddrs([{If,Opts}|IfOpts], T) -> + case ktree_is_defined(If, T) of + true -> + OptSet = comp_ifaddrs_add(ktree_get(If, T), Opts), + comp_ifaddrs(IfOpts, ktree_update(If, OptSet, T)); + false -> + OptSet = comp_ifaddrs_add(ktree_empty(), Opts), + comp_ifaddrs(IfOpts, ktree_insert(If, OptSet, T)) + 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) + end; +comp_ifaddrs_add(OptSet, []) -> OptSet. + +%% Legacy emulation of getifaddrs + +getifaddrs_ifget(_, []) -> []; +getifaddrs_ifget(S, [IF|IFs]) -> + case ifget(S, IF, [flags]) of + {ok,[{flags,Flags}]=FlagsVals} -> + BroadOpts = + case member(broadcast, Flags) of + true -> + [broadaddr,hwaddr]; + false -> + [hwaddr] + end, + P2POpts = + case member(pointtopoint, Flags) of + true -> + [dstaddr|BroadOpts]; + false -> + BroadOpts + end, + getifaddrs_ifget(S, IFs, IF, FlagsVals, [addr,netmask|P2POpts]); + _ -> + getifaddrs_ifget(S, IFs, IF, [], [addr,netmask,hwaddr]) + end. + +getifaddrs_ifget(S, IFs, IF, FlagsVals, Opts) -> + OptVals = + case ifget(S, IF, Opts) of + {ok,OVs} -> OVs; + _ -> [] + end, + [{IF,FlagsVals++OptVals}|getifaddrs_ifget(S, IFs)]. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% +%% getiflist(insock()) -> {ok,IfNameList} | {error, Reason} %% %% get interface name list %% @@ -1325,6 +1409,19 @@ type_value_2({enum,List}, Enum) -> {value,_} -> true; false -> false end; +type_value_2(sockaddr, Addr) -> + case Addr of + any -> true; + loopback -> true; + {A,B,C,D} when ?ip(A,B,C,D) -> true; + {A,B,C,D,E,F,G,H} when ?ip6(A,B,C,D,E,F,G,H) -> true; + _ -> false + end; +type_value_2(linkaddr, Addr) when is_list(Addr) -> + case len(Addr, 32768) of + undefined -> false; + _ -> true + end; type_value_2({bitenumlist,List}, EnumList) -> case enum_vals(EnumList, List) of Ls when is_list(Ls) -> true; @@ -1413,14 +1510,21 @@ enc_value_2(addr, {any,Port}) -> [?INET_AF_ANY|?int16(Port)]; enc_value_2(addr, {loopback,Port}) -> [?INET_AF_LOOPBACK|?int16(Port)]; -enc_value_2(addr, {IP,Port}) -> - case tuple_size(IP) of - 4 -> - [?INET_AF_INET,?int16(Port)|ip4_to_bytes(IP)]; - 8 -> - [?INET_AF_INET6,?int16(Port)|ip6_to_bytes(IP)] - end; +enc_value_2(addr, {IP,Port}) when tuple_size(IP) =:= 4 -> + [?INET_AF_INET,?int16(Port)|ip4_to_bytes(IP)]; +enc_value_2(addr, {IP,Port}) when tuple_size(IP) =:= 8 -> + [?INET_AF_INET6,?int16(Port)|ip6_to_bytes(IP)]; enc_value_2(ether, [X1,X2,X3,X4,X5,X6]) -> [X1,X2,X3,X4,X5,X6]; +enc_value_2(sockaddr, any) -> + [?INET_AF_ANY]; +enc_value_2(sockaddr, loopback) -> + [?INET_AF_LOOPBACK]; +enc_value_2(sockaddr, IP) when tuple_size(IP) =:= 4 -> + [?INET_AF_INET|ip4_to_bytes(IP)]; +enc_value_2(sockaddr, IP) when tuple_size(IP) =:= 8 -> + [?INET_AF_INET6|ip6_to_bytes(IP)]; +enc_value_2(linkaddr, Linkaddr) -> + [?int16(length(Linkaddr)),Linkaddr]; enc_value_2(sctp_assoc_id, Val) -> ?int32(Val); %% enc_value_2(sctp_assoc_id, Bin) -> [byte_size(Bin),Bin]; enc_value_2({enum,List}, Enum) -> @@ -1465,6 +1569,10 @@ dec_value(time, [X3,X2,X1,X0|T]) -> end; dec_value(ip, [A,B,C,D|T]) -> {{A,B,C,D}, T}; dec_value(ether,[X1,X2,X3,X4,X5,X6|T]) -> {[X1,X2,X3,X4,X5,X6],T}; +dec_value(sockaddr, [X|T]) -> + get_ip(X, T); +dec_value(linkaddr, [X1,X0|T]) -> + split(?i16(X1,X0), T); dec_value({enum,List}, [X3,X2,X1,X0|T]) -> Val = ?i32(X3,X2,X1,X0), case enum_name(Val, List) of @@ -1480,7 +1588,7 @@ dec_value({bitenumlist,List}, [X3,X2,X1,X0|T]) -> %% {enum_names(Val, List), T}; dec_value(binary,[L0,L1,L2,L3|List]) -> Len = ?i32(L0,L1,L2,L3), - {X,T}=lists:split(Len,List), + {X,T}=split(Len,List), {list_to_binary(X),T}; dec_value(Types, List) when is_tuple(Types) -> {L,T} = dec_value_tuple(Types, List, 1, []), @@ -1495,7 +1603,7 @@ dec_value_tuple(Types, List, N, Acc) {Term,Tail} = dec_value(element(N, Types), List), dec_value_tuple(Types, Tail, N+1, [Term|Acc]); dec_value_tuple(_, List, _, Acc) -> - {lists:reverse(Acc),List}. + {rev(Acc),List}. borlist([V|Vs], Value) -> borlist(Vs, V bor Value); @@ -1702,11 +1810,11 @@ merge_fields(_, _, _) -> []. %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -type_ifopt(addr) -> ip; -type_ifopt(broadaddr) -> ip; -type_ifopt(dstaddr) -> ip; +type_ifopt(addr) -> sockaddr; +type_ifopt(broadaddr) -> sockaddr; +type_ifopt(dstaddr) -> sockaddr; type_ifopt(mtu) -> int; -type_ifopt(netmask) -> ip; +type_ifopt(netmask) -> sockaddr; type_ifopt(flags) -> {bitenumlist, [{up, ?INET_IFF_UP}, @@ -1718,7 +1826,7 @@ type_ifopt(flags) -> {no_pointtopoint, ?INET_IFF_NPOINTTOPOINT}, {running, ?INET_IFF_RUNNING}, {multicast, ?INET_IFF_MULTICAST}]}; -type_ifopt(hwaddr) -> ether; +type_ifopt(hwaddr) -> linkaddr; type_ifopt(Opt) when is_atom(Opt) -> undefined. enc_ifopt(addr) -> ?INET_IFOPT_ADDR; @@ -1903,6 +2011,30 @@ encode_ifname(Name) -> if N > 255 -> {error, einval}; true -> {ok,[N | Name]} end. + +build_ifaddrs(Cs) -> + build_ifaddrs(Cs, []). +%% +build_ifaddrs([], []) -> + []; +build_ifaddrs([0|Cs], Acc) -> + Name = rev(Acc), + {Opts,Rest} = build_ifaddrs_opts(Cs, []), + [{Name,rev(Opts)}|build_ifaddrs(Rest)]; +build_ifaddrs([C|Cs], Acc) -> + build_ifaddrs(Cs, [C|Acc]). + +build_ifaddrs_opts([0|Cs], Acc) -> + {rev(Acc),Cs}; +build_ifaddrs_opts([C|Cs]=CCs, Acc) -> + case dec_ifopt(C) of + undefined -> + erlang:error([CCs,Acc]); + Opt -> + Type = type_ifopt(Opt), + {Val,Rest} = dec_value(Type, Cs), + build_ifaddrs_opts(Rest, [{Opt,Val}|Acc]) + end. build_iflist(Cs) -> build_iflist(Cs, [], []). @@ -1927,6 +2059,59 @@ rev(L) -> rev(L,[]). rev([C|L],Acc) -> rev(L,[C|Acc]); rev([],Acc) -> Acc. +split(N, L) -> split(N, L, []). +split(0, L, R) when is_list(L) -> {rev(R),L}; +split(N, [H|T], R) when is_integer(N), N > 0 -> split(N-1, T, [H|R]). + +len(L, N) -> len(L, N, 0). +len([], N, C) when is_integer(N), N >= 0 -> C; +len(L, 0, _) when is_list(L) -> undefined; +len([_|L], N, C) when is_integer(N), N >= 0 -> len(L, N-1, C+1). + +member(X, [X|_]) -> true; +member(X, [_|Xs]) -> member(X, Xs); +member(_, []) -> false. + + + +%% Lookup tree that keeps key insert order + +ktree_empty() -> {[],tree()}. +ktree_is_defined(Key, {_,T}) -> tree(T, Key, is_defined). +ktree_get(Key, {_,T}) -> tree(T, Key, get). +ktree_insert(Key, V, {Keys,T}) -> {[Key|Keys],tree(T, Key, {insert,V})}. +ktree_update(Key, V, {Keys,T}) -> {Keys,tree(T, Key, {update,V})}. +ktree_keys({Keys,_}) -> rev(Keys). + +%% Simple lookup tree. Hash the key to get statistical balance. +%% Key is matched equal, not compared equal. + +tree() -> nil. +tree(T, Key, Op) -> tree(T, Key, Op, erlang:phash2(Key)). + +tree(nil, _, is_defined, _) -> false; +tree(nil, K, {insert,V}, _) -> {K,V,nil,nil}; +tree({K,_,_,_}, K, is_defined, _) -> true; +tree({K,V,_,_}, K, get, _) -> V; +tree({K,_,L,R}, K, {update,V}, _) -> {K,V,L,R}; +tree({K0,V0,L,R}, K, Op, H) -> + H0 = erlang:phash2(K0), + if H0 < H; H0 =:= H, K0 < K -> + if is_tuple(Op) -> + {K0,V0,tree(L, K, Op, H),R}; + true -> + tree(L, K, Op, H) + end; + true -> + if is_tuple(Op) -> + {K0,V0,L,tree(R, K, Op, H)}; + true -> + tree(R, K, Op, H) + end + end. + + + 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). diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl index 93d75321ba..327e0f93f1 100644 --- a/lib/kernel/src/inet.erl +++ b/lib/kernel/src/inet.erl @@ -25,6 +25,7 @@ %% socket -export([peername/1, sockname/1, port/1, send/2, setopts/2, getopts/2, + getifaddrs/0, getifaddrs/1, getif/1, getif/0, getiflist/0, getiflist/1, ifget/3, ifget/2, ifset/3, ifset/2, getstat/1, getstat/2, @@ -265,6 +266,17 @@ setopts(Socket, Opts) -> getopts(Socket, Opts) -> prim_inet:getopts(Socket, Opts). +-spec getifaddrs(Socket :: socket()) -> + {'ok', [string()]} | {'error', posix()}. + +getifaddrs(Socket) -> + prim_inet:getifaddrs(Socket). + +-spec getifaddrs() -> {'ok', [string()]} | {'error', posix()}. + +getifaddrs() -> + withsocket(fun(S) -> prim_inet:getifaddrs(S) end). + -spec getiflist(Socket :: socket()) -> {'ok', [string()]} | {'error', posix()}. diff --git a/lib/kernel/src/inet_int.hrl b/lib/kernel/src/inet_int.hrl index cf357b7fba..6f1688c6a2 100644 --- a/lib/kernel/src/inet_int.hrl +++ b/lib/kernel/src/inet_int.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% Copyright Ericsson AB 1997-2010. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -82,6 +82,7 @@ -define(INET_REQ_IFGET, 22). -define(INET_REQ_IFSET, 23). -define(INET_REQ_SUBSCRIBE, 24). +-define(INET_REQ_GETIFADDRS, 25). %% TCP requests -define(TCP_REQ_ACCEPT, 40). -define(TCP_REQ_LISTEN, 41). -- cgit v1.2.3 From ce4c78512fccda58e75c4846ced1c3a4e10d7454 Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Thu, 14 Oct 2010 16:56:43 +0200 Subject: Implement inet:getifaddrs/0 on Windows --- erts/aclocal.m4 | 14 +- erts/autoconf/win32.config.cache.static | 1 - erts/emulator/drivers/common/inet_drv.c | 686 ++++++++++++++++++++++++++++++-- erts/etc/common/inet_gethost.c | 1 + erts/etc/win32/cygwin_tools/vc/ld.sh | 2 +- erts/preloaded/ebin/prim_inet.beam | Bin 64188 -> 65184 bytes erts/preloaded/src/prim_inet.erl | 39 +- 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 -#include ], +#ifdef __WIN32__ +#include +#include +#else +#include +#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 -#include ], +#ifdef __WIN32__ +#include +#include +#else +#include +#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 #endif #include +#include #include /* 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 #include +#include #include #include #include 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 Binary files a/erts/preloaded/ebin/prim_inet.beam and b/erts/preloaded/ebin/prim_inet.beam 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). -- cgit v1.2.3 From 8770ba523b79b9b995af660a56f05cc36dc60791 Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Wed, 3 Nov 2010 17:15:02 +0100 Subject: Add testcase --- lib/kernel/test/inet_SUITE.erl | 129 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 126 insertions(+), 3 deletions(-) diff --git a/lib/kernel/test/inet_SUITE.erl b/lib/kernel/test/inet_SUITE.erl index f4f27933a5..ec05bf99b9 100644 --- a/lib/kernel/test/inet_SUITE.erl +++ b/lib/kernel/test/inet_SUITE.erl @@ -27,7 +27,7 @@ ipv4_to_ipv6/1, host_and_addr/1, parse/1, t_gethostnative/1, gethostnative_parallell/1, cname_loop/1, gethostnative_soft_restart/1,gethostnative_debug_level/1,getif/1, - getif_ifr_name_overflow/1,getservbyname_overflow/1]). + getif_ifr_name_overflow/1,getservbyname_overflow/1,getifaddrs/1]). -export([get_hosts/1, get_ipv6_hosts/1, parse_hosts/1, parse_address/1, kill_gethost/0, parallell_gethost/0]). @@ -40,7 +40,7 @@ all(suite) -> ipv4_to_ipv6, host_and_addr, parse,t_gethostnative, gethostnative_parallell, cname_loop, gethostnative_debug_level,gethostnative_soft_restart, - getif,getif_ifr_name_overflow,getservbyname_overflow]. + getif,getif_ifr_name_overflow,getservbyname_overflow,getifaddrs]. init_per_testcase(_Func, Config) -> Dog = test_server:timetrap(test_server:seconds(60)), @@ -873,6 +873,14 @@ getif(suite) -> getif(doc) -> ["Tests basic functionality of getiflist, getif, and ifget"]; getif(Config) when is_list(Config) -> + ?line case os:type() of + {unix,Osname} -> + ?line do_getif(Osname); + {_,_} -> + {skip,"inet:getif/0 probably not supported"} + end. + +do_getif(Osname) -> ?line {ok,Hostname} = inet:gethostname(), ?line {ok,Address} = inet:getaddr(Hostname, inet), ?line {ok,Loopback} = inet:getaddr("localhost", inet), @@ -887,7 +895,8 @@ getif(Config) when is_list(Config) -> end end, [], Interfaces)), ?line io:format("HWAs = ~p~n", [HWAs]), - ?line length(HWAs) > 0 orelse ?t:fail(no_HWAs), + ?line (Osname =/= sunos) + andalso ((length(HWAs) > 0) orelse (?t:fail(no_HWAs))), ?line Addresses = lists:sort( lists:foldl( @@ -906,6 +915,14 @@ getif(Config) when is_list(Config) -> getif_ifr_name_overflow(doc) -> "Test long interface names do not overrun buffer"; getif_ifr_name_overflow(Config) when is_list(Config) -> + ?line case os:type() of + {unix,Osname} -> + ?line do_getif_ifr_name_overflow(Osname); + {_,_} -> + {skip,"inet:ifget/2 probably not supported"} + end. + +do_getif_ifr_name_overflow(_) -> %% emulator should not crash ?line {ok,[]} = inet:ifget(lists:duplicate(128, "x"), [addr]), ok. @@ -917,6 +934,112 @@ getservbyname_overflow(Config) when is_list(Config) -> ?line {error,einval} = inet:getservbyname(list_to_atom(lists:flatten(lists:duplicate(128, "x"))), tcp), ok. +getifaddrs(doc) -> + "Test inet:gifaddrs/0"; +getifaddrs(Config) when is_list (Config) -> + ?line {ok,IfAddrs} = inet:getifaddrs(), + ?line ?t:format("IfAddrs = ~p.~n", [IfAddrs]), + ?line + case + {os:type(), + [If || + {If,Opts} <- IfAddrs, + lists:keymember(hwaddr, 1, Opts)]} of + {{unix,sunos},[]} -> ok; + {OT,[]} -> + ?t:fail({should_have_hwaddr,OT}); + _ -> ok + end, + ?line Addrs = + [element(1, A) || A <- ifaddrs(IfAddrs)], + ?line ?t:format("Addrs = ~p.~n", [Addrs]), + ?line [check_addr(Addr) || Addr <- Addrs], + ok. + +check_addr(Addr) + when tuple_size(Addr) =:= 8, + element(1, Addr) band 16#FFC0 =:= 16#FE80 -> + ?line ?t:format("Addr: ~p link local; SKIPPED!~n", [Addr]), + ok; +check_addr(Addr) -> + ?line ?t:format("Addr: ~p.~n", [Addr]), + ?line Ping = "ping", + ?line Pong = "pong", + ?line {ok,L} = gen_tcp:listen(0, [{ip,Addr},{active,false}]), + ?line {ok,P} = inet:port(L), + ?line {ok,S1} = gen_tcp:connect(Addr, P, [{active,false}]), + ?line {ok,S2} = gen_tcp:accept(L), + ?line ok = gen_tcp:send(S2, Ping), + ?line {ok,Ping} = gen_tcp:recv(S1, length(Ping)), + ?line ok = gen_tcp:send(S1, Pong), + ?line ok = gen_tcp:close(S1), + ?line {ok,Pong} = gen_tcp:recv(S2, length(Pong)), + ?line ok = gen_tcp:close(S2), + ?line ok = gen_tcp:close(L), + ok. + +-record(ifopts, {name,flags,addrs=[],hwaddr}). + +ifaddrs([]) -> []; +ifaddrs([{If,Opts}|IOs]) -> + ?line #ifopts{flags=Flags} = Ifopts = + check_ifopts(Opts, #ifopts{name=If}), + ?line case Flags =/= undefined andalso lists:member(up, Flags) of + true -> + Ifopts#ifopts.addrs; + false -> + [] + end++ifaddrs(IOs). + +check_ifopts([], #ifopts{name=If,flags=Flags,addrs=Raddrs}=Ifopts) -> + Addrs = lists:reverse(Raddrs), + R = Ifopts#ifopts{addrs=Addrs}, + ?t:format("~p.~n", [R]), + %% See how we did... + if is_list(Flags) -> ok; + true -> + ?t:fail({flags_undefined,If}) + end, + case lists:member(broadcast, Flags) of + true -> + [case A of + {_,_,_} -> A; + {T,_} when tuple_size(T) =:= 8 -> A; + _ -> + ?t:fail({broaddr_missing,If,A}) + end || A <- Addrs]; + false -> + [case A of {_,_} -> A; + _ -> + ?t:fail({should_have_netmask,If,A}) + end || A <- Addrs] + end, + R; +check_ifopts([{flags,Flags}|Opts], #ifopts{flags=undefined}=Ifopts) -> + check_ifopts(Opts, Ifopts#ifopts{flags=Flags}); +check_ifopts([{flags,Fs}|Opts], #ifopts{flags=Flags}=Ifopts) -> + case Fs of + Flags -> + check_ifopts(Opts, Ifopts#ifopts{}); + _ -> + ?t:fail({multiple_flags,Fs,Ifopts}) + end; +check_ifopts( + [{addr,Addr},{netmask,Netmask},{broadaddr,Broadaddr}|Opts], + #ifopts{addrs=Addrs}=Ifopts) -> + check_ifopts(Opts, Ifopts#ifopts{addrs=[{Addr,Netmask,Broadaddr}|Addrs]}); +check_ifopts( + [{addr,Addr},{netmask,Netmask}|Opts], + #ifopts{addrs=Addrs}=Ifopts) -> + check_ifopts(Opts, Ifopts#ifopts{addrs=[{Addr,Netmask}|Addrs]}); +check_ifopts([{addr,Addr}|Opts], #ifopts{addrs=Addrs}=Ifopts) -> + check_ifopts(Opts, Ifopts#ifopts{addrs=[{Addr}|Addrs]}); +check_ifopts([{hwaddr,Hwaddr}|Opts], #ifopts{hwaddr=undefined}=Ifopts) + when is_list(Hwaddr) -> + check_ifopts(Opts, Ifopts#ifopts{hwaddr=Hwaddr}); +check_ifopts([{hwaddr,HwAddr}|_], #ifopts{}=Ifopts) -> + ?t:fail({multiple_hwaddrs,HwAddr,Ifopts}). + %% Works just like lists:member/2, except that any {127,_,_,_} tuple %% matches any other {127,_,_,_}. We do this to handle Linux systems %% that use (for instance) 127.0.1.1 as the IP address for the hostname. -- cgit v1.2.3 From 95ab9ac047453bd0105fd9a0a42a6e43cc6152cd Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Tue, 9 Nov 2010 11:21:50 +0100 Subject: Delete decommented code --- erts/emulator/drivers/common/inet_drv.c | 187 +------------------------------- 1 file changed, 2 insertions(+), 185 deletions(-) diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index 70439ba3f4..f07e4793d2 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -4461,6 +4461,8 @@ static int inet_ctl_ifset(inet_descriptor* desc, char* buf, int len, +/* Latin-1 to utf8 */ + static int utf8_len(const char *c, int m) { int l; for (l = 0; m; c++, l++, m--) { @@ -4484,62 +4486,6 @@ static void utf8_encode(const char *c, int m, char *p) { #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'; @@ -4561,23 +4507,6 @@ int eq_masked_bytes(char *a, char *b, int pref_len) { 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) { @@ -4631,7 +4560,6 @@ static int inet_ctl_getifaddrs(inet_descriptor* desc_p, ULONG (WINAPI *fpGetAdaptersAddresses) (ULONG, ULONG, PVOID, PIP_ADAPTER_ADDRESSES, PULONG); HMODULE iphlpapi = GetModuleHandle("iphlpapi"); - /*iphlpapi = NULL*/; fpGetAdaptersAddresses = (void *) (iphlpapi ? GetProcAddress(iphlpapi, "GetAdaptersAddresses") : @@ -4692,83 +4620,6 @@ static int inet_ctl_getifaddrs(inet_descriptor* desc_p, } } 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; @@ -4796,7 +4647,6 @@ index: 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; @@ -4814,7 +4664,6 @@ index: } if (wname_p) { int len; -/* printf("InterfaceName [%d]: %ws\n", i, ifrow.wszName);*/ /* Convert interface name to UTF-8 */ len = WideCharToMultiByte( @@ -4829,7 +4678,6 @@ index: * 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( @@ -4875,25 +4723,16 @@ index: 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); @@ -4908,9 +4747,6 @@ index: 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; @@ -4963,9 +4799,6 @@ index: 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)) { @@ -4986,10 +4819,6 @@ index: shortest_length = 128; } break; } - } else { -/* erts_printf("shortest_p: "); - * print_sockaddr(shortest_p); - * erts_printf("\n");*/ } switch (shortest_p->sa_family) { case AF_INET: { @@ -4998,9 +4827,6 @@ index: 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); @@ -5010,9 +4836,6 @@ index: ((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); @@ -5025,9 +4848,6 @@ index: 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); @@ -5037,9 +4857,6 @@ index: } 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; -- cgit v1.2.3 From d5c04534c1a04701493c28ff24d7040cc513515c Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Tue, 9 Nov 2010 16:11:07 +0100 Subject: Write documentation --- lib/kernel/doc/src/inet.xml | 63 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/lib/kernel/doc/src/inet.xml b/lib/kernel/doc/src/inet.xml index 2ae230152c..a22c0a8346 100644 --- a/lib/kernel/doc/src/inet.xml +++ b/lib/kernel/doc/src/inet.xml @@ -220,6 +220,69 @@ fe80::204:acff:fe17:bf38

Returns the local hostname. Will never fail.

+ + + getifaddrs() -> {ok,Iflist} | {error,posix} + Return a list of interfaces and their addresses + + Iflist = {Ifname,[Ifopt]} + Ifname = string() + Ifopt = {flag,[Flag]} | {addr,Addr} | {netmask,Netmask} + | {broadaddr,Broadaddr} | {dstaddr,Dstaddr} + | {hwaddr,Hwaddr} + Flag = up | broadcast | loopback | pointtopoint + | running | multicast + Addr = Netmask = Broadadddr = Dstaddr = ip_address() + Hwaddr = [byte()] + + + +

+ Returns a list of 2-tuples containing interface names and the + interface's addresses. Ifname is a Unicode string. + Hwaddr is hardware dependent, e.g on Ethernet interfaces + it is the 6-byte Ethernet address (MAC address (EUI-48 address)). +

+

+ The {addr,Addr}, {netmask,_} and {broadaddr,_} + tuples are repeated in the result list iff the interface has multiple + addresses. If you come across an interface that has + multiple {flag,_} or {hwaddr,_} tuples you have + a really strange interface or possibly a bug in this function. + The {flag,_} tuple is mandatory, all other optional. +

+

+ Do not rely too much on the order of Flag atoms or + Ifopt tuples. There are some rules, though: + + + Immediately after {addr,_} follows {netmask,_} + + + Immediately thereafter follows {broadaddr,_} if + the broadcast flag is not set and the + pointtopointflag is set. + + + Any {netmask,_}, {broadaddr,_} or + {dstaddr,_} tuples that follow an {addr,_} + tuple concerns that address. + + +

+

+ The {hwaddr,_} tuple is not returned on Solaris since the + hardware address historically belongs to the link layer and only + the superuser can read such addresses. +

+

+ On Windows, the data is fetched from quite different OS API + functions, so the Netmask and Broadaddr + values may be calculated, just as some Flag values. + You have been warned. Report flagrant bugs. +

+
+ getopts(Socket, Options) -> {ok, OptionValues} | {error, posix()} Get one or more options for a socket -- cgit v1.2.3