AddrInfo

e$BDs0F$J$N$G$9$,!"e(Bext/socket e$B$Ge(B AddrInfo
e$B%/%i%9$r?7@_$9$k$N$O$I$&$G$7$g$&$+!#e(B

AddrInfo e$B$O4pK\E*$K$Oe(B getaddrinfo(3) e$B$Ne(B struct addrinfo
e$B$HBPe(B
e$B1~$9$k>pJs$r$b$D$b$N$H$7$^$9!#e(B

e$B$J$s$G$3$l$,M_$7$$$N$+$H$$$&M}M3$O$$$m$$$m$H$“$j$^$9$,!”$9$0e(B
e$B$K;W$$Ib$+$VM}M3$@$1$G$b0J2<$N$h$&$J$b$N$,$"$j$^$9!#e(B

  • Socket.getaddrinfo e$B$NJV$jCM$,$o$+$j$K$/$$e(B
  • Socket#{accept,recvfrom} e$B$,JV$9Aw?.85$,$o$+$j$K$/$$e(B
  • BasicSocket#{getsockname,getpeername} e$B$,JV$9$b$N$,$o$+$j$Ke(B
    e$B$/$$e(B
  • Socket.sockaddr_in(port, host) e$B$O0z?t$N=gHV$,5U$G8MOG$&e(B
  • Socket.getaddrinfo e$B$N7k2L$r%W%m%H%3%kHs0MB8$Ke(B connect/bind
    e$B$G$-$J$$e(B

e$B$^$:e(B Socket.getaddrinfo
e$B$NJV$jCM$,$o$+$j$K$/$$$H$$$&OC$G$9$,!"e(B
e$B:G6a$Ne(B [ruby-dev:37674] e$B$G;XE&$7$?LdBj$Ne(B

% ./ruby -rpp -rsocket -ve ‘pp Socket.getaddrinfo(“www.ruby-lang.org”,
80)’
ruby 1.9.1 (2009-01-01 patchlevel-5000 trunk 21253) [i686-linux]
[[“AF_INET”, 80, “carbon.ruby-lang.org”, “221.186.184.68”, 2, 2, 17]]

e$B$H$$$&Nc$G$$$&$H!"I=<($7$F$b0UL#$,$h$/$o$+$i$J$$CM$,$$$/$D$+e(B
e$B$D$$$F$$$^$9!#$7$+$7!“e(Bstruct addrinfo
e$B$KBP1~$9$k%/%i%9$,$”$j!“e(B
e$B$=$Ne(B inspecte$B$,E,@Z$KDj5A$5$l$F$$$l$P!”$b$C$H$o$+$j$d$9$$I=<(e(B
e$B$r9T$&$3$H$,$G$-$^$9!#e(BAddrInfo.getaddrinfo e$B$rDj5A$9$k$3$H$Ke(B
e$B$7$F!"e(BAddrInfo e$B$NG[Ns$rJV$9$H$9$l$P!"0J2<$N$h$&$K!"e(BTCP
e$B$H$+e(B
UDP e$B$H$$$C$?$o$+$j$d$9$$I=<($r$9$k$3$H$,=PMh$^$9!#e(B

% ./ruby -rpp -rsocket -e ‘pp AddrInfo.getaddrinfo(“www.ruby-lang.org”,
80)’
[#<AddrInfo: 221.186.184.68:80 TCP (www.ruby-lang.org:80)>,
#<AddrInfo: 221.186.184.68:80 UDP (www.ruby-lang.org:80)>]

e$B$^$?!“e(BAddrInfo e$B$Oe(B struct sockaddr
e$B$rCf$K;}$C$F$$$k$N$G!“e(B
Socket e$B%/%i%9$r;H$&$H$-$KI,MW$H$J$k!”!V%=%1%C%H%”%I%l%99=B$e(B
e$BBN$re(B pack e$B$7$?J8;zNs!W$NBe$o$j$K;H$&$3$H$,=PMh$^$9!#e(B

Socket#{accept,recvfrom} e$B$,JV$9Aw?.85$,$o$+$j$K$/$$$H$$$&$Ne(B
e$B$O!“Aw?.85$H$7$F%=%1%C%H%”%I%l%99=B$BN$rJV$9$+$i$G$9$,!"$3$le(B
e$B$re(B AddrInfo
e$B$KJQ$($k$3$H$K$h$j$o$+$j$d$9$/$9$k$3$H$,$G$-$^$9!#e(B
e$B$J$*e(B Socket#{accept_nonblock,recvfrom_nonblock} e$B$bF1MM$G$9!#e(B

e$B$?$@$7$3$NJQ99$OHs8_49$K$J$j$^$9!#$H$O$$$(!“%=%1%C%H%”%I%l%9e(B
e$B9=B$BN$r<u$1IU$1$k$H$3$m$G$Oe(B AddrInfo e$B$r<u$1IU$1$k$h$&$K$7$Fe(B
e$B$“$k$N$G!”$=$l$[$IBg$-$JLdBj$O5/$-$J$$$3$H$r4|BT$7$^$9!#$^$?!“e(B
AddrInfo#to_sockaddr e$B$Ge(B AddrInfo e$B$+$i%=%1%C%H%”%I%l%99=B$BNe(B
e$B$r<h$j=P$;$^$9$N$G!"$3$NHs8_49@-$GLdBj$,=P$?$H$-$K$O$=$l$,;He(B
e$B$($^$9!#e(B

e$B$^$?!“e(BBasicSocket#{getsockname,getpeername}
e$B$b%=%1%C%H%”%I%l%9e(B
e$B9=B$BN$rJV$9$N$G$o$+$j$K$/$$$N$G$9$,!“e(B
BasicSocket#{local_address,remote_address} e$B$H$$$&%a%=%C%I$re(B
e$B?7@$7$F$=$C$A$Oe(B AddrInfo e$B$rJV$9$h$&$K$7$F$$^$7$?!#e(B
e$B$3$C$A$”$O?7@_$J$N$GHs8_49@-$O$"$j$^$;$s!#$^$?!"e(Bgetsockname
e$B$h$je(B local_address
e$B$H$$$&L>A0$N$[$&$,$o$+$j$d$9$$$H;W$$$^$9!#e(B

BasicSocket e$B$K$D$1$?$N$Ge(B TCPSocket e$B$K$b;H$($F!"Nc$($P!"0J2<e(B
e$B$N$h$&$KF0$-$^$9!#e(B

% ./ruby -rsocket -e ’
TCPSocket.open(“localhost”, 80) {|s| p [s.local_address, s.remote_address] }’
[#<AddrInfo: 127.0.0.1:58231 TCP>, #<AddrInfo: 127.0.0.1:80 TCP>]

IPSocket e$B$G$Oe(B addr, peeraddr e$B$,$“$j$^$9$,!”$3$l$^$?=g=x$r3Pe(B
e$B$($i$l$J$$$H$$$&LdBj$,$"$j$^$9!#e(B

% ./ruby -rsocket -e ’
TCPSocket.open(“localhost”, 80) {|s| p s.addr }’
[“AF_INET”, 58985, “localhost”, “127.0.0.1”]

e$B$5$i$K!"e(Baddr, peeraddr
e$B$OBhe(B3e$BMWAG$r5a$a$k$N$K5U0z$-$r9T$&$N$,e(B
e$BLq2p$G$9!#e(BBasicSocket.do_not_reverse_lookup = true e$B$GM^@)$Oe(B
e$B=PMh$^$9$,!"e(BAddrInfo#inspect e$B$O$=$b$=$b5U0z$-$r9T$$$^$;$s!#e(B
e$B5U0z$-$r9T$o$J$$Be$o$j$K!“e(BAddrInfo e$B$O@8@.;~$Ke(B inspect
e$BMQ$NL>e(B
e$BA0$r5-O?$G$-$^$9!#@50z$-$G%”%I%l%9$r5a$a$?;~$K$O!"85$K$J$C$?e(B
e$BL>A0$r5-O?$7$F$*$/$N$G!“e(B
#<AddrInfo: 221.186.184.68:80 TCP (www.ruby-lang.org:80)>
e$B$H$$$&$h$&$K!”%+%C%3$NCf$KL>A0$,=P$F$-$^$9!#e(B

AddrInfo e$B$r:n$kJ}K!$O$$$/$D$+MQ0U$7$^$7$?$,!“$=$NCf$Ge(B
AddrInfo.tcp(host, port) e$B$He(B AddrInfo.udp(host, port) e$B$Oe(B
Socket.sockaddr_in(port, host) e$B$N0z?t=g$N$o$+$j$K$/$5$r2r7he(B
e$B$7$F$$$^$9!#$J$*!“e(Btcp/udp e$B$N6hJL$r$7$J$$$H$$$1$J$$$N$Oe(B
AddrInfo e$B$,%=%1%C%H%”%I%l%99=B$BN$K2C$($F!”%=%1%C%H$r@8@.$9e(B
e$B$k$?$a$N>pJse(B (SOCK_STREAM/SOCK_DGRAM e$B$H$+e(B)
e$B$b;}$C$F$$$k$+$ie(B
e$B$G$9!#e(B

e$B$=$N>pJs$r;}$C$F$$$k$N$G!“e(BAddrInfo e$B$,M?$($i$l$l$P!”%=%1%C%He(B
e$B$r@8@.$7$Fe(B connect/bind e$B$9$k$3$H$,$G$-$^$9!#e(B

ai = AddrInfo.getaddrinfo(“localhost”, 80)[0] # e$B:G=i$N$d$D$r;H$&e(B
(e$BK\Ev$ONI$/$J$$e(B)
sock = Socket.new(ai.pfamily, ai.socktype, ai.protocol)
sock.connect(ai)

e$B$3$l$KBP$7!“e(BSocket.getaddrinfo e$B$r;H$&$H!”%W%m%H%3%kHs0MB8$Je(B
e$B7A$G$O5-=R$G$-$^$;$s!#e(B

ai = Socket.getaddrinfo(“localhost”, 80)[0]
sock = Socket.new(ai[4], ai[5], ai[6])
sock.connect(Socket.sockaddr_in(ai[1], ai[3]))

e$B$3$3$G!“e(BSocket.sockaddr_in e$B$r;H$C$F$$$k$N$G!”$3$l$Oe(B
IPv4/IPv6 e$B$K0MB8$7$?=q$-J}$K$J$C$F$$$^$9!#e(B

e$B$^$!!"<B:]$Ke(B getaddrinfo e$B$,e(B IPv4/IPv6
e$B0J30$K;H$($k$+$H$$$&$He(B
e$BHyL/$J$H$3$m$G$9$,!"e(BC e$B%l%Y%k$Ne(B getaddrinfo(3)
e$B$G<B8=$G$-$F$$e(B
e$B$k%W%m%H%3%kHs0MB8@-$re(B Ruby e$B$G$O$$$/$i$+<:$C$F$$$k$N$O$?$7$+e(B
e$B$G$9!#e(B

e$B$^$?!"@h$NOC$H$7$F$O!"e(B

  • IPv6 e$B$G$Oe(B sendmsg/recvmsg e$B$NJd=u%G!<%?$r3hMQ$7$F$$$k$h$&$Je(B
    e$B$s$G$9$,!"e(Brecvmsg e$B$G$Oe(B recvfrom
    e$B$HF1MM$KAw?.85$rJV$9$N$G$d$Ce(B
    e$B$Q$je(B AddrInfo e$B$r;H$$$?$$e(B
  • e$B%W%m%H%3%kHs0MB8$K=q$-$?$$$H$O$$$C$F$b$d$C$Q$j%“%I%l%9$KBPe(B
    e$B$9$kA:n$O$?$^$KI,MW$K$J$k$N$Ge(B AddrInfo#ipv4_private? e$B$H$+e(B e$BA:n$r2C$($?$$e(B
    e$B$H$+!”$$$m$$$m9M$($i$l$^$9!#e(B

e$B$H$$$&$o$1$G$I$&$G$7$g$&$+!#Hs8_49@-$O!">e$G=R$Y$?e(B
Socket#{accept,recvfrom,accept_nonblock,recvfrom_nonblock}
e$B$@$1$J$N$G!"0-$/$J$$$s$8$c$J$$$+$H;W$&$s$G$9$,!#e(B

Index: ext/socket/socket.c

— ext/socket/socket.c (revision 21278)
+++ ext/socket/socket.c (working copy)
@@ -88,6 +88,7 @@ VALUE rb_cUNIXSocket;
VALUE rb_cUNIXServer;
#endif
VALUE rb_cSocket;
+static VALUE rb_cAddrInfo;

static VALUE rb_eSocket;

@@ -572,6 +573,88 @@ bsock_getpeername(VALUE sock)
return rb_str_new(buf, len);
}

+static VALUE addrinfo_new(struct sockaddr *, socklen_t, int, int, int,
VALUE, VALUE);
+
+static VALUE
+fd_socket_addrinfo(int fd, struct sockaddr *addr, socklen_t len)
+{

  • /* assumes protocol family and address family are identical */
  • int family = addr->sa_family;
  • int socktype;
  • int ret;
  • socklen_t optlen = sizeof(socktype);
  • ret = getsockopt(fd, SOL_SOCKET, SO_TYPE, (void*)&socktype,
    &optlen);
  • if (ret == -1) {
  • rb_sys_fail(“getsockopt(SO_TYPE)”);
  • }
  • return addrinfo_new(addr, len, family, socktype, 0, Qnil, Qnil);
    +}

+static VALUE
+io_socket_addrinfo(VALUE io, struct sockaddr *addr, socklen_t len)
+{

  • rb_io_t *fptr;
  • switch (TYPE(io)) {
  •  case T_FIXNUM:
    
  •    return fd_socket_addrinfo(FIX2INT(io), addr, len);
    
  •  case T_BIGNUM:
    
  •    return fd_socket_addrinfo(NUM2INT(io), addr, len);
    
  •  case T_FILE:
    
  •    GetOpenFile(io, fptr);
    
  •    return fd_socket_addrinfo(fptr->fd, addr, len);
    
  •  default:
    
  • rb_raise(rb_eTypeError, “neither IO nor file descriptor”);
  • }
    +}

+/*

    • call-seq:
    • bsock.local_address => addrinfo
    • returns an AddrInfo object for local address obtained by
      getsockname.
    • Note that addrinfo.protocol is filled by 0.
  • */
    +static VALUE
    +bsock_local_address(VALUE sock)
    +{
  • char buf[1024];
  • socklen_t len = sizeof buf;
  • rb_io_t *fptr;
  • GetOpenFile(sock, fptr);
  • if (getsockname(fptr->fd, (struct sockaddr*)buf, &len) < 0)
  • rb_sys_fail(“getsockname(2)”);
  • return fd_socket_addrinfo(fptr->fd, (struct sockaddr *)buf, len);
    +}

+/*

    • call-seq:
    • bsock.remote_address => addrinfo
    • returns an AddrInfo object for remote address obtained by
      getpeername.
    • Note that addrinfo.protocol is filled by 0.
  • */
    +static VALUE
    +bsock_remote_address(VALUE sock)
    +{
  • char buf[1024];
  • socklen_t len = sizeof buf;
  • rb_io_t *fptr;
  • GetOpenFile(sock, fptr);
  • if (getpeername(fptr->fd, (struct sockaddr*)buf, &len) < 0)
  • rb_sys_fail(“getpeername(2)”);
  • return fd_socket_addrinfo(fptr->fd, (struct sockaddr *)buf, len);
    +}

struct send_arg {
int fd, flags;
VALUE mesg;
@@ -744,7 +827,7 @@ s_recvfrom(VALUE sock, int argc, VALUE *
return rb_assoc_new(str, unixaddr((struct sockaddr_un*)arg.buf,
arg.alen));
#endif
case RECV_SOCKET:

  • return rb_assoc_new(str, rb_str_new(arg.buf, arg.alen));
  • return rb_assoc_new(str, io_socket_addrinfo(sock, (struct
    sockaddr*)arg.buf, arg.alen));
    default:
    rb_bug(“s_recvfrom called with bad value”);
    }
    @@ -804,7 +887,7 @@ s_recvfrom_nonblock(VALUE sock, int argc
    break;

    case RECV_SOCKET:
    
  •    addr = rb_str_new(buf, alen);
    
  •    addr = io_socket_addrinfo(sock, (struct sockaddr*)buf, alen);
       break;
    
     default:
    

@@ -2971,7 +3054,7 @@ sock_accept(VALUE sock)
GetOpenFile(sock, fptr);
sock2 = s_accept(rb_cSocket,fptr->fd,(struct sockaddr*)buf,&len);

  • return rb_assoc_new(sock2, rb_str_new(buf, len));
  • return rb_assoc_new(sock2, io_socket_addrinfo(sock2, (struct
    sockaddr*)buf, len));
    }

/*
@@ -3032,7 +3115,7 @@ sock_accept_nonblock(VALUE sock)

 GetOpenFile(sock, fptr);
 sock2 = s_accept_nonblock(rb_cSocket, fptr, (struct sockaddr *)buf, 

&len);

  • return rb_assoc_new(sock2, rb_str_new(buf, len));
  • return rb_assoc_new(sock2, io_socket_addrinfo(sock2, (struct
    sockaddr*)buf, len));
    }

/*
@@ -3085,7 +3168,7 @@ sock_sysaccept(VALUE sock)
GetOpenFile(sock, fptr);
sock2 = s_accept(0,fptr->fd,(struct sockaddr*)buf,&len);

  • return rb_assoc_new(sock2, rb_str_new(buf, len));
  • return rb_assoc_new(sock2, io_socket_addrinfo(sock2, (struct
    sockaddr*)buf, len));
    }

#ifdef HAVE_GETHOSTNAME
@@ -3516,6 +3599,864 @@ sock_s_unpack_sockaddr_un(VALUE self, VA
}
#endif

+typedef struct {

  • VALUE inspectname;
  • VALUE canonname;
  • int pfamily;
  • int socktype;
  • int protocol;
  • struct sockaddr_storage addr;
    +} rb_addrinfo_t;

+static void
+addrinfo_mark(rb_addrinfo_t *rai)
+{

  • if (rai) {
  •    rb_gc_mark(rai->inspectname);
    
  •    rb_gc_mark(rai->canonname);
    
  • }
    +}

+static void
+addrinfo_free(rb_addrinfo_t *rai)
+{

  • xfree(rai);
    +}

+static socklen_t
+sockaddr_size(int family)
+{

  • switch (family) {
  •  case AF_INET: return sizeof(struct sockaddr_in);
    

+#ifdef INET6

  •  case AF_INET6: return sizeof(struct sockaddr_in6);
    

+#endif
+#ifdef HAVE_SYS_UN_H

  •  case AF_UNIX: return sizeof(struct sockaddr_un);
    

+#endif

  •  default: return sizeof(struct sockaddr);
    
  • }
    +}

+static VALUE
+addrinfo_s_allocate(VALUE klass)
+{

  • return Data_Wrap_Struct(klass, addrinfo_mark, addrinfo_free, 0);
    +}

+#define IS_ADDRINFO(obj) (RDATA(obj)->dmark ==
(RUBY_DATA_FUNC)addrinfo_mark)
+static rb_addrinfo_t *
+check_addrinfo(VALUE self)
+{

  • Check_Type(self, T_DATA);
  • if (!IS_ADDRINFO(self)) {
  •    rb_raise(rb_eTypeError, "wrong argument type %s (expected 
    

AddrInfo)",

  •             rb_class2name(CLASS_OF(self)));
    
  • }
  • return DATA_PTR(self);
    +}

+static rb_addrinfo_t *
+get_addrinfo(VALUE self)
+{

  • rb_addrinfo_t *rai = check_addrinfo(self);
  • if (!rai) {
  •    rb_raise(rb_eTypeError, "uninitialized socket address");
    
  • }
  • return rai;
    +}

+static rb_addrinfo_t *
+alloc_addrinfo()
+{

  • rb_addrinfo_t *rai = ALLOC(rb_addrinfo_t);
  • memset(rai, 0, sizeof(rb_addrinfo_t));
  • rai->inspectname = Qnil;
  • rai->canonname = Qnil;
  • return rai;
    +}

+static void
+init_addrinfo(rb_addrinfo_t *rai, struct sockaddr *sa, size_t len,

  •          int pfamily, int socktype, int protocol,
    
  •          VALUE canonname, VALUE inspectname)
    

+{

  • if (sizeof(rai->addr) < len)
  •    rb_raise(rb_eArgError, "sockaddr string too big");
    
  • memcpy((void *)&rai->addr, (void *)sa, len);
  • rai->pfamily = pfamily;
  • rai->socktype = socktype;
  • rai->protocol = protocol;
  • rai->canonname = canonname;
  • rai->inspectname = inspectname;
    +}

+static VALUE
+addrinfo_new(struct sockaddr *addr, socklen_t len,

  •         int family, int socktype, int protocol,
    
  •         VALUE canonname, VALUE inspectname)
    

+{

  • VALUE a;
  • rb_addrinfo_t *rai;
  • a = addrinfo_s_allocate(rb_cAddrInfo);
  • DATA_PTR(a) = rai = alloc_addrinfo();
  • init_addrinfo(rai, addr, len, family, socktype, protocol,
    canonname, inspectname);
  • return a;
    +}

+static struct addrinfo *
+call_getaddrinfo(VALUE node, VALUE service,

  •             VALUE family, VALUE socktype, VALUE protocol, VALUE 
    

flags)
+{

  • struct addrinfo hints, *res;
  • MEMZERO(&hints, struct addrinfo, 1);
  • hints.ai_family = NIL_P(family) ? PF_UNSPEC : family_arg(family);
  • if (!NIL_P(socktype)) {
  • hints.ai_socktype = socktype_arg(socktype);
  • }
  • if (!NIL_P(protocol)) {
  • hints.ai_protocol = NUM2INT(protocol);
  • }
  • if (!NIL_P(flags)) {
  • hints.ai_flags = NUM2INT(flags);
  • }
  • res = sock_getaddrinfo(node, service, &hints, 0);
  • if (res == NULL)
  • rb_raise(rb_eSocket, “host not found”);
  • return res;
    +}

+static void
+init_addrinfo_getaddrinfo(rb_addrinfo_t *rai, VALUE node, VALUE
service,

  •                      VALUE family, VALUE socktype, VALUE protocol, 
    

VALUE flags,

  •                      VALUE inspectname)
    

+{

  • struct addrinfo *res = call_getaddrinfo(node, service, family,
    socktype, protocol, flags);
  • VALUE canonname;
  • canonname = Qnil;
  • if (res->ai_canonname) {
  •    canonname = rb_tainted_str_new_cstr(res->ai_canonname);
    
  •    OBJ_FREEZE(canonname);
    
  • }
  • init_addrinfo(rai, res->ai_addr, res->ai_addrlen,
  •              NUM2INT(family), NUM2INT(socktype), 
    

NUM2INT(protocol),

  •              canonname, inspectname);
    
  • freeaddrinfo(res);
    +}

+static VALUE
+make_inspectname(VALUE node, VALUE service)
+{

  • VALUE inspectname = Qnil;
  • if (TYPE(node) == T_STRING) {
  •    inspectname = rb_str_dup(node);
    
  • }
  • if (TYPE(service) == T_STRING) {
  •    if (NIL_P(inspectname))
    
  •        inspectname = rb_sprintf(":%s", StringValueCStr(service));
    
  •    else
    
  •        rb_str_catf(inspectname, ":%s", StringValueCStr(service));
    
  • }
  • else if (TYPE(service) == T_FIXNUM && FIX2INT(service) != 0)
  • {
  •    if (NIL_P(inspectname))
    
  •        inspectname = rb_sprintf(":%d", FIX2INT(service));
    
  •    else
    
  •        rb_str_catf(inspectname, ":%d", FIX2INT(service));
    
  • }
  • if (!NIL_P(inspectname)) {
  •    OBJ_INFECT(inspectname, node);
    
  •    OBJ_INFECT(inspectname, service);
    
  •    OBJ_FREEZE(inspectname);
    
  • }
  • return inspectname;
    +}

+static VALUE
+addrinfo_firstonly_new(VALUE node, VALUE service, VALUE family, VALUE
socktype, VALUE protocol, VALUE flags)
+{

  • VALUE ret;
  • VALUE canonname;
  • VALUE inspectname;
  • struct addrinfo *res = call_getaddrinfo(node, service, family,
    socktype, protocol, flags);
  • inspectname = make_inspectname(node, service);
  • canonname = Qnil;
  • if (res->ai_canonname) {
  •    canonname = rb_tainted_str_new_cstr(res->ai_canonname);
    
  •    OBJ_FREEZE(canonname);
    
  • }
  • ret = addrinfo_new(res->ai_addr, res->ai_addrlen,
  •                   res->ai_family, res->ai_socktype, 
    

res->ai_protocol,

  •                   canonname, inspectname);
    
  • freeaddrinfo(res);
  • return ret;
    +}

+static VALUE
+addrinfo_list_new(VALUE node, VALUE service, VALUE family, VALUE
socktype, VALUE protocol, VALUE flags)
+{

  • VALUE ret;
  • struct addrinfo *r;
  • VALUE inspectname;
  • struct addrinfo *res = call_getaddrinfo(node, service, family,
    socktype, protocol, flags);
  • inspectname = make_inspectname(node, service);
  • ret = rb_ary_new();
  • for (r = res; r; r = r->ai_next) {
  •    VALUE addr;
    
  •    VALUE canonname = Qnil;
    
  •    if (r->ai_canonname) {
    
  •        canonname = rb_tainted_str_new_cstr(r->ai_canonname);
    
  •        OBJ_FREEZE(canonname);
    
  •    }
    
  •    addr = addrinfo_new(r->ai_addr, r->ai_addrlen,
    
  •                        r->ai_family, r->ai_socktype, 
    

r->ai_protocol,

  •                        canonname, inspectname);
    
  •    rb_ary_push(ret, addr);
    
  • }
  • freeaddrinfo(res);
  • return ret;
    +}

+#ifdef HAVE_SYS_UN_H
+static VALUE
+init_unix_addrinfo(rb_addrinfo_t *rai, VALUE path)
+{

  • struct sockaddr_un un;
  • VALUE addr;
  • StringValue(path);
  • if (sizeof(un.sun_path) <= RSTRING_LEN(path))
  •    rb_raise(rb_eArgError, "too long unix socket path (max: 
    

%dbytes)",

  •        (int)sizeof(un.sun_path)-1);
    
  • MEMZERO(&un, struct sockaddr_un, 1);
  • un.sun_family = AF_UNIX;
  • memcpy((void*)&un.sun_path, RSTRING_PTR(path), RSTRING_LEN(path));
  • init_addrinfo(rai, (struct sockaddr *)&un, sizeof(un), AF_UNIX,
    SOCK_STREAM, 0, Qnil, Qnil);
  • return addr;
    +}
    +#endif

+/*

    • call-seq:
    • AddrInfo.new(sockaddr)
    • AddrInfo.new(sockaddr, family)
    • AddrInfo.new(sockaddr, family, socktype)
    • AddrInfo.new(sockaddr, family, socktype, protocol)
    • returns a new instance of AddrInfo.
    • It the instnace contains sockaddr, family, socktype, protocol.
    • sockaddr means struct sockaddr which can be used for connect(2),
      etc.
    • family, socktype and protocol are integers which is used for
      arguments of socket(2).
    • sockaddr is specified as an array or a string.
    • The array should be compatible to the value of IPSocket#addr or
      UNIXSocket#addr.
    • The string should be struct sockaddr as generated by
    • Socket.sockaddr_in or Socket.unpack_sockaddr_un.
    • sockaddr examples:
      • [“AF_INET”, 46102, “localhost.localdomain”, “127.0.0.1”]
      • [“AF_INET6”, 42304, “ip6-localhost”, “::1”]
      • [“AF_UNIX”, “/tmp/sock”]
      • Socket.sockaddr_in(“smtp”, “2001:DB8::1”)
      • Socket.sockaddr_in(80, “172.18.22.42”)
      • Socket.sockaddr_un(“/tmp/sock”)
    • In an AF_INET/AF_INET6 sockaddr array, the 4th element,
    • numeric IP address, is used to construct socket address in the
      AddrInfo instance.
    • The 3rd element, textual host name, is also recorded but only used
      for AddrInfo#inspect.
    • family is specified as an integer to specify the protocol family
      such as Socket::PF_INET.
    • It can be a symbol or a string which is the constant name
    • with or without PF_ prefix such as :INET, :INET6, :UNIX, “PF_INET”,
      etc.
    • If ommitted, PF_UNSPEC is assumed.
    • socktype is specified as an integer to specify the socket type such
      as Socket::SOCK_STREAM.
    • It can be a symbol or a string which is the constant name
    • with or without SOCK_ prefix such as :STREAM, :DGRAM, :RAW,
      “SOCK_STREAM”, etc.
    • If ommitted, 0 is assumed.
    • protocol is specified as an integer to specify the protocol such as
      Socket::IPPROTO_TCP.
    • It must be an integer, unlike family and socktype.
    • If ommitted, 0 is assumed.
    • Note that 0 is reasonable value for most protocols, except raw
      socket.
  • */
    +static VALUE
    +addrinfo_initialize(int argc, VALUE *argv, VALUE self)
    +{
  • rb_addrinfo_t *rai;
  • VALUE sockaddr_arg, sockaddr_ary, pfamily, socktype, protocol;
  • int i_pfamily, i_socktype, i_protocol;
  • struct sockaddr *sockaddr_ptr;
  • size_t sockaddr_len;
  • VALUE canonname = Qnil, inspectname = Qnil;
  • if (check_addrinfo(self))
  •    rb_raise(rb_eTypeError, "already initialized socket address");
    
  • DATA_PTR(self) = rai = alloc_addrinfo();
  • rb_scan_args(argc, argv, “13”, &sockaddr_arg, &pfamily, &socktype,
    &protocol);
  • i_pfamily = NIL_P(pfamily) ? PF_UNSPEC : family_arg(pfamily);
  • i_socktype = NIL_P(socktype) ? 0 : socktype_arg(socktype);
  • i_protocol = NIL_P(protocol) ? 0 : NUM2INT(protocol);
  • sockaddr_ary = rb_check_array_type(sockaddr_arg);
  • if (!NIL_P(sockaddr_ary)) {
  •    VALUE afamily = rb_ary_entry(sockaddr_ary, 0);
    
  •    int af;
    
  •    StringValue(afamily);
    
  •    if (family_to_int(RSTRING_PTR(afamily), RSTRING_LEN(afamily), 
    

&af) == -1)

  •  rb_raise(rb_eSocket, "unknown address family: %s", 
    

StringValueCStr(afamily));

  •    switch (af) {
    
  •      case AF_INET: /* ["AF_INET", 46102, "localhost.localdomain", 
    

“127.0.0.1”] */
+#ifdef INET6

  •      case AF_INET6: /* ["AF_INET6", 42304, "ip6-localhost", "::1"] 
    

*/
+#endif

  •      {
    
  •        VALUE service = rb_ary_entry(sockaddr_ary, 1);
    
  •        VALUE nodename = rb_ary_entry(sockaddr_ary, 2);
    
  •        VALUE numericnode = rb_ary_entry(sockaddr_ary, 3);
    
  •        service = INT2NUM(NUM2INT(service));
    
  •        if (!NIL_P(nodename))
    
  •            StringValue(nodename);
    
  •        StringValue(numericnode);
    
  •        init_addrinfo_getaddrinfo(rai, numericnode, service,
    
  •                INT2NUM(i_pfamily ? i_pfamily : af), 
    

INT2NUM(i_socktype), INT2NUM(i_protocol),

  •                INT2NUM(AI_NUMERICHOST|AI_NUMERICSERV),
    
  •                rb_str_equal(numericnode, nodename) ? Qnil : 
    

make_inspectname(nodename, service));

  •        break;
    
  •      }
    

+#ifdef HAVE_SYS_UN_H

  •      case AF_UNIX: /* ["AF_UNIX", "/tmp/sock"] */
    
  •      {
    
  •        VALUE path = rb_ary_entry(sockaddr_ary, 1);
    
  •        StringValue(path);
    
  •        init_unix_addrinfo(rai, path);
    
  •        break;
    
  •      }
    

+#endif
+

  •      default:
    
  •        rb_raise(rb_eSocket, "unexpected address family");
    
  •    }
    
  • }
  • else {
  •    StringValue(sockaddr_arg);
    
  •    sockaddr_ptr = (struct sockaddr *)RSTRING_PTR(sockaddr_arg);
    
  •    sockaddr_len = RSTRING_LEN(sockaddr_arg);
    
  •    init_addrinfo(rai, sockaddr_ptr, sockaddr_len,
    
  •                  i_pfamily, i_socktype, i_protocol,
    
  •                  canonname, inspectname);
    
  • }
  • return self;
    +}

+/*

    • call-seq:
    • addrinfo.inspect
    • returns a string which shows addrinfo in human-readable form.
    • AddrInfo.tcp(“localhost”, 80).inspect #=> “#<AddrInfo:
      127.0.0.1:80 TCP (localhost:80)>”
    • AddrInfo.unix(“/tmp/sock”).inspect #=> “#<AddrInfo: /tmp/sock
      SOCK_STREAM>”
  • */
    +static VALUE
    +addrinfo_inspect(VALUE self)
    +{
  • rb_addrinfo_t *rai = get_addrinfo(self);
  • int internet_p;
  • VALUE ret;
  • ret = rb_sprintf("#<%s: ", rb_obj_classname(self));
  • switch (rai->addr.ss_family) {
  •  case AF_INET:
    
  •  {
    
  •    struct sockaddr_in *addr = (struct sockaddr_in *)&rai->addr;
    
  •    int port;
    
  •    rb_str_catf(ret, "%d.%d.%d.%d",
    
  •                ((unsigned char*)&addr->sin_addr)[0],
    
  •                ((unsigned char*)&addr->sin_addr)[1],
    
  •                ((unsigned char*)&addr->sin_addr)[2],
    
  •                ((unsigned char*)&addr->sin_addr)[3]);
    
  •    port = ntohs(addr->sin_port);
    
  •    if (port)
    
  •        rb_str_catf(ret, ":%d", port);
    
  •    break;
    
  •  }
    

+#ifdef INET6

  •  case AF_INET6:
    
  •  {
    
  •    struct sockaddr_in6 *addr = (struct sockaddr_in6 *)&rai->addr;
    
  •    char hbuf[1024];
    
  •    int port;
    
  •    int error;
    
  •    /* use getnameinfo for scope_id.
    
  •     * RFC 4007: IPv6 Scoped Address Architecture
    
  •     * draft-ietf-ipv6-scope-api-00.txt: Scoped Address Extensions 
    

to the IPv6 Basic Socket API

  •     */
    
  •    error = getnameinfo((struct sockaddr *)&rai->addr, 
    

sizeof(struct sockaddr_in6),

  •                        hbuf, sizeof(hbuf), NULL, 0,
    
  •                        NI_NUMERICHOST|NI_NUMERICSERV);
    
  •    if (error) {
    
  •        raise_socket_error("getnameinfo", error);
    
  •    }
    
  •    rb_str_catf(ret, "[%s]", hbuf);
    
  •    port = ntohs(addr->sin6_port);
    
  •    if (port)
    
  •        rb_str_catf(ret, ":%d", port);
    
  •    break;
    
  •  }
    

+#endif
+
+#ifdef HAVE_SYS_UN_H

  •  case AF_UNIX:
    
  •  {
    
  •    struct sockaddr_un *addr = (struct sockaddr_un *)&rai->addr;
    
  •    if (addr->sun_path[0] == '/') { /* show absolute path as-is */
    
  •        rb_str_catf(ret, "%.*s", sizeof(addr->sun_path), 
    

addr->sun_path);

  •    }
    
  •    else {
    
  •        char *s, *e;
    
  •        rb_str_cat2(ret, "AF_UNIX");
    
  •        s = addr->sun_path;
    
  •        e = addr->sun_path + sizeof(addr->sun_path);
    
  •        while (s < e && *(e-1) == '\0')
    
  •            e--;
    
  •        while (s < e)
    
  •            rb_str_catf(ret, ":%02x", (unsigned char)*s++);
    
  •    }
    
  •    break;
    
  •  }
    

+#endif
+

  •  default:
    
  •  {
    
  •    ID id = intern_family(rai->addr.ss_family);
    
  •    if (id == 0)
    
  •        rb_str_catf(ret, "unknown address family %d", 
    

rai->addr.ss_family);

  •    else
    
  •        rb_str_catf(ret, "%s address format unknown", 
    

rb_id2name(id));

  •    break;
    
  •  }
    
  • }
  • if (rai->pfamily && rai->addr.ss_family != rai->pfamily) {
  •    ID id = intern_protocol_family(rai->pfamily);
    
  •    if (id)
    
  •        rb_str_catf(ret, " %s", rb_id2name(id));
    
  •    else
    
  •        rb_str_catf(ret, " PF_\?\?\?(%d)", rai->pfamily);
    
  • }
  • internet_p = rai->pfamily == PF_INET;
    +#ifdef INET6
  • internet_p = internet_p || rai->pfamily == PF_INET6;
    +#endif
  • if (internet_p && rai->socktype == SOCK_STREAM &&
  •    (rai->protocol == 0 || rai->protocol == IPPROTO_TCP)) {
    
  •    rb_str_cat2(ret, " TCP");
    
  • }
  • else if (internet_p && rai->socktype == SOCK_DGRAM &&
  •    (rai->protocol == 0 || rai->protocol == IPPROTO_UDP)) {
    
  •    rb_str_cat2(ret, " UDP");
    
  • }
  • else {
  •    if (rai->socktype) {
    
  •        ID id = intern_socktype(rai->socktype);
    
  •        if (id)
    
  •            rb_str_catf(ret, " %s", rb_id2name(id));
    
  •        else
    
  •            rb_str_catf(ret, " SOCK_\?\?\?(%d)", rai->socktype);
    
  •    }
    
  •    if (rai->protocol) {
    
  •        if (internet_p) {
    
  •            ID id = intern_ipproto(rai->protocol);
    
  •            if (id)
    
  •                rb_str_catf(ret, " %s", rb_id2name(id));
    
  •            else
    
  •                goto unknown_protocol;
    
  •        }
    
  •        else {
    
  •          unknown_protocol:
    
  •            rb_str_catf(ret, " UNKNOWN_PROTOCOL(%d)", 
    

rai->protocol);

  •        }
    
  •    }
    
  • }
  • if (!NIL_P(rai->canonname)) {
  •    VALUE name = rai->canonname;
    
  •    rb_str_catf(ret, " %s", StringValueCStr(name));
    
  • }
  • if (!NIL_P(rai->inspectname)) {
  •    VALUE name = rai->inspectname;
    
  •    rb_str_catf(ret, " (%s)", StringValueCStr(name));
    
  • }
  • rb_str_buf_cat2(ret, “>”);
  • return ret;
    +}

+/*

    • call-seq:
    • addrinfo.afamily
    • returns the address family as an integer.
    • AddrInfo.tcp(“localhost”, 80).afamily == Socket::AF_INET #=> true
  • */
    +static VALUE
    +addrinfo_afamily(VALUE self)
    +{
  • rb_addrinfo_t *rai = get_addrinfo(self);
  • return INT2NUM(rai->addr.ss_family);
    +}

+/*

    • call-seq:
    • addrinfo.pfamily
    • returns the protocol family as an integer.
    • AddrInfo.tcp(“localhost”, 80).pfamily == Socket::PF_INET #=> true
  • */
    +static VALUE
    +addrinfo_pfamily(VALUE self)
    +{
  • rb_addrinfo_t *rai = get_addrinfo(self);
  • return INT2NUM(rai->pfamily);
    +}

+/*

    • call-seq:
    • addrinfo.socktype
    • returns the socket type as an integer.
    • AddrInfo.tcp(“localhost”, 80).socktype == Socket::SOCK_STREAM #=>
      true
  • */
    +static VALUE
    +addrinfo_socktype(VALUE self)
    +{
  • rb_addrinfo_t *rai = get_addrinfo(self);
  • return INT2NUM(rai->socktype);
    +}

+/*

    • call-seq:
    • addrinfo.protocol
    • returns the socket type as an integer.
    • AddrInfo.tcp(“localhost”, 80).protocol == Socket::IPPROTO_TCP #=>
      true
  • */
    +static VALUE
    +addrinfo_protocol(VALUE self)
    +{
  • rb_addrinfo_t *rai = get_addrinfo(self);
  • return INT2NUM(rai->protocol);
    +}

+/*

    • call-seq:
    • addrinfo.to_sockaddr
    • returns the socket address as packed struct sockaddr string.
    • AddrInfo.tcp(“localhost”, 80).to_sockaddr
    • #=>
      “\x02\x00\x00P\x7F\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00”
  • */
    +static VALUE
    +addrinfo_to_sockaddr(VALUE self)
    +{
  • rb_addrinfo_t *rai = get_addrinfo(self);
  • VALUE ret;
  • ret = rb_str_new((char*)&rai->addr,
    sockaddr_size(rai->addr.ss_family));
  • OBJ_INFECT(ret, self);
  • return ret;
    +}

+/*

    • call-seq:
    • addrinfo.canonname
    • returns the canonical name as an string.
    • The canonical name is set by AddrInfo.getaddrinfo when AI_CANONNAME
      is specified.
    • list = AddrInfo.getaddrinfo(“www.ruby-lang.org”, 80, :INET,
      :STREAM, nil, Socket::AI_CANONNAME)
  • */
    +static VALUE
    +addrinfo_canonname(VALUE self)
    +{
  • rb_addrinfo_t *rai = get_addrinfo(self);
  • return rai->canonname;
    +}

+/*

    • call-seq:
    • addrinfo.inet?
    • returns true if addrinfo is internet (IPv4/IPv6) address.
    • AddrInfo.tcp(“127.0.0.1”, 80).inet? #=> true
    • AddrInfo.tcp(“::1”, 80).inet? #=> true
    • AddrInfo.unix(“/tmp/sock”).inet? #=> false
  • */
    +static VALUE
    +addrinfo_inet_p(VALUE self)
    +{
  • rb_addrinfo_t *rai = get_addrinfo(self);
  • return rai->addr.ss_family == AF_INET
    +#ifdef AF_INET6
  •    || rai->addr.ss_family == AF_INET6
    

+#endif

  •    ? Qtrue : Qfalse;
    
  • return Qfalse;
    +}

+/*

    • call-seq:
    • addrinfo.ipv4?
    • returns true if addrinfo is IPv4 address.
    • AddrInfo.tcp(“127.0.0.1”, 80).ipv4? #=> true
    • AddrInfo.tcp(“::1”, 80).ipv4? #=> false
    • AddrInfo.unix(“/tmp/sock”).ipv4? #=> false
  • */
    +static VALUE
    +addrinfo_ipv4_p(VALUE self)
    +{
  • rb_addrinfo_t *rai = get_addrinfo(self);
  • return rai->addr.ss_family == AF_INET ? Qtrue : Qfalse;
    +}

+/*

    • call-seq:
    • addrinfo.ipv6?
    • returns true if addrinfo is IPv6 address.
    • AddrInfo.tcp(“127.0.0.1”, 80).ipv6? #=> false
    • AddrInfo.tcp(“::1”, 80).ipv6? #=> true
    • AddrInfo.unix(“/tmp/sock”).ipv6? #=> false
  • */
    +static VALUE
    +addrinfo_ipv6_p(VALUE self)
    +{
  • rb_addrinfo_t *rai = get_addrinfo(self);
    +#ifdef AF_INET6
  • return rai->addr.ss_family == AF_INET6 ? Qtrue : Qfalse;
    +#else
  • return Qfalse;
    +#endif
    +}

+/*

    • call-seq:
    • addrinfo.unix?
    • returns true if addrinfo is UNIX address.
    • AddrInfo.tcp(“127.0.0.1”, 80).ipv6? #=> false
    • AddrInfo.tcp(“::1”, 80).ipv6? #=> false
    • AddrInfo.unix(“/tmp/sock”).ipv6? #=> true
  • */
    +static VALUE
    +addrinfo_unix_p(VALUE self)
    +{
  • rb_addrinfo_t *rai = get_addrinfo(self);
    +#ifdef AF_UNIX
  • return rai->addr.ss_family == AF_UNIX ? Qtrue : Qfalse;
    +#else
  • return Qfalse;
    +#endif
    +}

+/*

    • call-seq:
    • addrinfo.getnameinfo => [nodename, service]
    • addrinfo.getnameinfo(flags) => [nodename, service]
    • returns nodename and service as a pair of strings.
    • This converts struct sockaddr in addrinfo to textual representation.
    • flags should be bitwise OR of Socket::NI_??? constants.
    • AddrInfo.tcp(“127.0.0.1”, 80).getnameinfo #=> [“localhost”, “www”]
    • AddrInfo.tcp(“127.0.0.1”, 80).getnameinfo(Socket::NI_NUMERICSERV)
    • #=> [“localhost”, “80”]
  • */
    +static VALUE
    +addrinfo_getnameinfo(int argc, VALUE *argv, VALUE self)
    +{
  • rb_addrinfo_t *rai = get_addrinfo(self);
  • VALUE vflags;
  • char hbuf[1024], pbuf[1024];
  • int flags, error;
  • rb_scan_args(argc, argv, “01”, &vflags);
  • flags = NIL_P(vflags) ? 0 : NUM2INT(vflags);
  • error = getnameinfo((struct sockaddr *)&rai->addr, sizeof(struct
    sockaddr_storage),
  •                    hbuf, sizeof(hbuf), pbuf, sizeof(pbuf),
    
  •                    flags);
    
  • if (error) {
  •    raise_socket_error("getnameinfo", error);
    
  • }
  • return rb_assoc_new(rb_str_new2(hbuf), rb_str_new2(pbuf));
    +}

+/*

    • call-seq:
    • AddrInfo.getaddrinfo(nodename, service, family, socktype,
      protocol, flags) => [addrinfo, …]
    • AddrInfo.getaddrinfo(nodename, service, family, socktype,
      protocol) => [addrinfo, …]
    • AddrInfo.getaddrinfo(nodename, service, family, socktype)
      => [addrinfo, …]
    • AddrInfo.getaddrinfo(nodename, service, family)
      => [addrinfo, …]
    • AddrInfo.getaddrinfo(nodename, service)
      => [addrinfo, …]
    • returns a list of addrinfo objects as an array.
    • This method converts nodename (hostname) and service (port) to
      addrinfo.
    • Since the conversion is not unique, the result is a list of addrinfo
      objects.
    • nodename or service can be nil if no conversion intended.
    • family, socktype and protocol are hint for prefered protocol.
    • If the result will be used for a socket with SOCK_STREAM,
    • SOCK_STREAM should be specified as socktype.
    • If so, AddrInfo.getaddrinfo returns addrinfo list appropriate for
      SOCK_STREAM.
    • If they are omitted or nil is given, the result is not restricted.
    • Similary, PF_INET6 as family restricts for IPv6.
    • flags should be bitwise OR of Socket::AI_??? constants.
    • AddrInfo.getaddrinfo(“www.kame.net”, 80, nil, :STREAM)
    • #<AddrInfo: [2001:200:0:8002:203:47ff:fea5:3085]:80 TCP

(www.kame.net:80)>]

  • */
    +static VALUE
    +addrinfo_s_getaddrinfo(int argc, VALUE *argv, VALUE self)
    +{
  • VALUE node, service, family, socktype, protocol, flags;
  • rb_scan_args(argc, argv, “24”, &node, &service, &family, &socktype,
    &protocol, &flags);
  • return addrinfo_list_new(node, service, family, socktype, protocol,
    flags);
    +}

+/*

    • call-seq:
    • AddrInfo.tcp(host, port) => addrinfo
    • returns an addrinfo object for TCP address.
    • AddrInfo.tcp(“localhost”, “smtp”) #=> #<AddrInfo: 127.0.0.1:25 TCP
      (localhost:smtp)>
  • */
    +static VALUE
    +addrinfo_s_tcp(VALUE self, VALUE host, VALUE port)
    +{
  • return addrinfo_firstonly_new(host, port,
  •        INT2NUM(PF_UNSPEC), INT2NUM(SOCK_STREAM), 
    

INT2FIX(IPPROTO_TCP), INT2FIX(0));
+}
+
+/*

    • call-seq:
    • AddrInfo.udp(host, port) => addrinfo
    • returns an addrinfo object for UDP address.
    • AddrInfo.udp(“localhost”, “daytime”) #=> #<AddrInfo: 127.0.0.1:13
      UDP (localhost:daytime)>
  • */
    +static VALUE
    +addrinfo_s_udp(VALUE self, VALUE host, VALUE port)
    +{
  • return addrinfo_firstonly_new(host, port,
  •        INT2NUM(PF_UNSPEC), INT2NUM(SOCK_DGRAM), 
    

INT2FIX(IPPROTO_UDP), INT2FIX(0));
+}
+
+#ifdef HAVE_SYS_UN_H
+
+/*

    • call-seq:
    • AddrInfo.udp(host, port) => addrinfo
    • returns an addrinfo object for UNIX socket address.
    • AddrInfo.unix(“/tmp/sock”) #=> #<AddrInfo: /tmp/sock SOCK_STREAM>
  • */
    +static VALUE
    +addrinfo_s_unix(VALUE self, VALUE path)
    +{
  • VALUE addr;
  • rb_addrinfo_t *rai;
  • addr = addrinfo_s_allocate(rb_cAddrInfo);
  • DATA_PTR(addr) = rai = alloc_addrinfo();
  • init_unix_addrinfo(rai, path);
  • OBJ_INFECT(addr, path);
  • return addr;
    +}

+#endif
+
static void
sock_define_const(const char *name, int value, VALUE mConst)
{
@@ -3578,6 +4519,8 @@ Init_socket()
rb_define_method(rb_cBasicSocket, “getsockopt”, bsock_getsockopt,
2);
rb_define_method(rb_cBasicSocket, “getsockname”, bsock_getsockname,
0);
rb_define_method(rb_cBasicSocket, “getpeername”, bsock_getpeername,
0);

  • rb_define_method(rb_cBasicSocket, “local_address”,
    bsock_local_address, 0);

  • rb_define_method(rb_cBasicSocket, “remote_address”,
    bsock_remote_address, 0);
    rb_define_method(rb_cBasicSocket, “send”, bsock_send, -1);
    rb_define_method(rb_cBasicSocket, “recv”, bsock_recv, -1);
    rb_define_method(rb_cBasicSocket, “recv_nonblock”,
    bsock_recv_nonblock, -1);
    @@ -3668,6 +4611,33 @@ Init_socket()
    rb_define_singleton_method(rb_cSocket, “unpack_sockaddr_un”,
    sock_s_unpack_sockaddr_un, 1);
    #endif

  • rb_cAddrInfo = rb_define_class(“AddrInfo”, rb_cData);

  • rb_define_alloc_func(rb_cAddrInfo, addrinfo_s_allocate);

  • rb_define_method(rb_cAddrInfo, “initialize”, addrinfo_initialize,
    -1);

  • rb_define_method(rb_cAddrInfo, “inspect”, addrinfo_inspect, 0);

  • rb_define_singleton_method(rb_cAddrInfo, “getaddrinfo”,
    addrinfo_s_getaddrinfo, -1);

  • rb_define_singleton_method(rb_cAddrInfo, “tcp”, addrinfo_s_tcp, 2);

  • rb_define_singleton_method(rb_cAddrInfo, “udp”, addrinfo_s_udp, 2);
    +#ifdef HAVE_SYS_UN_H

  • rb_define_singleton_method(rb_cAddrInfo, “unix”, addrinfo_s_unix,
    1);
    +#endif

  • rb_define_method(rb_cAddrInfo, “afamily”, addrinfo_afamily, 0);

  • rb_define_method(rb_cAddrInfo, “pfamily”, addrinfo_pfamily, 0);

  • rb_define_method(rb_cAddrInfo, “socktype”, addrinfo_socktype, 0);

  • rb_define_method(rb_cAddrInfo, “protocol”, addrinfo_protocol, 0);

  • rb_define_method(rb_cAddrInfo, “canonname”, addrinfo_canonname, 0);

  • rb_define_method(rb_cAddrInfo, “inet?”, addrinfo_inet_p, 0);

  • rb_define_method(rb_cAddrInfo, “ipv4?”, addrinfo_ipv4_p, 0);

  • rb_define_method(rb_cAddrInfo, “ipv6?”, addrinfo_ipv6_p, 0);

  • rb_define_method(rb_cAddrInfo, “unix?”, addrinfo_unix_p, 0);

  • rb_define_method(rb_cAddrInfo, “to_sockaddr”, addrinfo_to_sockaddr,
    0);

  • rb_define_method(rb_cAddrInfo, “to_str”, addrinfo_to_sockaddr, 0);
    /* for compatibility */

  • rb_define_method(rb_cAddrInfo, “getnameinfo”, addrinfo_getnameinfo,
    -1);

  • /* constants */
    mConst = rb_define_module_under(rb_cSocket, “Constants”);
    init_constants(mConst);
    Index: ext/socket/mkconstants.rb
    ===================================================================
    — ext/socket/mkconstants.rb (revision 21278)
    +++ ext/socket/mkconstants.rb (working copy)
    @@ -172,6 +172,9 @@ def def_intern(func_name, pat, prefix_op
    end

def_intern(‘intern_family’, /\AAF_/)
+def_intern(‘intern_protocol_family’, /\APF_/)
+def_intern(‘intern_socktype’, /\ASOCK_/)
+def_intern(‘intern_ipproto’, /\AIPPROTO_/)

result << ERB.new(<<‘EOS’, nil, ‘%’).result(binding)

Index: test/socket/test_socket.rb

— test/socket/test_socket.rb (revision 21278)
+++ test/socket/test_socket.rb (working copy)
@@ -102,7 +102,7 @@ class TestSocket < Test::Unit::TestCase
c = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
c.connect(serv.getsockname)
fd, peeraddr = serv.sysaccept

  • assert_equal(c.getsockname, peeraddr)
  • assert_equal(c.getsockname, peeraddr.to_sockaddr)
    ensure
    serv.close if serv
    c.close if c