e$BDs0F$J$s$G$9$,!"%[%9%H$,;}$C$F$$$ke(B IP e$B%"%I%l%9$N%j%9%H$rJV$9e(B
e$B%a%=%C%I$rMQ0U$9$k$N$O$I$&$G$7$g$&$+!#e(B
% ./ruby -rsocket -rpp -e ‘pp AddrInfo.list_ipaddr’
[#<AddrInfo: 127.0.0.1>,
#<AddrInfo: 150.82.175.199>,
#<AddrInfo: ::1>,
#<AddrInfo: fe80::20b:97ff:fe2b:8539%eth0>]
e$B$3$l$,$J$<I,MW$+$H$$$&$H!"$^$:!“e(BIPv6 e$B$,MxMQ$G$-$J$$%[%9%H$re(B
e$BH=CG$7$?$$$+$i$G$9!#>e5-$N%j%9%H$G$Oe(B ::1 e$B$He(B
fe80::20b:97ff:fe2b:8539%eth0 e$B$H$$$&$U$?$D$Ne(B IPv6 e$B%”%I%l%9$,e(B
e$B$"$j$^$9$,!"$3$l$i$Oe(B loopback address e$B$He(B link local address
e$B$H$$$&$b$N$G!"%0%m!<%P%k$K$O;H$($J$$$b$N$G$9!#$3$NH=CG$r9T$&e(B
e$B$3$H$K$h$j!“e(Bresolv.rb e$B$G;H$($b$7$J$$e(B IPv6
e$B%”%I%l%9$rLd$$9g$oe(B
e$B$;$?$jJV$7$?$j$9$k$3$H$rKI$0$3$H$,$G$-$^$9!#e(B
e$B$^$?!“e(BIP e$B%”%I%l%9$N%j%9%H$Oe(B UDP
e$B$G%5!<%P$r:n$k>l9g$K$b=EMW$Ge(B
e$B$9!#e(BUDP e$B$N%5!<%P$OE~Ce$7$?%Q%1%C%H$N08@h$+$iJV;v$rAw$k$3$H$,e(B
e$BK>$^$l$^$9!#e(B[RFC 1123] e$B$^$!!“Aw$C$?$H$3$m0J30$+$iJV$9$H!”%/e(B
e$B%i%$%"%s%H$O4X78$J$$$H$3$m$+$ie(B (e$B$"$k$$$O4m$J$$$R$H$+$ie(B)
e$BMh$?e(B
e$B%Q%1%C%H$@$H;W$C$FL5;k$9$k$+$b$7$l$J$$$o$1$G$9!#e(B
e$B30$K$D$J$,$C$F$$$ke(B IP e$B%"%I%l%9$,$R$H$D$G$"$l$PLdBj$K$O$J$i$Je(B
e$B$$$s$G$9$,!“J#?t$Ne(B IP e$B%”%I%l%9$r;}$D%^%k%A%[!<%`$J4D6-$GLdBje(B
e$B$K$J$j$^$9!#e(B
e$B$G$O!"%Q%1%C%H$r<u$1<h$k$H$-$K08@h$rF@$l$P!"$H;W$&$o$1$G$9$,!“e(B
e$B;DG0$J$3$H$Ke(B recvfrom e$B$G$O08@h$OF@$i$l$^$;$s!#e(Brecvfrom
e$B$GF@e(B
e$B$i$l$k%”%I%l%9$O%Q%1%C%H$NAw?.85$G$"$C$F08@h$G$O$J$$$+$i$G$9!#e(B
e$B$^$?!"F1MM$Ke(B sendto e$B$G$b%5!<%PB&$G$NAw?.85$r;XDj$9$k$3$H$O$Ge(B
e$B$-$^$;$s!#e(B
e$B$3$l$r2r7h$9$k$R$H$D$NJ}K!$O!"%=%1%C%H$r$"$i$+$8$a3F%"%I%l%9e(B
e$B$4$H$K$D$/$C$Fe(B bind e$B$7$F$*$/$H$$$&$b$N$G$9$,!"$=$3$Ge(B IP
e$B%"%Ie(B
e$B%l%9$N%j%9%H$,I,MW$K$J$j$^$9!#e(B
e$B$=$l0J30$NJ}K!$H$7$F$O!"e(BIPv6 e$B$G$Oe(B IPV6_RECVPKTINFO
e$B$H$+e(B
setsockopt e$B$9$k$He(B recvmsg/sendmsg e$B$G2DG=$J$h$&$G$9!#e(B[RFC
3542]
e$B$,!“e(BIPv4 e$B$G$OI8=`2=$5$l$?$”$k$$$O9-$/;H$($k$b$N$O$J$$$h$&$Ge(B
e$B$9!#e(B(e$B$H$/$KAw?.85$r;XDj$9$kJ}K!$,e(B)
e$B$3$NMW5a$O2a5n$K$b2?2s$,$"$,$C$F$$$^$9!#e(B
[ruby-talk:162689], [ruby-talk:260514], [ruby-talk:324043]
e$B$?$$$F$$!“e(BSocket.gethostname e$B$N7k2L$r5U0z$-$9$k!”$H$$$&OC$Ke(B
e$B$J$k$s$G$9$,!"$3$l$Oe(B /etc/hosts e$B$de(B DNS
e$B$K0MB8$9$k$J$I!“3N<Be(B
e$B$K;H$($k$H$$$&$b$N$G$O$”$j$^$;$s!#$d$O$j%M%C%H%o!<%/%$%s%?!<e(B
e$B%U%’!<%9$N>pJs$,M_$7$1$l$P!"e(B e$B%$%s%?!<%U%’!<%9<+?H$K?R$M$k$Ye(B
e$B$-$@$H;W$$$^$9!#e(B
e$B<B:]$K?R$M$kJ}K!$O!";DG0$J$3$H$Ke(B IP e$B%"%I%l%9$N%j%9%H$rF@$kJ}e(B
e$BK!$OI8=`2=$5$l$F$$$J$$$h$&$J$N$G!“0J2<$r<BAu$7$F$”$j$^$9!#e(B
- getifaddrs:
BSD/OS, FreeBSD, NetBSD, OpenBSD, DragonFly BSD, MirOS BSD,
GNU/Linux, MacOS X, AIX - SIOCGLIFCONF: Solaris
- SIOCGIFCONF: 4.3BSD
e$B$I$&$d$i!"e(Bgetifaddrs e$B$OIa5Z$,?J$s$G$$$k$h$&$G$9!#e(B
4.3BSD e$B$Ne(B SIOCGIFCONF e$B$r;H$&$b$N$r<BAu$7$F$"$k$N$G!"$=$3$KM3e(B
e$BMh$9$k$b$N$O$@$$$?$$F0$/$s$8$c$J$$$+$H;W$$$^$9!#$?$@!"$=$N>le(B
e$B9g$Oe(B IPv4 e$B8BDj$K$J$j$^$9$,!#e(B
(e$B$J$!“e(B4.4BSD e$B$Ne(B SIOCGIFCONF e$B$O3HD%$5$l$Fe(B IPv6
e$B$b07$($F!”$$e(B
e$B$A$$&$=$N>l9g$bF0$/$h$&$K$7$F$"$j$^$9$,!"e(B4.4BSD e$B$Ge(B
getifaddrs e$B$,$J$$4D6-$O;D$C$F$$$J$$$h$&$K;W$($^$9!#e(B)
e$B$J$*!"$3$3$GH4$1$F$$$k$b$N$H$7$Fe(B HP-UX e$B$,$"$j$^$9$,!"$3$l$Ke(B
e$B$Oe(B SIOCGLIFCONF e$B$,$"$k$h$&$G$9!#$?$@$7e(B Solaris
e$B$H$O9=B$BN$,e(B
e$B0c$&$h$&$G!"%F%9%H4D6-$,$J$$$N$G<BAu$7$F$$$^$;$s!#<B5!$,$"$le(B
e$B$P$=$s$J$KFq$7$/$J$$$H;W$$$^$9!#e(B
e$B$H$$$&$o$1$G$I$&$G$7$g$&$+!#e(B
% svn diff --diff-cmd diff -x ‘-u -p’
Index: ext/socket/socket.c
— ext/socket/socket.c (revision 21486)
+++ ext/socket/socket.c (working copy)
@@ -67,6 +67,20 @@
#include <fcntl.h>
#endif
#endif
+
+#ifdef HAVE_IFADDRS_H
+#include <ifaddrs.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+#ifdef HAVE_SYS_SOCKIO_H
+#include <sys/sockio.h>
+#endif
+#ifdef HAVE_NET_IF_H
+#include <net/if.h>
+#endif
+
#ifndef EWOULDBLOCK
#define EWOULDBLOCK EAGAIN
#endif
@@ -5403,6 +5417,235 @@ addrinfo_s_unix(VALUE self, VALUE path)
#endif
+#if defined(HAVE_GETIFADDRS) || defined(SIOCGLIFCONF) ||
defined(SIOCGIFCONF)
+static VALUE
+sockaddr_obj(struct sockaddr *addr)
+{
- socklen_t len;
- if (addr == NULL)
-
return Qnil;
- switch (addr->sa_family) {
+#ifdef HAVE_SYS_UN_H -
case AF_UNIX:
-
len = sizeof(struct sockaddr_un);
-
break;
+#endif
+
-
case AF_INET:
-
len = sizeof(struct sockaddr_in);
-
break;
+#ifdef AF_INET6
-
case AF_INET6:
-
len = sizeof(struct sockaddr_in6);
-
break;
+#endif
+
-
default:
-
len = sizeof(struct sockaddr_in);
-
break;
- }
+#ifdef SA_LEN - if (len < SA_LEN(addr))
- len = SA_LEN(addr);
+#endif - return addrinfo_new(addr, len, 0, 0, 0, Qnil, Qnil);
+}
+#endif
+/*
-
- call-seq:
-
- AddrInfo.list_ipaddr => array
-
-
- Returns local IP addresses as an array.
-
-
- The array contains AddrInfo objects.
-
-
- pp AddrInfo.list_ipaddr
-
- #=> [#<AddrInfo: 127.0.0.1>,
-
-
#<AddrInfo: 192.168.0.128>,
-
-
-
#<AddrInfo: ::1>,
-
-
-
...]
-
-
- */
+static VALUE
+addrinfo_s_list_ipaddr(VALUE self)
+{
+#if defined(HAVE_GETIFADDRS) - struct ifaddrs *ifp = NULL;
- struct ifaddrs *p;
- int ret;
- VALUE list;
- ret = getifaddrs(&ifp);
- if (ret == -1) {
-
rb_sys_fail("getifaddrs");
- }
- list = rb_ary_new();
- for (p = ifp; p; p = p->ifa_next) {
-
if (IS_IP_FAMILY(p->ifa_addr->sa_family)) {
-
rb_ary_push(list, sockaddr_obj(p->ifa_addr));
-
}
- }
- freeifaddrs(ifp);
- return list;
+#elif defined(SIOCGLIFCONF) && defined(SIOCGLIFNUM) - /* Solaris if_tcp(7P) */
- int fd = -1;
- int ret;
- struct lifnum ln;
- struct lifconf lc;
- char *reason = NULL;
- int save_errno;
- int i;
- VALUE list;
- lc.lifc_buf = NULL;
- fd = socket(AF_INET, SOCK_DGRAM, 0);
- if (fd == -1)
-
rb_sys_fail("socket");
- memset(&ln, 0, sizeof(ln));
- ln.lifn_family = AF_UNSPEC;
- ret = ioctl(fd, SIOCGLIFNUM, &ln);
- if (ret == -1) {
- reason = “SIOCGLIFNUM”;
- goto finish;
- }
- memset(&lc, 0, sizeof(lc));
- lc.lifc_family = AF_UNSPEC;
- lc.lifc_flags = 0;
- lc.lifc_len = sizeof(struct lifreq) * ln.lifn_count;
- lc.lifc_req = xmalloc(lc.lifc_len);
- ret = ioctl(fd, SIOCGLIFCONF, &lc);
- if (ret == -1) {
- reason = “SIOCGLIFCONF”;
- goto finish;
- }
- close(fd);
- fd = -1;
- list = rb_ary_new();
- for (i = 0; i < ln.lifn_count; i++) {
- struct lifreq *req = &lc.lifc_req[i];
-
if (IS_IP_FAMILY(req->lifr_addr.ss_family)) {
-
rb_ary_push(list, sockaddr_obj((struct sockaddr
*)&req->lifr_addr));
-
}
- }
- finish:
- save_errno = errno;
- if (lc.lifc_buf != NULL)
- xfree(lc.lifc_req);
- if (fd != -1)
- close(fd);
- errno = save_errno;
- if (reason)
- rb_sys_fail(reason);
- return list;
+#elif defined(SIOCGIFCONF)
- int fd = -1;
- int ret;
+#define EXTRA_SPACE (sizeof(struct ifconf) + sizeof(struct
sockaddr_storage)) - char initbuf[4096+EXTRA_SPACE];
- char *buf = initbuf;
- int bufsize;
- struct ifconf conf;
- struct ifreq *req;
- VALUE list = Qnil;
- char *reason = NULL;
- int save_errno;
- fd = socket(AF_INET, SOCK_DGRAM, 0);
- if (fd == -1)
-
rb_sys_fail("socket");
- bufsize = sizeof(initbuf);
- buf = initbuf;
- retry:
- conf.ifc_len = bufsize;
- conf.ifc_req = (struct ifreq *)buf;
- /* fprintf(stderr, “bufsize: %d\n”, bufsize); */
- ret = ioctl(fd, SIOCGIFCONF, &conf);
- if (ret == -1) {
-
reason = "SIOCGIFCONF";
-
goto finish;
- }
- /* fprintf(stderr, “conf.ifc_len: %d\n”, conf.ifc_len); */
- if (bufsize - EXTRA_SPACE < conf.ifc_len) {
- if (bufsize < conf.ifc_len) {
-
/* NetBSD returns required size for all interfaces. */
-
bufsize = conf.ifc_len + EXTRA_SPACE;
- }
- else {
-
bufsize = bufsize << 1;
- }
- if (buf == initbuf)
-
buf = NULL;
- buf = xrealloc(buf, bufsize);
- goto retry;
- }
- close(fd);
- fd = -1;
- list = rb_ary_new();
- req = conf.ifc_req;
- while ((char*)req < (char*)conf.ifc_req + conf.ifc_len) {
- struct sockaddr *addr = &req->ifr_addr;
-
if (IS_IP_FAMILY(addr->sa_family)) {
-
rb_ary_push(list, sockaddr_obj(addr));
- }
+#ifdef HAVE_SA_LEN
+# ifndef _SIZEOF_ADDR_IFREQ
+# define _SIZEOF_ADDR_IFREQ® (sizeof(struct ifreq) + \ -
(sizeof(struct sockaddr) <
®.ifr_addr.sa_len ? \
-
(r).ifr_addr.sa_len - sizeof(struct sockaddr) : \
-
0))
+# endif
- req = (struct ifreq )((char)req + _SIZEOF_ADDR_IFREQ(*req));
+#else - req = (struct ifreq )((char)req + sizeof(struct ifreq));
+#endif - }
- finish:
- save_errno = errno;
- if (buf != initbuf)
-
xfree(buf);
- if (fd != -1)
- close(fd);
- errno = save_errno;
- if (reason)
- rb_sys_fail(reason);
- return list;
+#undef EXTRA_SPACE
+#else
- rb_notimplement();
+#endif
+}
static VALUE
sockaddr_string_value(volatile VALUE *v)
{
@@ -5605,6 +5848,8 @@ Init_socket()
rb_define_method(rb_cAddrInfo, "getnameinfo", addrinfo_getnameinfo,
-1);
- rb_define_singleton_method(rb_cAddrInfo, “list_ipaddr”,
addrinfo_s_list_ipaddr, 0); - /* constants */
mConst = rb_define_module_under(rb_cSocket, “Constants”);
init_constants(mConst);
Index: ext/socket/extconf.rb
===================================================================
— ext/socket/extconf.rb (revision 21486)
+++ ext/socket/extconf.rb (working copy)
@@ -258,6 +258,12 @@ unless getaddr_info_ok and have_func("ge
have_header(“resolv.h”)
end
+have_header(“ifaddrs.h”)
+have_func(“getifaddrs”)
+have_header(“sys/ioctl.h”)
+have_header(“sys/sockio.h”)
+have_header(“net/if.h”)
+
unless have_type(“socklen_t”, headers)
$defs << “-Dsocklen_t=int”
end
Index: test/socket/test_addrinfo.rb
— test/socket/test_addrinfo.rb (revision 21486)
+++ test/socket/test_addrinfo.rb (working copy)
@@ -39,6 +39,17 @@ class TestSocketAddrInfo < Test::Unit::T
assert_equal(0, ai.protocol)
end
- def test_list_ipaddr
- begin
-
list = AddrInfo.list_ipaddr
- rescue NotImplementedError
-
return
- end
- list.each {|ai|
-
assert_instance_of(AddrInfo, ai)
- }
- end
- def test_addrinfo_predicates
ipv4_ai = AddrInfo.new(Socket.sockaddr_in(80, “192.168.0.1”))
assert(ipv4_ai.ip?)