[前][次][番号順一覧][スレッド一覧]

ruby-changes:10067

From: akr <ko1@a...>
Date: Fri, 16 Jan 2009 22:32:08 +0900 (JST)
Subject: [ruby-changes:10067] Ruby:r21610 (trunk): * ext/socket/socket.c: move addrinfo code.

akr	2009-01-16 22:31:49 +0900 (Fri, 16 Jan 2009)

  New Revision: 21610

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=21610

  Log:
    * ext/socket/socket.c: move addrinfo code.

  Modified files:
    trunk/ChangeLog
    trunk/ext/socket/socket.c

Index: ChangeLog
===================================================================
--- ChangeLog	(revision 21609)
+++ ChangeLog	(revision 21610)
@@ -1,3 +1,7 @@
+Fri Jan 16 22:30:27 2009  Tanaka Akira  <akr@f...>
+
+	* ext/socket/socket.c: move addrinfo code.
+
 Fri Jan 16 18:51:11 2009  NAKAMURA Usaku  <usa@r...>
 
 	* win32/Makefile.sub (up): tell nmake that need to run command via
Index: ext/socket/socket.c
===================================================================
--- ext/socket/socket.c	(revision 21609)
+++ ext/socket/socket.c	(revision 21610)
@@ -139,6 +139,8 @@
 #undef sock_define_const
 #undef sock_define_uconst
 
+NORETURN(static void raise_socket_error(const char *, int));
+
 #if defined(INET6) && (defined(LOOKUP_ORDER_HACK_INET) || defined(LOOKUP_ORDER_HACK_INET6))
 #define LOOKUP_ORDERS (sizeof(lookup_order_table) / sizeof(lookup_order_table[0]))
 static const int lookup_order_table[] = {
@@ -394,7 +396,1035 @@
     return constant_arg(how, shutdown_how_to_int, "unknown shutdown argument");
 }
 
+typedef struct {
+    VALUE inspectname;
+    VALUE canonname;
+    int pfamily;
+    int socktype;
+    int protocol;
+    size_t sockaddr_len;
+    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 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, RUBY_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->sockaddr_len = 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* sock_getaddrinfo(VALUE host, VALUE port, struct addrinfo *hints, int socktype_hack);
+
+static struct addrinfo *
+call_getaddrinfo(VALUE node, VALUE service,
+                 VALUE family, VALUE socktype, VALUE protocol, VALUE flags,
+                 int socktype_hack)
+{
+    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, socktype_hack);
+
+    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, 1);
+    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, 0);
+
+    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, 0);
+
+    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 void
+init_unix_addrinfo(rb_addrinfo_t *rai, VALUE path)
+{
+    struct sockaddr_un un;
+
+    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);
+}
+#endif
+
+/*
+ * call-seq:
+ *   AddrInfo.new(sockaddr)                             => addrinfo
+ *   AddrInfo.new(sockaddr, family)                     => addrinfo
+ *   AddrInfo.new(sockaddr, family, socktype)           => addrinfo
+ *   AddrInfo.new(sockaddr, family, socktype, protocol) => addrinfo
+ *
+ * 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_in(80, "www.ruby-lang.org")
+ * - 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);
+            int flags;
+
+            service = INT2NUM(NUM2INT(service));
+            if (!NIL_P(nodename))
+                StringValue(nodename);
+            StringValue(numericnode);
+            flags = AI_NUMERICHOST;
+#ifdef AI_NUMERICSERV
+            flags |= AI_NUMERICSERV;
+#endif
+
+            init_addrinfo_getaddrinfo(rai, numericnode, service,
+                    INT2NUM(i_pfamily ? i_pfamily : af), INT2NUM(i_socktype), INT2NUM(i_protocol),
+                    INT2NUM(flags),
+                    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;
+}
+
+static int
+get_afamily(struct sockaddr *addr, socklen_t len)
+{
+    if ((char*)&addr->sa_family + sizeof(addr->sa_family) - (char*)addr <= len)
+        return addr->sa_family;
+    else
+        return AF_UNSPEC;
+}
+
+static int
+ai_get_afamily(rb_addrinfo_t *rai)
+{
+    return get_afamily((struct sockaddr *)&rai->addr, rai->sockaddr_len);
+}
+
+/*
+ * call-seq:
+ *   addrinfo.inspect => string
+ *
+ * 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));
+
+    if (rai->sockaddr_len == 0) {
+        rb_str_cat2(ret, "empty-sockaddr");
+    }
+    else if (rai->sockaddr_len < ((char*)&rai->addr.ss_family + sizeof(rai->addr.ss_family)) - (char*)&rai->addr)
+        rb_str_cat2(ret, "too-short-sockaddr");
+    else {
+        switch (rai->addr.ss_family) {
+          case AF_INET:
+          {
+            struct sockaddr_in *addr;
+            int port;
+            if (rai->sockaddr_len < sizeof(struct sockaddr_in)) {
+                rb_str_cat2(ret, "too-short-AF_INET-sockaddr");
+            }
+            else {
+                addr = (struct sockaddr_in *)&rai->addr;
+                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);
+                if (sizeof(struct sockaddr_in) < rai->sockaddr_len)
+                    rb_str_catf(ret, "(sockaddr %d bytes too long)", (int)(rai->sockaddr_len - sizeof(struct sockaddr_in)));
+            }
+            break;
+          }
+
+#ifdef INET6
+          case AF_INET6:
+          {
+            struct sockaddr_in6 *addr;
+            char hbuf[1024];
+            int port;
+            int error;
+            if (rai->sockaddr_len < sizeof(struct sockaddr_in6)) {
+                rb_str_cat2(ret, "too-short-AF_INET6-sockaddr");
+            }
+            else {
+                addr = (struct sockaddr_in6 *)&rai->addr;
+                /* 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, rai->sockaddr_len,
+                                    hbuf, sizeof(hbuf), NULL, 0,
+                                    NI_NUMERICHOST|NI_NUMERICSERV);
+                if (error) {
+                    raise_socket_error("getnameinfo", error);
+                }
+                if (addr->sin6_port == 0) {
+                    rb_str_cat2(ret, hbuf);
+                }
+                else {
+                    port = ntohs(addr->sin6_port);
+                    rb_str_catf(ret, "[%s]:%d", hbuf, port);
+                }
+                if (sizeof(struct sockaddr_in6) < rai->sockaddr_len)
+                    rb_str_catf(ret, "(sockaddr %d bytes too long)", (int)(rai->sockaddr_len - sizeof(struct sockaddr_in6)));
+            }
+            break;
+          }
+#endif
+
+#ifdef HAVE_SYS_UN_H
+          case AF_UNIX:
+          {
+            struct sockaddr_un *addr = (struct sockaddr_un *)&rai->addr;
+            char *p, *s, *t, *e;
+            s = addr->sun_path;
+            e = (char*)addr + rai->sockaddr_len;
+            if (e < s)
+                rb_str_cat2(ret, "too-short-AF_UNIX-sockaddr");
+            else if (s == e)
+                rb_str_cat2(ret, "empty-path-AF_UNIX-sockaddr");
+            else {
+                int printable_only = 1;
+                p = s;
+                while (p < e && *p != '\0') {
+                    printable_only = printable_only && ISPRINT(*p) && !ISSPACE(*p);
+                    p++;
+                }
+                t = p;
+                while (p < e && *p == '\0')
+                    p++;
+                if (printable_only && /* only printable, no space */
+                    t < e && /* NUL terminated */
+                    p == e) { /* no data after NUL */
+		    if (s == t)
+			rb_str_cat2(ret, "empty-path-AF_UNIX-sockaddr");
+		    else if (s[0] == '/') /* absolute path */
+			rb_str_cat2(ret, s);
+		    else
+                        rb_str_catf(ret, "AF_UNIX %s", s);
+                }
+                else {
+                    rb_str_cat2(ret, "AF_UNIX");
+                    e = (char *)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++);
+                }
+                if (addr->sun_path + sizeof(addr->sun_path) < (char*)&rai->addr + rai->sockaddr_len)
+                    rb_str_catf(ret, "(sockaddr %d bytes too long)",
+                            (int)(rai->sockaddr_len - (addr->sun_path + sizeof(addr->sun_path) - (char*)&rai->addr)));
+            }
+            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 && ai_get_afamily(rai) != 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 => integer
+ *
+ * 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(ai_get_afamily(rai));
+}
+
+/*
+ * call-seq:
+ *   addrinfo.pfamily => integer
+ *
+ * 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 => integer
+ *
+ * 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 => integer
+ *
+ * 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 => string
+ *
+ * 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, rai->sockaddr_len);
+    OBJ_INFECT(ret, self);
+    return ret;
+}
+
+/*
+ * call-seq:
+ *   addrinfo.canonname => string or nil
+ *
+ * returns the canonical name as an string.
+ *
+ * nil is returned if no canonical name.
+ *
+ * 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)
+ *   p list[0] #=> #<AddrInfo: 221.186.184.68:80 TCP carbon.ruby-lang.org (www.ruby-lang.org:80)>
+ *   p list[0].canonname #=> "carbon.ruby-lang.org"
+ *
+ */
+static VALUE
+addrinfo_canonname(VALUE self)
+{
+    rb_addrinfo_t *rai = get_addrinfo(self);
+    return rai->canonname;
+}
+
+#ifdef AF_INET6
+# define IS_IP_FAMILY(af) ((af) == AF_INET || (af) == AF_INET6)
+#else
+# define IS_IP_FAMILY(af) ((af) == AF_INET)
+#endif
+
+/*
+ * call-seq:
+ *   addrinfo.ip? => true or false
+ *
+ * returns true if addrinfo is internet (IPv4/IPv6) address.
+ * returns false otherwise.
+ *
+ *   AddrInfo.tcp("127.0.0.1", 80).ip? #=> true
+ *   AddrInfo.tcp("::1", 80).ip?       #=> true
+ *   AddrInfo.unix("/tmp/sock").ip?    #=> false
+ *
+ */
+static VALUE
+addrinfo_ip_p(VALUE self)
+{
+    rb_addrinfo_t *rai = get_addrinfo(self);
+    int family = ai_get_afamily(rai);
+    return IS_IP_FAMILY(family) ? Qtrue : Qfalse;
+}
+
+/*
+ * call-seq:
+ *   addrinfo.ipv4? => true or false
+ *
+ * returns true if addrinfo is IPv4 address.
+ * returns false otherwise.
+ *
+ *   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 ai_get_afamily(rai) == AF_INET ? Qtrue : Qfalse;
+}
+
+/*
+ * call-seq:
+ *   addrinfo.ipv6? => true or false
+ *
+ * returns true if addrinfo is IPv6 address.
+ * returns false otherwise.
+ *
+ *   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)
+{
+#ifdef AF_INET6
+    rb_addrinfo_t *rai = get_addrinfo(self);
+    return ai_get_afamily(rai) == AF_INET6 ? Qtrue : Qfalse;
+#else
+    return Qfalse;
+#endif
+}
+
+/*
+ * call-seq:
+ *   addrinfo.unix? => true or false
+ *
+ * returns true if addrinfo is UNIX address.
+ * returns false otherwise.
+ *
+ *   AddrInfo.tcp("127.0.0.1", 80).unix? #=> false
+ *   AddrInfo.tcp("::1", 80).unix?       #=> false
+ *   AddrInfo.unix("/tmp/sock").unix?    #=> true
+ *
+ */
+static VALUE
+addrinfo_unix_p(VALUE self)
+{
+    rb_addrinfo_t *rai = get_addrinfo(self);
+#ifdef AF_UNIX
+    return ai_get_afamily(rai) == 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);
+
+    if (rai->socktype == SOCK_DGRAM)
+        flags |= NI_DGRAM;
+
+    error = getnameinfo((struct sockaddr *)&rai->addr, rai->sockaddr_len,
+                        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.ip_unpack => [addr, port]
+ *
+ * Returns the IP address and port number as 2-element array.
+ *
+ *   AddrInfo.tcp("127.0.0.1", 80).ip_unpack    #=> ["127.0.0.1", 80]
+ *   AddrInfo.tcp("::1", 80).ip_unpack          #=> ["::1", 80]
+ */
+static VALUE
+addrinfo_ip_unpack(VALUE self)
+{
+    rb_addrinfo_t *rai = get_addrinfo(self);
+    int family = ai_get_afamily(rai);
+    VALUE vflags;
+    VALUE ret, portstr;
+
+    if (!IS_IP_FAMILY(family))
+	rb_raise(rb_eSocket, "need IPv4 or IPv6 address");
+
+    vflags = INT2NUM(NI_NUMERICHOST|NI_NUMERICSERV);
+    ret = addrinfo_getnameinfo(1, &vflags, self);
+    portstr = rb_ary_entry(ret, 1);
+    rb_ary_store(ret, 1, INT2NUM(atoi(StringValueCStr(portstr))));
+    return ret;
+}
+
+#ifdef HAVE_SYS_UN_H
+/*
+ * call-seq:
+ *   addrinfo.unix_path => path
+ *
+ * Returns the socket path as a string.
+ *
+ *   AddrInfo.unix("/tmp/sock").unix_path       #=> "/tmp/sock"
+ */
+static VALUE
+addrinfo_unix_path(VALUE self)
+{
+    rb_addrinfo_t *rai = get_addrinfo(self);
+    int family = ai_get_afamily(rai);
+    struct sockaddr_un *addr;
+    char *s, *e;
+
+    if (family != AF_UNIX)
+	rb_raise(rb_eSocket, "need AF_UNIX address");
+
+    addr = (struct sockaddr_un *)&rai->addr;
+
+    s = addr->sun_path;
+    e = (char*)addr + rai->sockaddr_len;
+    if (e < s)
+        rb_raise(rb_eSocket, "too short AF_UNIX address");
+    if (addr->sun_path + sizeof(addr->sun_path) < e)
+        rb_raise(rb_eSocket, "too long AF_UNIX address");
+    while (s < e && *(e-1) == '\0')
+        e--;
+    return rb_str_new(s, e-s);
+}
+#endif
+
+/*
+ * 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: 203.178.141.194:80 TCP (www.kame.net:80)>,
+ *   #    #<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.ip(host) => addrinfo
+ *
+ * returns an addrinfo object for IP address.
+ *
+ *   AddrInfo.ip("localhost") #=> #<AddrInfo: 127.0.0.1 (localhost)>
+ */
+static VALUE
+addrinfo_s_ip(VALUE self, VALUE host)
+{
+    VALUE ret;
+    rb_addrinfo_t *rai;
+    ret = addrinfo_firstonly_new(host, Qnil,
+            INT2NUM(PF_UNSPEC), INT2FIX(0), INT2FIX(0), INT2FIX(0));
+    rai = get_addrinfo(ret);
+    rai->socktype = 0;
+    rai->protocol = 0;
+    return ret;
+}
+
+/*
+ * 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), INT2NUM(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), INT2NUM(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 VALUE
+sockaddr_string_value(volatile VALUE *v)
+{
+    VALUE val = *v;
+    if (TYPE(val) == RUBY_T_DATA && IS_ADDRINFO(val)) {
+        *v = addrinfo_to_sockaddr(val);
+    }
+    StringValue(*v);
+    return *v;
+}
+
+static char *
+sockaddr_string_value_ptr(volatile VALUE *v)
+{
+    sockaddr_string_value(v);
+    return RSTRING_PTR(*v);
+}
+
+
+static VALUE
 init_sock(VALUE sock, int fd)
 {
     rb_io_t *fp;
@@ -748,15 +1778,6 @@
 
 static VALUE addrinfo_new(struct sockaddr *, socklen_t, int, int, int, VALUE, VALUE);
 
-static int
-get_afamily(struct sockaddr *addr, socklen_t len)
-{
-    if ((char*)&addr->sa_family + sizeof(addr->sa_family) - (char*)addr <= len)
-        return addr->sa_family;
-    else
-        return AF_UNSPEC;
-}
-
 static VALUE
 fd_socket_addrinfo(int fd, struct sockaddr *addr, socklen_t len)
 {
@@ -1245,7 +2266,6 @@
     return val;
 }
 
-NORETURN(static void raise_socket_error(const char *, int));
 static void
 raise_socket_error(const char *reason, int error)
 {
@@ -4438,1023 +5458,7 @@
 }
 #endif
 
-typedef struct {
-    VALUE inspectname;
-    VALUE canonname;
-    int pfamily;
-    int socktype;
-    int protocol;
-    size_t sockaddr_len;
-    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 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, RUBY_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->sockaddr_len = 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,
-                 int socktype_hack)
-{
-    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, socktype_hack);
-
-    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, 1);
-    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, 0);
-
-    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, 0);
-
-    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 void
-init_unix_addrinfo(rb_addrinfo_t *rai, VALUE path)
-{
-    struct sockaddr_un un;
-
-    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);
-}
-#endif
-
-/*
- * call-seq:
- *   AddrInfo.new(sockaddr)                             => addrinfo
- *   AddrInfo.new(sockaddr, family)                     => addrinfo
- *   AddrInfo.new(sockaddr, family, socktype)           => addrinfo
- *   AddrInfo.new(sockaddr, family, socktype, protocol) => addrinfo
- *
- * 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_in(80, "www.ruby-lang.org")
- * - 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);
-            int flags;
-
-            service = INT2NUM(NUM2INT(service));
-            if (!NIL_P(nodename))
-                StringValue(nodename);
-            StringValue(numericnode);
-            flags = AI_NUMERICHOST;
-#ifdef AI_NUMERICSERV
-            flags |= AI_NUMERICSERV;
-#endif
-
-            init_addrinfo_getaddrinfo(rai, numericnode, service,
-                    INT2NUM(i_pfamily ? i_pfamily : af), INT2NUM(i_socktype), INT2NUM(i_protocol),
-                    INT2NUM(flags),
-                    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;
-}
-
-static int
-ai_get_afamily(rb_addrinfo_t *rai)
-{
-    return get_afamily((struct sockaddr *)&rai->addr, rai->sockaddr_len);
-}
-
-/*
- * call-seq:
- *   addrinfo.inspect => string
- *
- * 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));
-
-    if (rai->sockaddr_len == 0) {
-        rb_str_cat2(ret, "empty-sockaddr");
-    }
-    else if (rai->sockaddr_len < ((char*)&rai->addr.ss_family + sizeof(rai->addr.ss_family)) - (char*)&rai->addr)
-        rb_str_cat2(ret, "too-short-sockaddr");
-    else {
-        switch (rai->addr.ss_family) {
-          case AF_INET:
-          {
-            struct sockaddr_in *addr;
-            int port;
-            if (rai->sockaddr_len < sizeof(struct sockaddr_in)) {
-                rb_str_cat2(ret, "too-short-AF_INET-sockaddr");
-            }
-            else {
-                addr = (struct sockaddr_in *)&rai->addr;
-                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);
-                if (sizeof(struct sockaddr_in) < rai->sockaddr_len)
-                    rb_str_catf(ret, "(sockaddr %d bytes too long)", (int)(rai->sockaddr_len - sizeof(struct sockaddr_in)));
-            }
-            break;
-          }
-
-#ifdef INET6
-          case AF_INET6:
-          {
-            struct sockaddr_in6 *addr;
-            char hbuf[1024];
-            int port;
-            int error;
-            if (rai->sockaddr_len < sizeof(struct sockaddr_in6)) {
-                rb_str_cat2(ret, "too-short-AF_INET6-sockaddr");
-            }
-            else {
-                addr = (struct sockaddr_in6 *)&rai->addr;
-                /* 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, rai->sockaddr_len,
-                                    hbuf, sizeof(hbuf), NULL, 0,
-                                    NI_NUMERICHOST|NI_NUMERICSERV);
-                if (error) {
-                    raise_socket_error("getnameinfo", error);
-                }
-                if (addr->sin6_port == 0) {
-                    rb_str_cat2(ret, hbuf);
-                }
-                else {
-                    port = ntohs(addr->sin6_port);
-                    rb_str_catf(ret, "[%s]:%d", hbuf, port);
-                }
-                if (sizeof(struct sockaddr_in6) < rai->sockaddr_len)
-                    rb_str_catf(ret, "(sockaddr %d bytes too long)", (int)(rai->sockaddr_len - sizeof(struct sockaddr_in6)));
-            }
-            break;
-          }
-#endif
-
-#ifdef HAVE_SYS_UN_H
-          case AF_UNIX:
-          {
-            struct sockaddr_un *addr = (struct sockaddr_un *)&rai->addr;
-            char *p, *s, *t, *e;
-            s = addr->sun_path;
-            e = (char*)addr + rai->sockaddr_len;
-            if (e < s)
-                rb_str_cat2(ret, "too-short-AF_UNIX-sockaddr");
-            else if (s == e)
-                rb_str_cat2(ret, "empty-path-AF_UNIX-sockaddr");
-            else {
-                int printable_only = 1;
-                p = s;
-                while (p < e && *p != '\0') {
-                    printable_only = printable_only && ISPRINT(*p) && !ISSPACE(*p);
-                    p++;
-                }
-                t = p;
-                while (p < e && *p == '\0')
-                    p++;
-                if (printable_only && /* only printable, no space */
-                    t < e && /* NUL terminated */
-                    p == e) { /* no data after NUL */
-		    if (s == t)
-			rb_str_cat2(ret, "empty-path-AF_UNIX-sockaddr");
-		    else if (s[0] == '/') /* absolute path */
-			rb_str_cat2(ret, s);
-		    else
-                        rb_str_catf(ret, "AF_UNIX %s", s);
-                }
-                else {
-                    rb_str_cat2(ret, "AF_UNIX");
-                    e = (char *)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++);
-                }
-                if (addr->sun_path + sizeof(addr->sun_path) < (char*)&rai->addr + rai->sockaddr_len)
-                    rb_str_catf(ret, "(sockaddr %d bytes too long)",
-                            (int)(rai->sockaddr_len - (addr->sun_path + sizeof(addr->sun_path) - (char*)&rai->addr)));
-            }
-            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 && ai_get_afamily(rai) != 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 => integer
- *
- * 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(ai_get_afamily(rai));
-}
-
-/*
- * call-seq:
- *   addrinfo.pfamily => integer
- *
- * 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 => integer
- *
- * 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 => integer
- *
- * 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 => string
- *
- * 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, rai->sockaddr_len);
-    OBJ_INFECT(ret, self);
-    return ret;
-}
-
-/*
- * call-seq:
- *   addrinfo.canonname => string or nil
- *
- * returns the canonical name as an string.
- *
- * nil is returned if no canonical name.
- *
- * 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)
- *   p list[0] #=> #<AddrInfo: 221.186.184.68:80 TCP carbon.ruby-lang.org (www.ruby-lang.org:80)>
- *   p list[0].canonname #=> "carbon.ruby-lang.org"
- *
- */
-static VALUE
-addrinfo_canonname(VALUE self)
-{
-    rb_addrinfo_t *rai = get_addrinfo(self);
-    return rai->canonname;
-}
-
-#ifdef AF_INET6
-# define IS_IP_FAMILY(af) ((af) == AF_INET || (af) == AF_INET6)
-#else
-# define IS_IP_FAMILY(af) ((af) == AF_INET)
-#endif
-
-/*
- * call-seq:
- *   addrinfo.ip? => true or false
- *
- * returns true if addrinfo is internet (IPv4/IPv6) address.
- * returns false otherwise.
- *
- *   AddrInfo.tcp("127.0.0.1", 80).ip? #=> true
- *   AddrInfo.tcp("::1", 80).ip?       #=> true
- *   AddrInfo.unix("/tmp/sock").ip?    #=> false
- *
- */
-static VALUE
-addrinfo_ip_p(VALUE self)
-{
-    rb_addrinfo_t *rai = get_addrinfo(self);
-    int family = ai_get_afamily(rai);
-    return IS_IP_FAMILY(family) ? Qtrue : Qfalse;
-}
-
-/*
- * call-seq:
- *   addrinfo.ipv4? => true or false
- *
- * returns true if addrinfo is IPv4 address.
- * returns false otherwise.
- *
- *   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 ai_get_afamily(rai) == AF_INET ? Qtrue : Qfalse;
-}
-
-/*
- * call-seq:
- *   addrinfo.ipv6? => true or false
- *
- * returns true if addrinfo is IPv6 address.
- * returns false otherwise.
- *
- *   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)
-{
-#ifdef AF_INET6
-    rb_addrinfo_t *rai = get_addrinfo(self);
-    return ai_get_afamily(rai) == AF_INET6 ? Qtrue : Qfalse;
-#else
-    return Qfalse;
-#endif
-}
-
-/*
- * call-seq:
- *   addrinfo.unix? => true or false
- *
- * returns true if addrinfo is UNIX address.
- * returns false otherwise.
- *
- *   AddrInfo.tcp("127.0.0.1", 80).unix? #=> false
- *   AddrInfo.tcp("::1", 80).unix?       #=> false
- *   AddrInfo.unix("/tmp/sock").unix?    #=> true
- *
- */
-static VALUE
-addrinfo_unix_p(VALUE self)
-{
-    rb_addrinfo_t *rai = get_addrinfo(self);
-#ifdef AF_UNIX
-    return ai_get_afamily(rai) == 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);
-
-    if (rai->socktype == SOCK_DGRAM)
-        flags |= NI_DGRAM;
-
-    error = getnameinfo((struct sockaddr *)&rai->addr, rai->sockaddr_len,
-                        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.ip_unpack => [addr, port]
- *
- * Returns the IP address and port number as 2-element array.
- *
- *   AddrInfo.tcp("127.0.0.1", 80).ip_unpack    #=> ["127.0.0.1", 80]
- *   AddrInfo.tcp("::1", 80).ip_unpack          #=> ["::1", 80]
- */
-static VALUE
-addrinfo_ip_unpack(VALUE self)
-{
-    rb_addrinfo_t *rai = get_addrinfo(self);
-    int family = ai_get_afamily(rai);
-    VALUE vflags;
-    VALUE ret, portstr;
-
-    if (!IS_IP_FAMILY(family))
-	rb_raise(rb_eSocket, "need IPv4 or IPv6 address");
-
-    vflags = INT2NUM(NI_NUMERICHOST|NI_NUMERICSERV);
-    ret = addrinfo_getnameinfo(1, &vflags, self);
-    portstr = rb_ary_entry(ret, 1);
-    rb_ary_store(ret, 1, INT2NUM(atoi(StringValueCStr(portstr))));
-    return ret;
-}
-
-#ifdef HAVE_SYS_UN_H
-/*
- * call-seq:
- *   addrinfo.unix_path => path
- *
- * Returns the socket path as a string.
- *
- *   AddrInfo.unix("/tmp/sock").unix_path       #=> "/tmp/sock"
- */
-static VALUE
-addrinfo_unix_path(VALUE self)
-{
-    rb_addrinfo_t *rai = get_addrinfo(self);
-    int family = ai_get_afamily(rai);
-    struct sockaddr_un *addr;
-    char *s, *e;
-
-    if (family != AF_UNIX)
-	rb_raise(rb_eSocket, "need AF_UNIX address");
-
-    addr = (struct sockaddr_un *)&rai->addr;
-
-    s = addr->sun_path;
-    e = (char*)addr + rai->sockaddr_len;
-    if (e < s)
-        rb_raise(rb_eSocket, "too short AF_UNIX address");
-    if (addr->sun_path + sizeof(addr->sun_path) < e)
-        rb_raise(rb_eSocket, "too long AF_UNIX address");
-    while (s < e && *(e-1) == '\0')
-        e--;
-    return rb_str_new(s, e-s);
-}
-#endif
-
-/*
- * 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: 203.178.141.194:80 TCP (www.kame.net:80)>,
- *   #    #<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.ip(host) => addrinfo
- *
- * returns an addrinfo object for IP address.
- *
- *   AddrInfo.ip("localhost") #=> #<AddrInfo: 127.0.0.1 (localhost)>
- */
-static VALUE
-addrinfo_s_ip(VALUE self, VALUE host)
-{
-    VALUE ret;
-    rb_addrinfo_t *rai;
-    ret = addrinfo_firstonly_new(host, Qnil,
-            INT2NUM(PF_UNSPEC), INT2FIX(0), INT2FIX(0), INT2FIX(0));
-    rai = get_addrinfo(ret);
-    rai->socktype = 0;
-    rai->protocol = 0;
-    return ret;
-}
-
-/*
- * 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), INT2NUM(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), INT2NUM(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 VALUE
-sockaddr_string_value(volatile VALUE *v)
-{
-    VALUE val = *v;
-    if (TYPE(val) == RUBY_T_DATA && IS_ADDRINFO(val)) {
-        *v = addrinfo_to_sockaddr(val);
-    }
-    StringValue(*v);
-    return *v;
-}
-
-static char *
-sockaddr_string_value_ptr(volatile VALUE *v)
-{
-    sockaddr_string_value(v);
-    return RSTRING_PTR(*v);
-}
-
-static void
 sock_define_const(const char *name, int value, VALUE mConst)
 {
     rb_define_const(rb_cSocket, name, INT2NUM(value));

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]