AddrInfo.list_ipaddr


#1

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?)

#2

In article removed_email_address@domain.invalid,
Tanaka A. removed_email_address@domain.invalid writes:

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

e$BH?1~$O$"$j$^$;$s$,!"F~$l$^$7$?!#e(B

e$B$J$*!"%a%=%C%IL>$ON,$5$J$$$J$IJQ$($Fe(B Socket.list_ip_address
e$B$K$7$^$7$?!#e(B


#3

At Tue, 20 Jan 2009 20:19:39 +0900,
Tanaka A. wrote:

In article removed_email_address@domain.invalid,
Tanaka A. removed_email_address@domain.invalid writes:

提案なんですが、ホストが持っている IP アドレスのリストを返す
メソッドを用意するのはどうでしょうか。

反応はありませんが、入れました。

なお、メソッド名は略さないなど変えて Socket.list_ip_address
にしました。

中身のことでなくてすみませんが、略さないなら list_ip_addresses か、
list を名詞で使って ip_address_list とすると文法の収まりがいいと
思います。

getifaddrs をもじって getipaddrs というのもありかもしれません。


#4

In article removed_email_address@domain.invalid,
“Akinori MUSHA” removed_email_address@domain.invalid writes:

e$BCf?H$N$3$H$G$J$/$F$9$_$^$;$s$,!"N,$5$J$$$J$ie(B list_ip_addresses e$B$+!"e(B
list e$B$rL>;l$G;H$C$Fe(B ip_address_list e$B$H$9$k$HJ8K!$N<}$^$j$,$$$$$He(B
e$B;W$$$^$9!#e(B

e$B$U$`!#8e<T$+$J$!e(B

getifaddrs e$B$r$b$8$C$Fe(B getipaddrs e$B$H$$$&$N$b$"$j$+$b$7$l$^$;$s!#e(B

getifaddrs e$B$H;w$9$.$F$$$k$H;W$$$^$9!#$$$D$NF|$+!“e(B
Socket.getifaddrs e$B$,M_$7$/$J$C$?$H$-$KL>A0$G6lO+$7$?$/$”$j$^e(B
e$B$;$s!#e(B