Ruby 1.9.2p136(2010-12-25revision30365)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

# ext/socket/raddrinfo.c

Go to the documentation of this file.

    00001 /************************************************
    00002
    00003   ainfo.c -
    00004
    00005   created at: Thu Mar 31 12:21:29 JST 1994
    00006
    00007   Copyright (C) 1993-2007 Yukihiro Matsumoto
    00008
    00009 ************************************************/
    00010
    00011 #include "rubysocket.h"
    00012
    00013 #if defined(INET6) && (defined(LOOKUP_ORDER_HACK_INET) || defined(LOOKUP_ORDER_HACK_INET6))
    00014 #define LOOKUP_ORDERS (sizeof(lookup_order_table) / sizeof(lookup_order_table[0]))
    00015 static const int lookup_order_table[] = {
    00016 #if defined(LOOKUP_ORDER_HACK_INET)
    00017     PF_INET, PF_INET6, PF_UNSPEC,
    00018 #elif defined(LOOKUP_ORDER_HACK_INET6)
    00019     PF_INET6, PF_INET, PF_UNSPEC,
    00020 #else
    00021     /* should not happen */
    00022 #endif
    00023 };
    00024
    00025 static int
    00026 ruby_getaddrinfo(const char *nodename, const char *servname,
    00027                  const struct addrinfo *hints, struct addrinfo **res)
    00028 {
    00029     struct addrinfo tmp_hints;
    00030     int i, af, error;
    00031
    00032     if (hints->ai_family != PF_UNSPEC) {
    00033         return getaddrinfo(nodename, servname, hints, res);
    00034     }
    00035
    00036     for (i = 0; i < LOOKUP_ORDERS; i++) {
    00037         af = lookup_order_table[i];
    00038         MEMCPY(&tmp_hints, hints, struct addrinfo, 1);
    00039         tmp_hints.ai_family = af;
    00040         error = getaddrinfo(nodename, servname, &tmp_hints, res);
    00041         if (error) {
    00042             if (tmp_hints.ai_family == PF_UNSPEC) {
    00043                 break;
    00044             }
    00045         }
    00046         else {
    00047             break;
    00048         }
    00049     }
    00050
    00051     return error;
    00052 }
    00053 #define getaddrinfo(node,serv,hints,res) ruby_getaddrinfo((node),(serv),(hints),(res))
    00054 #endif
    00055
    00056 #if defined(_AIX)
    00057 static int
    00058 ruby_getaddrinfo__aix(const char *nodename, const char *servname,
    00059                       struct addrinfo *hints, struct addrinfo **res)
    00060 {
    00061     int error = getaddrinfo(nodename, servname, hints, res);
    00062     struct addrinfo *r;
    00063     if (error)
    00064         return error;
    00065     for (r = *res; r != NULL; r = r->ai_next) {
    00066         if (r->ai_addr->sa_family == 0)
    00067             r->ai_addr->sa_family = r->ai_family;
    00068         if (r->ai_addr->sa_len == 0)
    00069             r->ai_addr->sa_len = r->ai_addrlen;
    00070     }
    00071     return 0;
    00072 }
    00073 #undef getaddrinfo
    00074 #define getaddrinfo(node,serv,hints,res) ruby_getaddrinfo__aix((node),(serv),(hints),(res))
    00075 static int
    00076 ruby_getnameinfo__aix(const struct sockaddr *sa, size_t salen,
    00077                       char *host, size_t hostlen,
    00078                       char *serv, size_t servlen, int flags)
    00079 {
    00080     struct sockaddr_in6 *sa6;
    00081     u_int32_t *a6;
    00082
    00083     if (sa->sa_family == AF_INET6) {
    00084         sa6 = (struct sockaddr_in6 *)sa;
    00085         a6 = sa6->sin6_addr.u6_addr.u6_addr32;
    00086
    00087         if (a6[0] == 0 && a6[1] == 0 && a6[2] == 0 && a6[3] == 0) {
    00088             strncpy(host, "::", hostlen);
    00089             snprintf(serv, servlen, "%d", sa6->sin6_port);
    00090             return 0;
    00091         }
    00092     }
    00093     return getnameinfo(sa, salen, host, hostlen, serv, servlen, flags);
    00094 }
    00095 #undef getnameinfo
    00096 #define getnameinfo(sa, salen, host, hostlen, serv, servlen, flags) \
    00097             ruby_getnameinfo__aix((sa), (salen), (host), (hostlen), (serv), (servlen), (flags))
    00098 #endif
    00099
    00100 static int str_is_number(const char *);
    00101
    00102 #if defined(__APPLE__)
    00103 /* fix [ruby-core:29427] */
    00104 static int
    00105 ruby_getaddrinfo__darwin(const char *nodename, const char *servname,
    00106                          struct addrinfo *hints, struct addrinfo **res)
    00107 {
    00108     const char *tmp_servname;
    00109     struct addrinfo tmp_hints;
    00110     tmp_servname = servname;
    00111     MEMCPY(&tmp_hints, hints, struct addrinfo, 1);
    00112     if (nodename && servname) {
    00113         if (str_is_number(tmp_servname) && atoi(servname) == 0) {
    00114             tmp_servname = NULL;
    00115 #ifdef AI_NUMERICSERV
    00116             if (tmp_hints.ai_flags) tmp_hints.ai_flags &= ~AI_NUMERICSERV;
    00117 #endif
    00118         }
    00119     }
    00120     int error = getaddrinfo(nodename, tmp_servname, &tmp_hints, res);
    00121     return error;
    00122 }
    00123 #undef getaddrinfo
    00124 #define getaddrinfo(node,serv,hints,res) ruby_getaddrinfo__darwin((node),(serv),(hints),(res))
    00125 #endif
    00126
    00127 #ifndef GETADDRINFO_EMU
    00128 struct getaddrinfo_arg
    00129 {
    00130     const char *node;
    00131     const char *service;
    00132     const struct addrinfo *hints;
    00133     struct addrinfo **res;
    00134 };
    00135
    00136 static VALUE
    00137 nogvl_getaddrinfo(void *arg)
    00138 {
    00139     struct getaddrinfo_arg *ptr = arg;
    00140     return getaddrinfo(ptr->node, ptr->service,
    00141                        ptr->hints, ptr->res);
    00142 }
    00143 #endif
    00144
    00145 int
    00146 rb_getaddrinfo(const char *node, const char *service,
    00147                const struct addrinfo *hints,
    00148                struct addrinfo **res)
    00149 {
    00150 #ifdef GETADDRINFO_EMU
    00151     return getaddrinfo(node, service, hints, res);
    00152 #else
    00153     struct getaddrinfo_arg arg;
    00154     int ret;
    00155     MEMZERO(&arg, sizeof arg, 1);
    00156     arg.node = node;
    00157     arg.service = service;
    00158     arg.hints = hints;
    00159     arg.res = res;
    00160     ret = (int)BLOCKING_REGION(nogvl_getaddrinfo, &arg);
    00161     return ret;
    00162 #endif
    00163 }
    00164
    00165 #ifndef GETADDRINFO_EMU
    00166 struct getnameinfo_arg
    00167 {
    00168     const struct sockaddr *sa;
    00169     socklen_t salen;
    00170     char *host;
    00171     size_t hostlen;
    00172     char *serv;
    00173     size_t servlen;
    00174     int flags;
    00175 };
    00176
    00177 static VALUE
    00178 nogvl_getnameinfo(void *arg)
    00179 {
    00180     struct getnameinfo_arg *ptr = arg;
    00181     return getnameinfo(ptr->sa, ptr->salen,
    00182                        ptr->host, (socklen_t)ptr->hostlen,
    00183                        ptr->serv, (socklen_t)ptr->servlen,
    00184                        ptr->flags);
    00185 }
    00186 #endif
    00187
    00188 int
    00189 rb_getnameinfo(const struct sockaddr *sa, socklen_t salen,
    00190            char *host, size_t hostlen,
    00191            char *serv, size_t servlen, int flags)
    00192 {
    00193 #ifdef GETADDRINFO_EMU
    00194     return getnameinfo(sa, salen, host, hostlen, serv, servlen, flags);
    00195 #else
    00196     struct getnameinfo_arg arg;
    00197     int ret;
    00198     arg.sa = sa;
    00199     arg.salen = salen;
    00200     arg.host = host;
    00201     arg.hostlen = hostlen;
    00202     arg.serv = serv;
    00203     arg.servlen = servlen;
    00204     arg.flags = flags;
    00205     ret = (int)BLOCKING_REGION(nogvl_getnameinfo, &arg);
    00206     return ret;
    00207 #endif
    00208 }
    00209
    00210 static void
    00211 make_ipaddr0(struct sockaddr *addr, char *buf, size_t len)
    00212 {
    00213     int error;
    00214
    00215     error = rb_getnameinfo(addr, SA_LEN(addr), buf, len, NULL, 0, NI_NUMERICHOST);
    00216     if (error) {
    00217         rsock_raise_socket_error("getnameinfo", error);
    00218     }
    00219 }
    00220
    00221 VALUE
    00222 rsock_make_ipaddr(struct sockaddr *addr)
    00223 {
    00224     char hbuf[1024];
    00225
    00226     make_ipaddr0(addr, hbuf, sizeof(hbuf));
    00227     return rb_str_new2(hbuf);
    00228 }
    00229
    00230 static void
    00231 make_inetaddr(unsigned int host, char *buf, size_t len)
    00232 {
    00233     struct sockaddr_in sin;
    00234
    00235     MEMZERO(&sin, struct sockaddr_in, 1);
    00236     sin.sin_family = AF_INET;
    00237     SET_SIN_LEN(&sin, sizeof(sin));
    00238     sin.sin_addr.s_addr = host;
    00239     make_ipaddr0((struct sockaddr*)&sin, buf, len);
    00240 }
    00241
    00242 static int
    00243 str_is_number(const char *p)
    00244 {
    00245     char *ep;
    00246
    00247     if (!p || *p == '\0')
    00248        return 0;
    00249     ep = NULL;
    00250     (void)STRTOUL(p, &ep, 10);
    00251     if (ep && *ep == '\0')
    00252        return 1;
    00253     else
    00254        return 0;
    00255 }
    00256
    00257 static char*
    00258 host_str(VALUE host, char *hbuf, size_t len, int *flags_ptr)
    00259 {
    00260     if (NIL_P(host)) {
    00261         return NULL;
    00262     }
    00263     else if (rb_obj_is_kind_of(host, rb_cInteger)) {
    00264         unsigned int i = NUM2UINT(host);
    00265
    00266         make_inetaddr(htonl(i), hbuf, len);
    00267         if (flags_ptr) *flags_ptr |= AI_NUMERICHOST;
    00268         return hbuf;
    00269     }
    00270     else {
    00271         char *name;
    00272
    00273         SafeStringValue(host);
    00274         name = RSTRING_PTR(host);
    00275         if (!name || *name == 0 || (name[0] == '<' && strcmp(name, "<any>") == 0)) {
    00276             make_inetaddr(INADDR_ANY, hbuf, len);
    00277             if (flags_ptr) *flags_ptr |= AI_NUMERICHOST;
    00278         }
    00279         else if (name[0] == '<' && strcmp(name, "<broadcast>") == 0) {
    00280             make_inetaddr(INADDR_BROADCAST, hbuf, len);
    00281             if (flags_ptr) *flags_ptr |= AI_NUMERICHOST;
    00282         }
    00283         else if (strlen(name) >= len) {
    00284             rb_raise(rb_eArgError, "hostname too long (%"PRIuSIZE")",
    00285                 strlen(name));
    00286         }
    00287         else {
    00288             strcpy(hbuf, name);
    00289         }
    00290         return hbuf;
    00291     }
    00292 }
    00293
    00294 static char*
    00295 port_str(VALUE port, char *pbuf, size_t len, int *flags_ptr)
    00296 {
    00297     if (NIL_P(port)) {
    00298         return 0;
    00299     }
    00300     else if (FIXNUM_P(port)) {
    00301         snprintf(pbuf, len, "%ld", FIX2LONG(port));
    00302 #ifdef AI_NUMERICSERV
    00303         if (flags_ptr) *flags_ptr |= AI_NUMERICSERV;
    00304 #endif
    00305         return pbuf;
    00306     }
    00307     else {
    00308         char *serv;
    00309
    00310         SafeStringValue(port);
    00311         serv = RSTRING_PTR(port);
    00312         if (strlen(serv) >= len) {
    00313             rb_raise(rb_eArgError, "service name too long (%"PRIuSIZE")",
    00314                 strlen(serv));
    00315         }
    00316         strcpy(pbuf, serv);
    00317         return pbuf;
    00318     }
    00319 }
    00320
    00321 struct addrinfo*
    00322 rsock_getaddrinfo(VALUE host, VALUE port, struct addrinfo *hints, int socktype_hack)
    00323 {
    00324     struct addrinfo* res = NULL;
    00325     char *hostp, *portp;
    00326     int error;
    00327     char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
    00328     int additional_flags = 0;
    00329
    00330     hostp = host_str(host, hbuf, sizeof(hbuf), &additional_flags);
    00331     portp = port_str(port, pbuf, sizeof(pbuf), &additional_flags);
    00332
    00333     if (socktype_hack && hints->ai_socktype == 0 && str_is_number(portp)) {
    00334        hints->ai_socktype = SOCK_DGRAM;
    00335     }
    00336     hints->ai_flags |= additional_flags;
    00337
    00338     error = rb_getaddrinfo(hostp, portp, hints, &res);
    00339     if (error) {
    00340         if (hostp && hostp[strlen(hostp)-1] == '\n') {
    00341             rb_raise(rb_eSocket, "newline at the end of hostname");
    00342         }
    00343         rsock_raise_socket_error("getaddrinfo", error);
    00344     }
    00345
    00346 #if defined(__APPLE__) && defined(__MACH__)
    00347     /* [ruby-dev:23164] */
    00348     {
    00349         struct addrinfo *r;
    00350         r = res;
    00351         while (r) {
    00352             if (! r->ai_socktype) r->ai_socktype = hints->ai_socktype;
    00353             if (! r->ai_protocol) {
    00354                 if (r->ai_socktype == SOCK_DGRAM) {
    00355                     r->ai_protocol = IPPROTO_UDP;
    00356                 }
    00357                 else if (r->ai_socktype == SOCK_STREAM) {
    00358                     r->ai_protocol = IPPROTO_TCP;
    00359                 }
    00360             }
    00361             r = r->ai_next;
    00362         }
    00363     }
    00364 #endif
    00365     return res;
    00366 }
    00367
    00368 struct addrinfo*
    00369 rsock_addrinfo(VALUE host, VALUE port, int socktype, int flags)
    00370 {
    00371     struct addrinfo hints;
    00372
    00373     MEMZERO(&hints, struct addrinfo, 1);
    00374     hints.ai_family = AF_UNSPEC;
    00375     hints.ai_socktype = socktype;
    00376     hints.ai_flags = flags;
    00377     return rsock_getaddrinfo(host, port, &hints, 1);
    00378 }
    00379
    00380 VALUE
    00381 rsock_ipaddr(struct sockaddr *sockaddr, int norevlookup)
    00382 {
    00383     VALUE family, port, addr1, addr2;
    00384     VALUE ary;
    00385     int error;
    00386     char hbuf[1024], pbuf[1024];
    00387     ID id;
    00388
    00389     id = rsock_intern_family(sockaddr->sa_family);
    00390     if (id) {
    00391         family = rb_str_dup(rb_id2str(id));
    00392     }
    00393     else {
    00394         sprintf(pbuf, "unknown:%d", sockaddr->sa_family);
    00395         family = rb_str_new2(pbuf);
    00396     }
    00397
    00398     addr1 = Qnil;
    00399     if (!norevlookup) {
    00400         error = rb_getnameinfo(sockaddr, SA_LEN(sockaddr), hbuf, sizeof(hbuf),
    00401                                NULL, 0, 0);
    00402         if (! error) {
    00403             addr1 = rb_str_new2(hbuf);
    00404         }
    00405     }
    00406     error = rb_getnameinfo(sockaddr, SA_LEN(sockaddr), hbuf, sizeof(hbuf),
    00407                            pbuf, sizeof(pbuf), NI_NUMERICHOST | NI_NUMERICSERV);
    00408     if (error) {
    00409         rsock_raise_socket_error("getnameinfo", error);
    00410     }
    00411     addr2 = rb_str_new2(hbuf);
    00412     if (addr1 == Qnil) {
    00413         addr1 = addr2;
    00414     }
    00415     port = INT2FIX(atoi(pbuf));
    00416     ary = rb_ary_new3(4, family, port, addr1, addr2);
    00417
    00418     return ary;
    00419 }
    00420
    00421 #ifdef HAVE_SYS_UN_H
    00422 const char*
    00423 rsock_unixpath(struct sockaddr_un *sockaddr, socklen_t len)
    00424 {
    00425     if (sockaddr->sun_path < (char*)sockaddr + len)
    00426         return sockaddr->sun_path;
    00427     else
    00428         return "";
    00429 }
    00430
    00431 VALUE
    00432 rsock_unixaddr(struct sockaddr_un *sockaddr, socklen_t len)
    00433 {
    00434     return rb_assoc_new(rb_str_new2("AF_UNIX"),
    00435                         rb_str_new2(rsock_unixpath(sockaddr, len)));
    00436 }
    00437 #endif
    00438
    00439 struct hostent_arg {
    00440     VALUE host;
    00441     struct addrinfo* addr;
    00442     VALUE (*ipaddr)(struct sockaddr*, size_t);
    00443 };
    00444
    00445 static VALUE
    00446 make_hostent_internal(struct hostent_arg *arg)
    00447 {
    00448     VALUE host = arg->host;
    00449     struct addrinfo* addr = arg->addr;
    00450     VALUE (*ipaddr)(struct sockaddr*, size_t) = arg->ipaddr;
    00451
    00452     struct addrinfo *ai;
    00453     struct hostent *h;
    00454     VALUE ary, names;
    00455     char **pch;
    00456     const char* hostp;
    00457     char hbuf[NI_MAXHOST];
    00458
    00459     ary = rb_ary_new();
    00460     if (addr->ai_canonname) {
    00461         hostp = addr->ai_canonname;
    00462     }
    00463     else {
    00464         hostp = host_str(host, hbuf, sizeof(hbuf), NULL);
    00465     }
    00466     rb_ary_push(ary, rb_str_new2(hostp));
    00467
    00468     if (addr->ai_canonname && (h = gethostbyname(addr->ai_canonname))) {
    00469         names = rb_ary_new();
    00470         if (h->h_aliases != NULL) {
    00471             for (pch = h->h_aliases; *pch; pch++) {
    00472                 rb_ary_push(names, rb_str_new2(*pch));
    00473             }
    00474         }
    00475     }
    00476     else {
    00477         names = rb_ary_new2(0);
    00478     }
    00479     rb_ary_push(ary, names);
    00480     rb_ary_push(ary, INT2NUM(addr->ai_family));
    00481     for (ai = addr; ai; ai = ai->ai_next) {
    00482         rb_ary_push(ary, (*ipaddr)(ai->ai_addr, ai->ai_addrlen));
    00483     }
    00484
    00485     return ary;
    00486 }
    00487
    00488 VALUE
    00489 rsock_freeaddrinfo(struct addrinfo *addr)
    00490 {
    00491     freeaddrinfo(addr);
    00492     return Qnil;
    00493 }
    00494
    00495 VALUE
    00496 rsock_make_hostent(VALUE host, struct addrinfo *addr, VALUE (*ipaddr)(struct sockaddr *, size_t))
    00497 {
    00498     struct hostent_arg arg;
    00499
    00500     arg.host = host;
    00501     arg.addr = addr;
    00502     arg.ipaddr = ipaddr;
    00503     return rb_ensure(make_hostent_internal, (VALUE)&arg,
    00504                      rsock_freeaddrinfo, (VALUE)addr);
    00505 }
    00506
    00507 typedef struct {
    00508     VALUE inspectname;
    00509     VALUE canonname;
    00510     int pfamily;
    00511     int socktype;
    00512     int protocol;
    00513     socklen_t sockaddr_len;
    00514     struct sockaddr_storage addr;
    00515 } rb_addrinfo_t;
    00516
    00517 static void
    00518 addrinfo_mark(void *ptr)
    00519 {
    00520     rb_addrinfo_t *rai = ptr;
    00521     if (rai) {
    00522         rb_gc_mark(rai->inspectname);
    00523         rb_gc_mark(rai->canonname);
    00524     }
    00525 }
    00526
    00527 #define addrinfo_free RUBY_TYPED_DEFAULT_FREE
    00528
    00529 static size_t
    00530 addrinfo_memsize(const void *ptr)
    00531 {
    00532     return ptr ? sizeof(rb_addrinfo_t) : 0;
    00533 }
    00534
    00535 static const rb_data_type_t addrinfo_type = {
    00536     "socket/addrinfo",
    00537     addrinfo_mark, addrinfo_free, addrinfo_memsize,
    00538 };
    00539
    00540 static VALUE
    00541 addrinfo_s_allocate(VALUE klass)
    00542 {
    00543     return TypedData_Wrap_Struct(klass, &addrinfo_type, 0);
    00544 }
    00545
    00546 #define IS_ADDRINFO(obj) rb_typeddata_is_kind_of(obj, &addrinfo_type)
    00547 static inline rb_addrinfo_t *
    00548 check_addrinfo(VALUE self)
    00549 {
    00550     return rb_check_typeddata(self, &addrinfo_type);
    00551 }
    00552
    00553 static rb_addrinfo_t *
    00554 get_addrinfo(VALUE self)
    00555 {
    00556     rb_addrinfo_t *rai = check_addrinfo(self);
    00557
    00558     if (!rai) {
    00559         rb_raise(rb_eTypeError, "uninitialized socket address");
    00560     }
    00561     return rai;
    00562 }
    00563
    00564
    00565 static rb_addrinfo_t *
    00566 alloc_addrinfo()
    00567 {
    00568     rb_addrinfo_t *rai = ALLOC(rb_addrinfo_t);
    00569     memset(rai, 0, sizeof(rb_addrinfo_t));
    00570     rai->inspectname = Qnil;
    00571     rai->canonname = Qnil;
    00572     return rai;
    00573 }
    00574
    00575 static void
    00576 init_addrinfo(rb_addrinfo_t *rai, struct sockaddr *sa, socklen_t len,
    00577               int pfamily, int socktype, int protocol,
    00578               VALUE canonname, VALUE inspectname)
    00579 {
    00580     if (sizeof(rai->addr) < len)
    00581         rb_raise(rb_eArgError, "sockaddr string too big");
    00582     memcpy((void *)&rai->addr, (void *)sa, len);
    00583     rai->sockaddr_len = len;
    00584
    00585     rai->pfamily = pfamily;
    00586     rai->socktype = socktype;
    00587     rai->protocol = protocol;
    00588     rai->canonname = canonname;
    00589     rai->inspectname = inspectname;
    00590 }
    00591
    00592 VALUE
    00593 rsock_addrinfo_new(struct sockaddr *addr, socklen_t len,
    00594                    int family, int socktype, int protocol,
    00595                    VALUE canonname, VALUE inspectname)
    00596 {
    00597     VALUE a;
    00598     rb_addrinfo_t *rai;
    00599
    00600     a = addrinfo_s_allocate(rb_cAddrinfo);
    00601     DATA_PTR(a) = rai = alloc_addrinfo();
    00602     init_addrinfo(rai, addr, len, family, socktype, protocol, canonname, inspectname);
    00603     return a;
    00604 }
    00605
    00606 static struct addrinfo *
    00607 call_getaddrinfo(VALUE node, VALUE service,
    00608                  VALUE family, VALUE socktype, VALUE protocol, VALUE flags,
    00609                  int socktype_hack)
    00610 {
    00611     struct addrinfo hints, *res;
    00612
    00613     MEMZERO(&hints, struct addrinfo, 1);
    00614     hints.ai_family = NIL_P(family) ? PF_UNSPEC : rsock_family_arg(family);
    00615
    00616     if (!NIL_P(socktype)) {
    00617         hints.ai_socktype = rsock_socktype_arg(socktype);
    00618     }
    00619     if (!NIL_P(protocol)) {
    00620         hints.ai_protocol = NUM2INT(protocol);
    00621     }
    00622     if (!NIL_P(flags)) {
    00623         hints.ai_flags = NUM2INT(flags);
    00624     }
    00625     res = rsock_getaddrinfo(node, service, &hints, socktype_hack);
    00626
    00627     if (res == NULL)
    00628         rb_raise(rb_eSocket, "host not found");
    00629     return res;
    00630 }
    00631
    00632 static VALUE make_inspectname(VALUE node, VALUE service, struct addrinfo *res);
    00633
    00634 static void
    00635 init_addrinfo_getaddrinfo(rb_addrinfo_t *rai, VALUE node, VALUE service,
    00636                           VALUE family, VALUE socktype, VALUE protocol, VALUE flags,
    00637                           VALUE inspectnode, VALUE inspectservice)
    00638 {
    00639     struct addrinfo *res = call_getaddrinfo(node, service, family, socktype, protocol, flags, 1);
    00640     VALUE canonname;
    00641     VALUE inspectname = rb_str_equal(node, inspectnode) ? Qnil : make_inspectname(inspectnode, inspectservice, res);
    00642
    00643     canonname = Qnil;
    00644     if (res->ai_canonname) {
    00645         canonname = rb_tainted_str_new_cstr(res->ai_canonname);
    00646         OBJ_FREEZE(canonname);
    00647     }
    00648
    00649     init_addrinfo(rai, res->ai_addr, res->ai_addrlen,
    00650                   NUM2INT(family), NUM2INT(socktype), NUM2INT(protocol),
    00651                   canonname, inspectname);
    00652
    00653     freeaddrinfo(res);
    00654 }
    00655
    00656 static VALUE
    00657 make_inspectname(VALUE node, VALUE service, struct addrinfo *res)
    00658 {
    00659     VALUE inspectname = Qnil;
    00660
    00661     if (res) {
    00662         char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
    00663         int ret;
    00664         ret = rb_getnameinfo(res->ai_addr, res->ai_addrlen, hbuf,
    00665                              sizeof(hbuf), pbuf, sizeof(pbuf),
    00666                              NI_NUMERICHOST|NI_NUMERICSERV);
    00667         if (ret == 0) {
    00668             if (TYPE(node) == T_STRING && strcmp(hbuf, RSTRING_PTR(node)) == 0)
    00669                 node = Qnil;
    00670             if (TYPE(service) == T_STRING && strcmp(pbuf, RSTRING_PTR(service)) == 0)
    00671                 service = Qnil;
    00672             else if (TYPE(service) == T_FIXNUM && atoi(pbuf) == FIX2INT(service))
    00673                 service = Qnil;
    00674         }
    00675     }
    00676
    00677     if (TYPE(node) == T_STRING) {
    00678         inspectname = rb_str_dup(node);
    00679     }
    00680     if (TYPE(service) == T_STRING) {
    00681         if (NIL_P(inspectname))
    00682             inspectname = rb_sprintf(":%s", StringValueCStr(service));
    00683         else
    00684             rb_str_catf(inspectname, ":%s", StringValueCStr(service));
    00685     }
    00686     else if (TYPE(service) == T_FIXNUM && FIX2INT(service) != 0)
    00687     {
    00688         if (NIL_P(inspectname))
    00689             inspectname = rb_sprintf(":%d", FIX2INT(service));
    00690         else
    00691             rb_str_catf(inspectname, ":%d", FIX2INT(service));
    00692     }
    00693     if (!NIL_P(inspectname)) {
    00694         OBJ_INFECT(inspectname, node);
    00695         OBJ_INFECT(inspectname, service);
    00696         OBJ_FREEZE(inspectname);
    00697     }
    00698     return inspectname;
    00699 }
    00700
    00701 static VALUE
    00702 addrinfo_firstonly_new(VALUE node, VALUE service, VALUE family, VALUE socktype, VALUE protocol, VALUE flags)
    00703 {
    00704     VALUE ret;
    00705     VALUE canonname;
    00706     VALUE inspectname;
    00707
    00708     struct addrinfo *res = call_getaddrinfo(node, service, family, socktype, protocol, flags, 0);
    00709
    00710     inspectname = make_inspectname(node, service, res);
    00711
    00712     canonname = Qnil;
    00713     if (res->ai_canonname) {
    00714         canonname = rb_tainted_str_new_cstr(res->ai_canonname);
    00715         OBJ_FREEZE(canonname);
    00716     }
    00717
    00718     ret = rsock_addrinfo_new(res->ai_addr, res->ai_addrlen,
    00719                              res->ai_family, res->ai_socktype, res->ai_protocol,
    00720                              canonname, inspectname);
    00721
    00722     freeaddrinfo(res);
    00723     return ret;
    00724 }
    00725
    00726 static VALUE
    00727 addrinfo_list_new(VALUE node, VALUE service, VALUE family, VALUE socktype, VALUE protocol, VALUE flags)
    00728 {
    00729     VALUE ret;
    00730     struct addrinfo *r;
    00731     VALUE inspectname;
    00732
    00733     struct addrinfo *res = call_getaddrinfo(node, service, family, socktype, protocol, flags, 0);
    00734
    00735     inspectname = make_inspectname(node, service, res);
    00736
    00737     ret = rb_ary_new();
    00738     for (r = res; r; r = r->ai_next) {
    00739         VALUE addr;
    00740         VALUE canonname = Qnil;
    00741
    00742         if (r->ai_canonname) {
    00743             canonname = rb_tainted_str_new_cstr(r->ai_canonname);
    00744             OBJ_FREEZE(canonname);
    00745         }
    00746
    00747         addr = rsock_addrinfo_new(r->ai_addr, r->ai_addrlen,
    00748                                   r->ai_family, r->ai_socktype, r->ai_protocol,
    00749                                   canonname, inspectname);
    00750
    00751         rb_ary_push(ret, addr);
    00752     }
    00753
    00754     freeaddrinfo(res);
    00755     return ret;
    00756 }
    00757
    00758
    00759 #ifdef HAVE_SYS_UN_H
    00760 static void
    00761 init_unix_addrinfo(rb_addrinfo_t *rai, VALUE path, int socktype)
    00762 {
    00763     struct sockaddr_un un;
    00764
    00765     StringValue(path);
    00766
    00767     if (sizeof(un.sun_path) <= (size_t)RSTRING_LEN(path))
    00768         rb_raise(rb_eArgError, "too long unix socket path (max: %dbytes)",
    00769             (int)sizeof(un.sun_path)-1);
    00770
    00771     MEMZERO(&un, struct sockaddr_un, 1);
    00772
    00773     un.sun_family = AF_UNIX;
    00774     memcpy((void*)&un.sun_path, RSTRING_PTR(path), RSTRING_LEN(path));
    00775
    00776     init_addrinfo(rai, (struct sockaddr *)&un, (socklen_t)sizeof(un),
    00777                   PF_UNIX, socktype, 0, Qnil, Qnil);
    00778 }
    00779 #endif
    00780
    00781 /*
    00782  * call-seq:
    00783  *   Addrinfo.new(sockaddr)                             => addrinfo
    00784  *   Addrinfo.new(sockaddr, family)                     => addrinfo
    00785  *   Addrinfo.new(sockaddr, family, socktype)           => addrinfo
    00786  *   Addrinfo.new(sockaddr, family, socktype, protocol) => addrinfo
    00787  *
    00788  * returns a new instance of Addrinfo.
    00789  * The instance contains sockaddr, family, socktype, protocol.
    00790  * sockaddr means struct sockaddr which can be used for connect(2), etc.
    00791  * family, socktype and protocol are integers which is used for arguments of socket(2).
    00792  *
    00793  * sockaddr is specified as an array or a string.
    00794  * The array should be compatible to the value of IPSocket#addr or UNIXSocket#addr.
    00795  * The string should be struct sockaddr as generated by
    00796  * Socket.sockaddr_in or Socket.unpack_sockaddr_un.
    00797  *
    00798  * sockaddr examples:
    00799  * - ["AF_INET", 46102, "localhost.localdomain", "127.0.0.1"]
    00800  * - ["AF_INET6", 42304, "ip6-localhost", "::1"]
    00801  * - ["AF_UNIX", "/tmp/sock"]
    00802  * - Socket.sockaddr_in("smtp", "2001:DB8::1")
    00803  * - Socket.sockaddr_in(80, "172.18.22.42")
    00804  * - Socket.sockaddr_in(80, "www.ruby-lang.org")
    00805  * - Socket.sockaddr_un("/tmp/sock")
    00806  *
    00807  * In an AF_INET/AF_INET6 sockaddr array, the 4th element,
    00808  * numeric IP address, is used to construct socket address in the Addrinfo instance.
    00809  * If the 3rd element, textual host name, is non-nil, it is also recorded but used only for Addrinfo#inspect.
    00810  *
    00811  * family is specified as an integer to specify the protocol family such as Socket::PF_INET.
    00812  * It can be a symbol or a string which is the constant name
    00813  * with or without PF_ prefix such as :INET, :INET6, :UNIX, "PF_INET", etc.
    00814  * If omitted, PF_UNSPEC is assumed.
    00815  *
    00816  * socktype is specified as an integer to specify the socket type such as Socket::SOCK_STREAM.
    00817  * It can be a symbol or a string which is the constant name
    00818  * with or without SOCK_ prefix such as :STREAM, :DGRAM, :RAW, "SOCK_STREAM", etc.
    00819  * If omitted, 0 is assumed.
    00820  *
    00821  * protocol is specified as an integer to specify the protocol such as Socket::IPPROTO_TCP.
    00822  * It must be an integer, unlike family and socktype.
    00823  * If omitted, 0 is assumed.
    00824  * Note that 0 is reasonable value for most protocols, except raw socket.
    00825  *
    00826  */
    00827 static VALUE
    00828 addrinfo_initialize(int argc, VALUE *argv, VALUE self)
    00829 {
    00830     rb_addrinfo_t *rai;
    00831     VALUE sockaddr_arg, sockaddr_ary, pfamily, socktype, protocol;
    00832     int i_pfamily, i_socktype, i_protocol;
    00833     struct sockaddr *sockaddr_ptr;
    00834     socklen_t sockaddr_len;
    00835     VALUE canonname = Qnil, inspectname = Qnil;
    00836
    00837     if (check_addrinfo(self))
    00838         rb_raise(rb_eTypeError, "already initialized socket address");
    00839     DATA_PTR(self) = rai = alloc_addrinfo();
    00840
    00841     rb_scan_args(argc, argv, "13", &sockaddr_arg, &pfamily, &socktype, &protocol);
    00842
    00843     i_pfamily = NIL_P(pfamily) ? PF_UNSPEC : rsock_family_arg(pfamily);
    00844     i_socktype = NIL_P(socktype) ? 0 : rsock_socktype_arg(socktype);
    00845     i_protocol = NIL_P(protocol) ? 0 : NUM2INT(protocol);
    00846
    00847     sockaddr_ary = rb_check_array_type(sockaddr_arg);
    00848     if (!NIL_P(sockaddr_ary)) {
    00849         VALUE afamily = rb_ary_entry(sockaddr_ary, 0);
    00850         int af;
    00851         StringValue(afamily);
    00852         if (rsock_family_to_int(RSTRING_PTR(afamily), RSTRING_LEN(afamily), &af) == -1)
    00853             rb_raise(rb_eSocket, "unknown address family: %s", StringValueCStr(afamily));
    00854         switch (af) {
    00855           case AF_INET: /* ["AF_INET", 46102, "localhost.localdomain", "127.0.0.1"] */
    00856 #ifdef INET6
    00857           case AF_INET6: /* ["AF_INET6", 42304, "ip6-localhost", "::1"] */
    00858 #endif
    00859           {
    00860             VALUE service = rb_ary_entry(sockaddr_ary, 1);
    00861             VALUE nodename = rb_ary_entry(sockaddr_ary, 2);
    00862             VALUE numericnode = rb_ary_entry(sockaddr_ary, 3);
    00863             int flags;
    00864
    00865             service = INT2NUM(NUM2INT(service));
    00866             if (!NIL_P(nodename))
    00867                 StringValue(nodename);
    00868             StringValue(numericnode);
    00869             flags = AI_NUMERICHOST;
    00870 #ifdef AI_NUMERICSERV
    00871             flags |= AI_NUMERICSERV;
    00872 #endif
    00873
    00874             init_addrinfo_getaddrinfo(rai, numericnode, service,
    00875                     INT2NUM(i_pfamily ? i_pfamily : af), INT2NUM(i_socktype), INT2NUM(i_protocol),
    00876                     INT2NUM(flags),
    00877                     nodename, service);
    00878             break;
    00879           }
    00880
    00881 #ifdef HAVE_SYS_UN_H
    00882           case AF_UNIX: /* ["AF_UNIX", "/tmp/sock"] */
    00883           {
    00884             VALUE path = rb_ary_entry(sockaddr_ary, 1);
    00885             StringValue(path);
    00886             init_unix_addrinfo(rai, path, SOCK_STREAM);
    00887             break;
    00888           }
    00889 #endif
    00890
    00891           default:
    00892             rb_raise(rb_eSocket, "unexpected address family");
    00893         }
    00894     }
    00895     else {
    00896         StringValue(sockaddr_arg);
    00897         sockaddr_ptr = (struct sockaddr *)RSTRING_PTR(sockaddr_arg);
    00898         sockaddr_len = RSTRING_LENINT(sockaddr_arg);
    00899         init_addrinfo(rai, sockaddr_ptr, sockaddr_len,
    00900                       i_pfamily, i_socktype, i_protocol,
    00901                       canonname, inspectname);
    00902     }
    00903
    00904     return self;
    00905 }
    00906
    00907 static int
    00908 get_afamily(struct sockaddr *addr, socklen_t len)
    00909 {
    00910     if ((char*)&addr->sa_family + sizeof(addr->sa_family) - (char*)addr <= len)
    00911         return addr->sa_family;
    00912     else
    00913         return AF_UNSPEC;
    00914 }
    00915
    00916 static int
    00917 ai_get_afamily(rb_addrinfo_t *rai)
    00918 {
    00919     return get_afamily((struct sockaddr *)&rai->addr, rai->sockaddr_len);
    00920 }
    00921
    00922 static VALUE
    00923 inspect_sockaddr(VALUE addrinfo, VALUE ret)
    00924 {
    00925     rb_addrinfo_t *rai = get_addrinfo(addrinfo);
    00926
    00927     if (rai->sockaddr_len == 0) {
    00928         rb_str_cat2(ret, "empty-sockaddr");
    00929     }
    00930     else if ((long)rai->sockaddr_len < ((char*)&rai->addr.ss_family + sizeof(rai->addr.ss_family)) - (char*)&rai->addr)
    00931         rb_str_cat2(ret, "too-short-sockaddr");
    00932     else {
    00933         switch (rai->addr.ss_family) {
    00934           case AF_INET:
    00935           {
    00936             struct sockaddr_in *addr;
    00937             int port;
    00938             if (rai->sockaddr_len < sizeof(struct sockaddr_in)) {
    00939                 rb_str_cat2(ret, "too-short-AF_INET-sockaddr");
    00940             }
    00941             else {
    00942                 addr = (struct sockaddr_in *)&rai->addr;
    00943                 rb_str_catf(ret, "%d.%d.%d.%d",
    00944                             ((unsigned char*)&addr->sin_addr)[0],
    00945                             ((unsigned char*)&addr->sin_addr)[1],
    00946                             ((unsigned char*)&addr->sin_addr)[2],
    00947                             ((unsigned char*)&addr->sin_addr)[3]);
    00948                 port = ntohs(addr->sin_port);
    00949                 if (port)
    00950                     rb_str_catf(ret, ":%d", port);
    00951                 if (sizeof(struct sockaddr_in) < rai->sockaddr_len)
    00952                     rb_str_catf(ret, "(sockaddr %d bytes too long)", (int)(rai->sockaddr_len - sizeof(struct sockaddr_in)));
    00953             }
    00954             break;
    00955           }
    00956
    00957 #ifdef AF_INET6
    00958           case AF_INET6:
    00959           {
    00960             struct sockaddr_in6 *addr;
    00961             char hbuf[1024];
    00962             int port;
    00963             int error;
    00964             if (rai->sockaddr_len < sizeof(struct sockaddr_in6)) {
    00965                 rb_str_cat2(ret, "too-short-AF_INET6-sockaddr");
    00966             }
    00967             else {
    00968                 addr = (struct sockaddr_in6 *)&rai->addr;
    00969                 /* use getnameinfo for scope_id.
    00970                  * RFC 4007: IPv6 Scoped Address Architecture
    00971                  * draft-ietf-ipv6-scope-api-00.txt: Scoped Address Extensions to the IPv6 Basic Socket API
    00972                  */
    00973                 error = getnameinfo((struct sockaddr *)&rai->addr, rai->sockaddr_len,
    00974                                     hbuf, (socklen_t)sizeof(hbuf), NULL, 0,
    00975                                     NI_NUMERICHOST|NI_NUMERICSERV);
    00976                 if (error) {
    00977                     rsock_raise_socket_error("getnameinfo", error);
    00978                 }
    00979                 if (addr->sin6_port == 0) {
    00980                     rb_str_cat2(ret, hbuf);
    00981                 }
    00982                 else {
    00983                     port = ntohs(addr->sin6_port);
    00984                     rb_str_catf(ret, "[%s]:%d", hbuf, port);
    00985                 }
    00986                 if (sizeof(struct sockaddr_in6) < rai->sockaddr_len)
    00987                     rb_str_catf(ret, "(sockaddr %d bytes too long)", (int)(rai->sockaddr_len - sizeof(struct sockaddr_in6)));
    00988             }
    00989             break;
    00990           }
    00991 #endif
    00992
    00993 #ifdef HAVE_SYS_UN_H
    00994           case AF_UNIX:
    00995           {
    00996             struct sockaddr_un *addr = (struct sockaddr_un *)&rai->addr;
    00997             char *p, *s, *t, *e;
    00998             s = addr->sun_path;
    00999             e = (char*)addr + rai->sockaddr_len;
    01000             if (e < s)
    01001                 rb_str_cat2(ret, "too-short-AF_UNIX-sockaddr");
    01002             else if (s == e)
    01003                 rb_str_cat2(ret, "empty-path-AF_UNIX-sockaddr");
    01004             else {
    01005                 int printable_only = 1;
    01006                 p = s;
    01007                 while (p < e && *p != '\0') {
    01008                     printable_only = printable_only && ISPRINT(*p) && !ISSPACE(*p);
    01009                     p++;
    01010                 }
    01011                 t = p;
    01012                 while (p < e && *p == '\0')
    01013                     p++;
    01014                 if (printable_only && /* only printable, no space */
    01015                     t < e && /* NUL terminated */
    01016                     p == e) { /* no data after NUL */
    01017                     if (s == t)
    01018                         rb_str_cat2(ret, "empty-path-AF_UNIX-sockaddr");
    01019                     else if (s[0] == '/') /* absolute path */
    01020                         rb_str_cat2(ret, s);
    01021                     else
    01022                         rb_str_catf(ret, "AF_UNIX %s", s);
    01023                 }
    01024                 else {
    01025                     rb_str_cat2(ret, "AF_UNIX");
    01026                     e = (char *)addr->sun_path + sizeof(addr->sun_path);
    01027                     while (s < e && *(e-1) == '\0')
    01028                         e--;
    01029                     while (s < e)
    01030                         rb_str_catf(ret, ":%02x", (unsigned char)*s++);
    01031                 }
    01032                 if (addr->sun_path + sizeof(addr->sun_path) < (char*)&rai->addr + rai->sockaddr_len)
    01033                     rb_str_catf(ret, "(sockaddr %d bytes too long)",
    01034                             (int)(rai->sockaddr_len - (addr->sun_path + sizeof(addr->sun_path) - (char*)&rai->addr)));
    01035             }
    01036             break;
    01037           }
    01038 #endif
    01039
    01040           default:
    01041           {
    01042             ID id = rsock_intern_family(rai->addr.ss_family);
    01043             if (id == 0)
    01044                 rb_str_catf(ret, "unknown address family %d", rai->addr.ss_family);
    01045             else
    01046                 rb_str_catf(ret, "%s address format unknown", rb_id2name(id));
    01047             break;
    01048           }
    01049         }
    01050     }
    01051
    01052     return ret;
    01053 }
    01054
    01055 /*
    01056  * call-seq:
    01057  *   addrinfo.inspect => string
    01058  *
    01059  * returns a string which shows addrinfo in human-readable form.
    01060  *
    01061  *   Addrinfo.tcp("localhost", 80).inspect #=> "#<Addrinfo: 127.0.0.1:80 TCP (localhost:80)>"
    01062  *   Addrinfo.unix("/tmp/sock").inspect    #=> "#<Addrinfo: /tmp/sock SOCK_STREAM>"
    01063  *
    01064  */
    01065 static VALUE
    01066 addrinfo_inspect(VALUE self)
    01067 {
    01068     rb_addrinfo_t *rai = get_addrinfo(self);
    01069     int internet_p;
    01070     VALUE ret;
    01071
    01072     ret = rb_sprintf("#<%s: ", rb_obj_classname(self));
    01073
    01074     inspect_sockaddr(self, ret);
    01075
    01076     if (rai->pfamily && ai_get_afamily(rai) != rai->pfamily) {
    01077         ID id = rsock_intern_protocol_family(rai->pfamily);
    01078         if (id)
    01079             rb_str_catf(ret, " %s", rb_id2name(id));
    01080         else
    01081             rb_str_catf(ret, " PF_\?\?\?(%d)", rai->pfamily);
    01082     }
    01083
    01084     internet_p = rai->pfamily == PF_INET;
    01085 #ifdef INET6
    01086     internet_p = internet_p || rai->pfamily == PF_INET6;
    01087 #endif
    01088     if (internet_p && rai->socktype == SOCK_STREAM &&
    01089         (rai->protocol == 0 || rai->protocol == IPPROTO_TCP)) {
    01090         rb_str_cat2(ret, " TCP");
    01091     }
    01092     else if (internet_p && rai->socktype == SOCK_DGRAM &&
    01093         (rai->protocol == 0 || rai->protocol == IPPROTO_UDP)) {
    01094         rb_str_cat2(ret, " UDP");
    01095     }
    01096     else {
    01097         if (rai->socktype) {
    01098             ID id = rsock_intern_socktype(rai->socktype);
    01099             if (id)
    01100                 rb_str_catf(ret, " %s", rb_id2name(id));
    01101             else
    01102                 rb_str_catf(ret, " SOCK_\?\?\?(%d)", rai->socktype);
    01103         }
    01104
    01105         if (rai->protocol) {
    01106             if (internet_p) {
    01107                 ID id = rsock_intern_ipproto(rai->protocol);
    01108                 if (id)
    01109                     rb_str_catf(ret, " %s", rb_id2name(id));
    01110                 else
    01111                     goto unknown_protocol;
    01112             }
    01113             else {
    01114               unknown_protocol:
    01115                 rb_str_catf(ret, " UNKNOWN_PROTOCOL(%d)", rai->protocol);
    01116             }
    01117         }
    01118     }
    01119
    01120     if (!NIL_P(rai->canonname)) {
    01121         VALUE name = rai->canonname;
    01122         rb_str_catf(ret, " %s", StringValueCStr(name));
    01123     }
    01124
    01125     if (!NIL_P(rai->inspectname)) {
    01126         VALUE name = rai->inspectname;
    01127         rb_str_catf(ret, " (%s)", StringValueCStr(name));
    01128     }
    01129
    01130     rb_str_buf_cat2(ret, ">");
    01131     return ret;
    01132 }
    01133
    01134 /*
    01135  * call-seq:
    01136  *   addrinfo.inspect_sockaddr => string
    01137  *
    01138  * returns a string which shows the sockaddr in _addrinfo_ with human-readable form.
    01139  *
    01140  *   Addrinfo.tcp("localhost", 80).inspect_sockaddr     #=> "127.0.0.1:80"
    01141  *   Addrinfo.tcp("ip6-localhost", 80).inspect_sockaddr #=> "[::1]:80"
    01142  *   Addrinfo.unix("/tmp/sock").inspect_sockaddr        #=> "/tmp/sock"
    01143  *
    01144  */
    01145 static VALUE
    01146 addrinfo_inspect_sockaddr(VALUE self)
    01147 {
    01148     return inspect_sockaddr(self, rb_str_new("", 0));
    01149 }
    01150
    01151 /* :nodoc: */
    01152 static VALUE
    01153 addrinfo_mdump(VALUE self)
    01154 {
    01155     rb_addrinfo_t *rai = get_addrinfo(self);
    01156     VALUE sockaddr, afamily, pfamily, socktype, protocol, canonname, inspectname;
    01157     int afamily_int = ai_get_afamily(rai);
    01158     ID id;
    01159
    01160     id = rsock_intern_protocol_family(rai->pfamily);
    01161     if (id == 0)
    01162         rb_raise(rb_eSocket, "unknown protocol family: %d", rai->pfamily);
    01163     pfamily = rb_id2str(id);
    01164
    01165     if (rai->socktype == 0)
    01166         socktype = INT2FIX(0);
    01167     else {
    01168         id = rsock_intern_socktype(rai->socktype);
    01169         if (id == 0)
    01170             rb_raise(rb_eSocket, "unknown socktype: %d", rai->socktype);
    01171         socktype = rb_id2str(id);
    01172     }
    01173
    01174     if (rai->protocol == 0)
    01175         protocol = INT2FIX(0);
    01176     else if (IS_IP_FAMILY(afamily_int)) {
    01177         id = rsock_intern_ipproto(rai->protocol);
    01178         if (id == 0)
    01179             rb_raise(rb_eSocket, "unknown IP protocol: %d", rai->protocol);
    01180         protocol = rb_id2str(id);
    01181     }
    01182     else {
    01183         rb_raise(rb_eSocket, "unknown protocol: %d", rai->protocol);
    01184     }
    01185
    01186     canonname = rai->canonname;
    01187
    01188     inspectname = rai->inspectname;
    01189
    01190     id = rsock_intern_family(afamily_int);
    01191     if (id == 0)
    01192         rb_raise(rb_eSocket, "unknown address family: %d", afamily_int);
    01193     afamily = rb_id2str(id);
    01194
    01195     switch(afamily_int) {
    01196 #ifdef HAVE_SYS_UN_H
    01197       case AF_UNIX:
    01198       {
    01199         struct sockaddr_un *su = (struct sockaddr_un *)&rai->addr;
    01200         char *s, *e;
    01201         s = su->sun_path;
    01202         e = (char*)s + sizeof(su->sun_path);
    01203         while (s < e && *(e-1) == '\0')
    01204             e--;
    01205         sockaddr = rb_str_new(s, e-s);
    01206         break;
    01207       }
    01208 #endif
    01209
    01210       default:
    01211       {
    01212         char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
    01213         int error;
    01214         error = getnameinfo((struct sockaddr *)&rai->addr, rai->sockaddr_len,
    01215                             hbuf, (socklen_t)sizeof(hbuf), pbuf, (socklen_t)sizeof(pbuf),
    01216                             NI_NUMERICHOST|NI_NUMERICSERV);
    01217         if (error) {
    01218             rsock_raise_socket_error("getnameinfo", error);
    01219         }
    01220         sockaddr = rb_assoc_new(rb_str_new_cstr(hbuf), rb_str_new_cstr(pbuf));
    01221         break;
    01222       }
    01223     }
    01224
    01225     return rb_ary_new3(7, afamily, sockaddr, pfamily, socktype, protocol, canonname, inspectname);
    01226 }
    01227
    01228 /* :nodoc: */
    01229 static VALUE
    01230 addrinfo_mload(VALUE self, VALUE ary)
    01231 {
    01232     VALUE v;
    01233     VALUE canonname, inspectname;
    01234     int afamily, pfamily, socktype, protocol;
    01235     struct sockaddr_storage ss;
    01236     socklen_t len;
    01237     rb_addrinfo_t *rai;
    01238
    01239     if (check_addrinfo(self))
    01240         rb_raise(rb_eTypeError, "already initialized socket address");
    01241
    01242     ary = rb_convert_type(ary, T_ARRAY, "Array", "to_ary");
    01243
    01244     v = rb_ary_entry(ary, 0);
    01245     StringValue(v);
    01246     if (rsock_family_to_int(RSTRING_PTR(v), RSTRING_LEN(v), &afamily) == -1)
    01247         rb_raise(rb_eTypeError, "unexpected address family");
    01248
    01249     v = rb_ary_entry(ary, 2);
    01250     StringValue(v);
    01251     if (rsock_family_to_int(RSTRING_PTR(v), RSTRING_LEN(v), &pfamily) == -1)
    01252         rb_raise(rb_eTypeError, "unexpected protocol family");
    01253
    01254     v = rb_ary_entry(ary, 3);
    01255     if (v == INT2FIX(0))
    01256         socktype = 0;
    01257     else {
    01258         StringValue(v);
    01259         if (rsock_socktype_to_int(RSTRING_PTR(v), RSTRING_LEN(v), &socktype) == -1)
    01260             rb_raise(rb_eTypeError, "unexpected socktype");
    01261     }
    01262
    01263     v = rb_ary_entry(ary, 4);
    01264     if (v == INT2FIX(0))
    01265         protocol = 0;
    01266     else {
    01267         StringValue(v);
    01268         if (IS_IP_FAMILY(afamily)) {
    01269             if (rsock_ipproto_to_int(RSTRING_PTR(v), RSTRING_LEN(v), &protocol) == -1)
    01270                 rb_raise(rb_eTypeError, "unexpected protocol");
    01271         }
    01272         else {
    01273             rb_raise(rb_eTypeError, "unexpected protocol");
    01274         }
    01275     }
    01276
    01277     v = rb_ary_entry(ary, 5);
    01278     if (NIL_P(v))
    01279         canonname = Qnil;
    01280     else {
    01281         StringValue(v);
    01282         canonname = v;
    01283     }
    01284
    01285     v = rb_ary_entry(ary, 6);
    01286     if (NIL_P(v))
    01287         inspectname = Qnil;
    01288     else {
    01289         StringValue(v);
    01290         inspectname = v;
    01291     }
    01292
    01293     v = rb_ary_entry(ary, 1);
    01294     switch(afamily) {
    01295 #ifdef HAVE_SYS_UN_H
    01296       case AF_UNIX:
    01297       {
    01298         struct sockaddr_un uaddr;
    01299         memset(&uaddr, 0, sizeof(uaddr));
    01300         uaddr.sun_family = AF_UNIX;
    01301
    01302         StringValue(v);
    01303         if (sizeof(uaddr.sun_path) <= (size_t)RSTRING_LEN(v))
    01304             rb_raise(rb_eSocket, "too long AF_UNIX path");
    01305         memcpy(uaddr.sun_path, RSTRING_PTR(v), RSTRING_LEN(v));
    01306         len = (socklen_t)sizeof(uaddr);
    01307         memcpy(&ss, &uaddr, len);
    01308         break;
    01309       }
    01310 #endif
    01311
    01312       default:
    01313       {
    01314         VALUE pair = rb_convert_type(v, T_ARRAY, "Array", "to_ary");
    01315         struct addrinfo *res;
    01316         int flags = AI_NUMERICHOST;
    01317 #ifdef AI_NUMERICSERV
    01318         flags |= AI_NUMERICSERV;
    01319 #endif
    01320         res = call_getaddrinfo(rb_ary_entry(pair, 0), rb_ary_entry(pair, 1),
    01321                                INT2NUM(pfamily), INT2NUM(socktype), INT2NUM(protocol),
    01322                                INT2NUM(flags), 1);
    01323
    01324         len = res->ai_addrlen;
    01325         memcpy(&ss, res->ai_addr, res->ai_addrlen);
    01326         break;
    01327       }
    01328     }
    01329
    01330     DATA_PTR(self) = rai = alloc_addrinfo();
    01331     init_addrinfo(rai, (struct sockaddr *)&ss, len,
    01332                   pfamily, socktype, protocol,
    01333                   canonname, inspectname);
    01334     return self;
    01335 }
    01336
    01337 /*
    01338  * call-seq:
    01339  *   addrinfo.afamily => integer
    01340  *
    01341  * returns the address family as an integer.
    01342  *
    01343  *   Addrinfo.tcp("localhost", 80).afamily == Socket::AF_INET #=> true
    01344  *
    01345  */
    01346 static VALUE
    01347 addrinfo_afamily(VALUE self)
    01348 {
    01349     rb_addrinfo_t *rai = get_addrinfo(self);
    01350     return INT2NUM(ai_get_afamily(rai));
    01351 }
    01352
    01353 /*
    01354  * call-seq:
    01355  *   addrinfo.pfamily => integer
    01356  *
    01357  * returns the protocol family as an integer.
    01358  *
    01359  *   Addrinfo.tcp("localhost", 80).pfamily == Socket::PF_INET #=> true
    01360  *
    01361  */
    01362 static VALUE
    01363 addrinfo_pfamily(VALUE self)
    01364 {
    01365     rb_addrinfo_t *rai = get_addrinfo(self);
    01366     return INT2NUM(rai->pfamily);
    01367 }
    01368
    01369 /*
    01370  * call-seq:
    01371  *   addrinfo.socktype => integer
    01372  *
    01373  * returns the socket type as an integer.
    01374  *
    01375  *   Addrinfo.tcp("localhost", 80).socktype == Socket::SOCK_STREAM #=> true
    01376  *
    01377  */
    01378 static VALUE
    01379 addrinfo_socktype(VALUE self)
    01380 {
    01381     rb_addrinfo_t *rai = get_addrinfo(self);
    01382     return INT2NUM(rai->socktype);
    01383 }
    01384
    01385 /*
    01386  * call-seq:
    01387  *   addrinfo.protocol => integer
    01388  *
    01389  * returns the socket type as an integer.
    01390  *
    01391  *   Addrinfo.tcp("localhost", 80).protocol == Socket::IPPROTO_TCP #=> true
    01392  *
    01393  */
    01394 static VALUE
    01395 addrinfo_protocol(VALUE self)
    01396 {
    01397     rb_addrinfo_t *rai = get_addrinfo(self);
    01398     return INT2NUM(rai->protocol);
    01399 }
    01400
    01401 /*
    01402  * call-seq:
    01403  *   addrinfo.to_sockaddr => string
    01404  *
    01405  * returns the socket address as packed struct sockaddr string.
    01406  *
    01407  *   Addrinfo.tcp("localhost", 80).to_sockaddr
    01408  *   #=> "\x02\x00\x00P\x7F\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00"
    01409  *
    01410  */
    01411 static VALUE
    01412 addrinfo_to_sockaddr(VALUE self)
    01413 {
    01414     rb_addrinfo_t *rai = get_addrinfo(self);
    01415     VALUE ret;
    01416     ret = rb_str_new((char*)&rai->addr, rai->sockaddr_len);
    01417     OBJ_INFECT(ret, self);
    01418     return ret;
    01419 }
    01420
    01421 /*
    01422  * call-seq:
    01423  *   addrinfo.canonname => string or nil
    01424  *
    01425  * returns the canonical name as an string.
    01426  *
    01427  * nil is returned if no canonical name.
    01428  *
    01429  * The canonical name is set by Addrinfo.getaddrinfo when AI_CANONNAME is specified.
    01430  *
    01431  *   list = Addrinfo.getaddrinfo("www.ruby-lang.org", 80, :INET, :STREAM, nil, Socket::AI_CANONNAME)
    01432  *   p list[0] #=> #<Addrinfo: 221.186.184.68:80 TCP carbon.ruby-lang.org (www.ruby-lang.org:80)>
    01433  *   p list[0].canonname #=> "carbon.ruby-lang.org"
    01434  *
    01435  */
    01436 static VALUE
    01437 addrinfo_canonname(VALUE self)
    01438 {
    01439     rb_addrinfo_t *rai = get_addrinfo(self);
    01440     return rai->canonname;
    01441 }
    01442
    01443 /*
    01444  * call-seq:
    01445  *   addrinfo.ip? => true or false
    01446  *
    01447  * returns true if addrinfo is internet (IPv4/IPv6) address.
    01448  * returns false otherwise.
    01449  *
    01450  *   Addrinfo.tcp("127.0.0.1", 80).ip? #=> true
    01451  *   Addrinfo.tcp("::1", 80).ip?       #=> true
    01452  *   Addrinfo.unix("/tmp/sock").ip?    #=> false
    01453  *
    01454  */
    01455 static VALUE
    01456 addrinfo_ip_p(VALUE self)
    01457 {
    01458     rb_addrinfo_t *rai = get_addrinfo(self);
    01459     int family = ai_get_afamily(rai);
    01460     return IS_IP_FAMILY(family) ? Qtrue : Qfalse;
    01461 }
    01462
    01463 /*
    01464  * call-seq:
    01465  *   addrinfo.ipv4? => true or false
    01466  *
    01467  * returns true if addrinfo is IPv4 address.
    01468  * returns false otherwise.
    01469  *
    01470  *   Addrinfo.tcp("127.0.0.1", 80).ipv4? #=> true
    01471  *   Addrinfo.tcp("::1", 80).ipv4?       #=> false
    01472  *   Addrinfo.unix("/tmp/sock").ipv4?    #=> false
    01473  *
    01474  */
    01475 static VALUE
    01476 addrinfo_ipv4_p(VALUE self)
    01477 {
    01478     rb_addrinfo_t *rai = get_addrinfo(self);
    01479     return ai_get_afamily(rai) == AF_INET ? Qtrue : Qfalse;
    01480 }
    01481
    01482 /*
    01483  * call-seq:
    01484  *   addrinfo.ipv6? => true or false
    01485  *
    01486  * returns true if addrinfo is IPv6 address.
    01487  * returns false otherwise.
    01488  *
    01489  *   Addrinfo.tcp("127.0.0.1", 80).ipv6? #=> false
    01490  *   Addrinfo.tcp("::1", 80).ipv6?       #=> true
    01491  *   Addrinfo.unix("/tmp/sock").ipv6?    #=> false
    01492  *
    01493  */
    01494 static VALUE
    01495 addrinfo_ipv6_p(VALUE self)
    01496 {
    01497 #ifdef AF_INET6
    01498     rb_addrinfo_t *rai = get_addrinfo(self);
    01499     return ai_get_afamily(rai) == AF_INET6 ? Qtrue : Qfalse;
    01500 #else
    01501     return Qfalse;
    01502 #endif
    01503 }
    01504
    01505 /*
    01506  * call-seq:
    01507  *   addrinfo.unix? => true or false
    01508  *
    01509  * returns true if addrinfo is UNIX address.
    01510  * returns false otherwise.
    01511  *
    01512  *   Addrinfo.tcp("127.0.0.1", 80).unix? #=> false
    01513  *   Addrinfo.tcp("::1", 80).unix?       #=> false
    01514  *   Addrinfo.unix("/tmp/sock").unix?    #=> true
    01515  *
    01516  */
    01517 static VALUE
    01518 addrinfo_unix_p(VALUE self)
    01519 {
    01520     rb_addrinfo_t *rai = get_addrinfo(self);
    01521 #ifdef AF_UNIX
    01522     return ai_get_afamily(rai) == AF_UNIX ? Qtrue : Qfalse;
    01523 #else
    01524     return Qfalse;
    01525 #endif
    01526 }
    01527
    01528 /*
    01529  * call-seq:
    01530  *   addrinfo.getnameinfo        => [nodename, service]
    01531  *   addrinfo.getnameinfo(flags) => [nodename, service]
    01532  *
    01533  * returns nodename and service as a pair of strings.
    01534  * This converts struct sockaddr in addrinfo to textual representation.
    01535  *
    01536  * flags should be bitwise OR of Socket::NI_??? constants.
    01537  *
    01538  *   Addrinfo.tcp("127.0.0.1", 80).getnameinfo #=> ["localhost", "www"]
    01539  *
    01540  *   Addrinfo.tcp("127.0.0.1", 80).getnameinfo(Socket::NI_NUMERICSERV)
    01541  *   #=> ["localhost", "80"]
    01542  */
    01543 static VALUE
    01544 addrinfo_getnameinfo(int argc, VALUE *argv, VALUE self)
    01545 {
    01546     rb_addrinfo_t *rai = get_addrinfo(self);
    01547     VALUE vflags;
    01548     char hbuf[1024], pbuf[1024];
    01549     int flags, error;
    01550
    01551     rb_scan_args(argc, argv, "01", &vflags);
    01552
    01553     flags = NIL_P(vflags) ? 0 : NUM2INT(vflags);
    01554
    01555     if (rai->socktype == SOCK_DGRAM)
    01556         flags |= NI_DGRAM;
    01557
    01558     error = getnameinfo((struct sockaddr *)&rai->addr, rai->sockaddr_len,
    01559                         hbuf, (socklen_t)sizeof(hbuf), pbuf, (socklen_t)sizeof(pbuf),
    01560                         flags);
    01561     if (error) {
    01562         rsock_raise_socket_error("getnameinfo", error);
    01563     }
    01564
    01565     return rb_assoc_new(rb_str_new2(hbuf), rb_str_new2(pbuf));
    01566 }
    01567
    01568 /*
    01569  * call-seq:
    01570  *   addrinfo.ip_unpack => [addr, port]
    01571  *
    01572  * Returns the IP address and port number as 2-element array.
    01573  *
    01574  *   Addrinfo.tcp("127.0.0.1", 80).ip_unpack    #=> ["127.0.0.1", 80]
    01575  *   Addrinfo.tcp("::1", 80).ip_unpack          #=> ["::1", 80]
    01576  */
    01577 static VALUE
    01578 addrinfo_ip_unpack(VALUE self)
    01579 {
    01580     rb_addrinfo_t *rai = get_addrinfo(self);
    01581     int family = ai_get_afamily(rai);
    01582     VALUE vflags;
    01583     VALUE ret, portstr;
    01584
    01585     if (!IS_IP_FAMILY(family))
    01586         rb_raise(rb_eSocket, "need IPv4 or IPv6 address");
    01587
    01588     vflags = INT2NUM(NI_NUMERICHOST|NI_NUMERICSERV);
    01589     ret = addrinfo_getnameinfo(1, &vflags, self);
    01590     portstr = rb_ary_entry(ret, 1);
    01591     rb_ary_store(ret, 1, INT2NUM(atoi(StringValueCStr(portstr))));
    01592     return ret;
    01593 }
    01594
    01595 /*
    01596  * call-seq:
    01597  *   addrinfo.ip_address => string
    01598  *
    01599  * Returns the IP address as a string.
    01600  *
    01601  *   Addrinfo.tcp("127.0.0.1", 80).ip_address    #=> "127.0.0.1"
    01602  *   Addrinfo.tcp("::1", 80).ip_address          #=> "::1"
    01603  */
    01604 static VALUE
    01605 addrinfo_ip_address(VALUE self)
    01606 {
    01607     rb_addrinfo_t *rai = get_addrinfo(self);
    01608     int family = ai_get_afamily(rai);
    01609     VALUE vflags;
    01610     VALUE ret;
    01611
    01612     if (!IS_IP_FAMILY(family))
    01613         rb_raise(rb_eSocket, "need IPv4 or IPv6 address");
    01614
    01615     vflags = INT2NUM(NI_NUMERICHOST|NI_NUMERICSERV);
    01616     ret = addrinfo_getnameinfo(1, &vflags, self);
    01617     return rb_ary_entry(ret, 0);
    01618 }
    01619
    01620 /*
    01621  * call-seq:
    01622  *   addrinfo.ip_port => port
    01623  *
    01624  * Returns the port number as an integer.
    01625  *
    01626  *   Addrinfo.tcp("127.0.0.1", 80).ip_port    #=> 80
    01627  *   Addrinfo.tcp("::1", 80).ip_port          #=> 80
    01628  */
    01629 static VALUE
    01630 addrinfo_ip_port(VALUE self)
    01631 {
    01632     rb_addrinfo_t *rai = get_addrinfo(self);
    01633     int family = ai_get_afamily(rai);
    01634     int port;
    01635
    01636     if (!IS_IP_FAMILY(family)) {
    01637       bad_family:
    01638 #ifdef AF_INET6
    01639         rb_raise(rb_eSocket, "need IPv4 or IPv6 address");
    01640 #else
    01641         rb_raise(rb_eSocket, "need IPv4 address");
    01642 #endif
    01643     }
    01644
    01645     switch (family) {
    01646       case AF_INET:
    01647         if (rai->sockaddr_len != sizeof(struct sockaddr_in))
    01648             rb_raise(rb_eSocket, "unexpected sockaddr size for IPv4");
    01649         port = ntohs(((struct sockaddr_in *)&rai->addr)->sin_port);
    01650         break;
    01651
    01652 #ifdef AF_INET6
    01653       case AF_INET6:
    01654         if (rai->sockaddr_len != sizeof(struct sockaddr_in6))
    01655             rb_raise(rb_eSocket, "unexpected sockaddr size for IPv6");
    01656         port = ntohs(((struct sockaddr_in6 *)&rai->addr)->sin6_port);
    01657         break;
    01658 #endif
    01659
    01660       default:
    01661         goto bad_family;
    01662     }
    01663
    01664     return INT2NUM(port);
    01665 }
    01666
    01667 static int
    01668 extract_in_addr(VALUE self, uint32_t *addrp)
    01669 {
    01670     rb_addrinfo_t *rai = get_addrinfo(self);
    01671     int family = ai_get_afamily(rai);
    01672     if (family != AF_INET) return 0;
    01673     *addrp = ntohl(((struct sockaddr_in *)&rai->addr)->sin_addr.s_addr);
    01674     return 1;
    01675 }
    01676
    01677 /*
    01678  * Returns true for IPv4 private address (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16).
    01679  * It returns false otherwise.
    01680  */
    01681 static VALUE
    01682 addrinfo_ipv4_private_p(VALUE self)
    01683 {
    01684     uint32_t a;
    01685     if (!extract_in_addr(self, &a)) return Qfalse;
    01686     if ((a & 0xff000000) == 0x0a000000 || /* 10.0.0.0/8 */
    01687         (a & 0xfff00000) == 0xac100000 || /* 172.16.0.0/12 */
    01688         (a & 0xffff0000) == 0xc0a80000)   /* 192.168.0.0/16 */
    01689         return Qtrue;
    01690     return Qfalse;
    01691 }
    01692
    01693 /*
    01694  * Returns true for IPv4 loopback address (127.0.0.0/8).
    01695  * It returns false otherwise.
    01696  */
    01697 static VALUE
    01698 addrinfo_ipv4_loopback_p(VALUE self)
    01699 {
    01700     uint32_t a;
    01701     if (!extract_in_addr(self, &a)) return Qfalse;
    01702     if ((a & 0xff000000) == 0x7f000000) /* 127.0.0.0/8 */
    01703         return Qtrue;
    01704     return Qfalse;
    01705 }
    01706
    01707 /*
    01708  * Returns true for IPv4 multicast address (224.0.0.0/4).
    01709  * It returns false otherwise.
    01710  */
    01711 static VALUE
    01712 addrinfo_ipv4_multicast_p(VALUE self)
    01713 {
    01714     uint32_t a;
    01715     if (!extract_in_addr(self, &a)) return Qfalse;
    01716     if ((a & 0xf0000000) == 0xe0000000) /* 224.0.0.0/4 */
    01717         return Qtrue;
    01718     return Qfalse;
    01719 }
    01720
    01721 #ifdef INET6
    01722
    01723 static struct in6_addr *
    01724 extract_in6_addr(VALUE self)
    01725 {
    01726     rb_addrinfo_t *rai = get_addrinfo(self);
    01727     int family = ai_get_afamily(rai);
    01728     if (family != AF_INET6) return NULL;
    01729     return &((struct sockaddr_in6 *)&rai->addr)->sin6_addr;
    01730 }
    01731
    01732 /*
    01733  * Returns true for IPv6 unspecified address (::).
    01734  * It returns false otherwise.
    01735  */
    01736 static VALUE
    01737 addrinfo_ipv6_unspecified_p(VALUE self)
    01738 {
    01739     struct in6_addr *addr = extract_in6_addr(self);
    01740     if (addr && IN6_IS_ADDR_UNSPECIFIED(addr)) return Qtrue;
    01741     return Qfalse;
    01742 }
    01743
    01744 /*
    01745  * Returns true for IPv6 loopback address (::1).
    01746  * It returns false otherwise.
    01747  */
    01748 static VALUE
    01749 addrinfo_ipv6_loopback_p(VALUE self)
    01750 {
    01751     struct in6_addr *addr = extract_in6_addr(self);
    01752     if (addr && IN6_IS_ADDR_LOOPBACK(addr)) return Qtrue;
    01753     return Qfalse;
    01754 }
    01755
    01756 /*
    01757  * Returns true for IPv6 multicast address (ff00::/8).
    01758  * It returns false otherwise.
    01759  */
    01760 static VALUE
    01761 addrinfo_ipv6_multicast_p(VALUE self)
    01762 {
    01763     struct in6_addr *addr = extract_in6_addr(self);
    01764     if (addr && IN6_IS_ADDR_MULTICAST(addr)) return Qtrue;
    01765     return Qfalse;
    01766 }
    01767
    01768 /*
    01769  * Returns true for IPv6 link local address (ff80::/10).
    01770  * It returns false otherwise.
    01771  */
    01772 static VALUE
    01773 addrinfo_ipv6_linklocal_p(VALUE self)
    01774 {
    01775     struct in6_addr *addr = extract_in6_addr(self);
    01776     if (addr && IN6_IS_ADDR_LINKLOCAL(addr)) return Qtrue;
    01777     return Qfalse;
    01778 }
    01779
    01780 /*
    01781  * Returns true for IPv6 site local address (ffc0::/10).
    01782  * It returns false otherwise.
    01783  */
    01784 static VALUE
    01785 addrinfo_ipv6_sitelocal_p(VALUE self)
    01786 {
    01787     struct in6_addr *addr = extract_in6_addr(self);
    01788     if (addr && IN6_IS_ADDR_SITELOCAL(addr)) return Qtrue;
    01789     return Qfalse;
    01790 }
    01791
    01792 /*
    01793  * Returns true for IPv4-mapped IPv6 address (::ffff:0:0/80).
    01794  * It returns false otherwise.
    01795  */
    01796 static VALUE
    01797 addrinfo_ipv6_v4mapped_p(VALUE self)
    01798 {
    01799     struct in6_addr *addr = extract_in6_addr(self);
    01800     if (addr && IN6_IS_ADDR_V4MAPPED(addr)) return Qtrue;
    01801     return Qfalse;
    01802 }
    01803
    01804 /*
    01805  * Returns true for IPv4-compatible IPv6 address (::/80).
    01806  * It returns false otherwise.
    01807  */
    01808 static VALUE
    01809 addrinfo_ipv6_v4compat_p(VALUE self)
    01810 {
    01811     struct in6_addr *addr = extract_in6_addr(self);
    01812     if (addr && IN6_IS_ADDR_V4COMPAT(addr)) return Qtrue;
    01813     return Qfalse;
    01814 }
    01815
    01816 /*
    01817  * Returns true for IPv6 multicast node-local scope address.
    01818  * It returns false otherwise.
    01819  */
    01820 static VALUE
    01821 addrinfo_ipv6_mc_nodelocal_p(VALUE self)
    01822 {
    01823     struct in6_addr *addr = extract_in6_addr(self);
    01824     if (addr && IN6_IS_ADDR_MC_NODELOCAL(addr)) return Qtrue;
    01825     return Qfalse;
    01826 }
    01827
    01828 /*
    01829  * Returns true for IPv6 multicast link-local scope address.
    01830  * It returns false otherwise.
    01831  */
    01832 static VALUE
    01833 addrinfo_ipv6_mc_linklocal_p(VALUE self)
    01834 {
    01835     struct in6_addr *addr = extract_in6_addr(self);
    01836     if (addr && IN6_IS_ADDR_MC_LINKLOCAL(addr)) return Qtrue;
    01837     return Qfalse;
    01838 }
    01839
    01840 /*
    01841  * Returns true for IPv6 multicast site-local scope address.
    01842  * It returns false otherwise.
    01843  */
    01844 static VALUE
    01845 addrinfo_ipv6_mc_sitelocal_p(VALUE self)
    01846 {
    01847     struct in6_addr *addr = extract_in6_addr(self);
    01848     if (addr && IN6_IS_ADDR_MC_SITELOCAL(addr)) return Qtrue;
    01849     return Qfalse;
    01850 }
    01851
    01852 /*
    01853  * Returns true for IPv6 multicast organization-local scope address.
    01854  * It returns false otherwise.
    01855  */
    01856 static VALUE
    01857 addrinfo_ipv6_mc_orglocal_p(VALUE self)
    01858 {
    01859     struct in6_addr *addr = extract_in6_addr(self);
    01860     if (addr && IN6_IS_ADDR_MC_ORGLOCAL(addr)) return Qtrue;
    01861     return Qfalse;
    01862 }
    01863
    01864 /*
    01865  * Returns true for IPv6 multicast global scope address.
    01866  * It returns false otherwise.
    01867  */
    01868 static VALUE
    01869 addrinfo_ipv6_mc_global_p(VALUE self)
    01870 {
    01871     struct in6_addr *addr = extract_in6_addr(self);
    01872     if (addr && IN6_IS_ADDR_MC_GLOBAL(addr)) return Qtrue;
    01873     return Qfalse;
    01874 }
    01875
    01876 /*
    01877  * Returns IPv4 address of IPv4 mapped/compatible IPv6 address.
    01878  * It returns nil if +self+ is not IPv4 mapped/compatible IPv6 address.
    01879  *
    01880  *   Addrinfo.ip("::192.0.2.3").ipv6_to_ipv4      #=> #<Addrinfo: 192.0.2.3>
    01881  *   Addrinfo.ip("::ffff:192.0.2.3").ipv6_to_ipv4 #=> #<Addrinfo: 192.0.2.3>
    01882  *   Addrinfo.ip("::1").ipv6_to_ipv4              #=> nil
    01883  *   Addrinfo.ip("192.0.2.3").ipv6_to_ipv4        #=> nil
    01884  *   Addrinfo.unix("/tmp/sock").ipv6_to_ipv4      #=> nil
    01885  */
    01886 static VALUE
    01887 addrinfo_ipv6_to_ipv4(VALUE self)
    01888 {
    01889     rb_addrinfo_t *rai = get_addrinfo(self);
    01890     struct in6_addr *addr;
    01891     int family = ai_get_afamily(rai);
    01892     if (family != AF_INET6) return Qnil;
    01893     addr = &((struct sockaddr_in6 *)&rai->addr)->sin6_addr;
    01894     if (IN6_IS_ADDR_V4MAPPED(addr) || IN6_IS_ADDR_V4COMPAT(addr)) {
    01895         struct sockaddr_in sin4;
    01896         MEMZERO(&sin4, struct sockaddr_in, 1);
    01897         sin4.sin_family = AF_INET;
    01898         SET_SIN_LEN(&sin4, sizeof(sin4));
    01899         memcpy(&sin4.sin_addr, (char*)addr + sizeof(*addr) - sizeof(sin4.sin_addr), sizeof(sin4.sin_addr));
    01900         return rsock_addrinfo_new((struct sockaddr *)&sin4, (socklen_t)sizeof(sin4),
    01901                                   PF_INET, rai->socktype, rai->protocol,
    01902                                   rai->canonname, rai->inspectname);
    01903     }
    01904     else {
    01905         return Qnil;
    01906     }
    01907 }
    01908
    01909 #endif
    01910
    01911 #ifdef HAVE_SYS_UN_H
    01912 /*
    01913  * call-seq:
    01914  *   addrinfo.unix_path => path
    01915  *
    01916  * Returns the socket path as a string.
    01917  *
    01918  *   Addrinfo.unix("/tmp/sock").unix_path       #=> "/tmp/sock"
    01919  */
    01920 static VALUE
    01921 addrinfo_unix_path(VALUE self)
    01922 {
    01923     rb_addrinfo_t *rai = get_addrinfo(self);
    01924     int family = ai_get_afamily(rai);
    01925     struct sockaddr_un *addr;
    01926     char *s, *e;
    01927
    01928     if (family != AF_UNIX)
    01929         rb_raise(rb_eSocket, "need AF_UNIX address");
    01930
    01931     addr = (struct sockaddr_un *)&rai->addr;
    01932
    01933     s = addr->sun_path;
    01934     e = (char*)addr + rai->sockaddr_len;
    01935     if (e < s)
    01936         rb_raise(rb_eSocket, "too short AF_UNIX address");
    01937     if (addr->sun_path + sizeof(addr->sun_path) < e)
    01938         rb_raise(rb_eSocket, "too long AF_UNIX address");
    01939     while (s < e && *(e-1) == '\0')
    01940         e--;
    01941     return rb_str_new(s, e-s);
    01942 }
    01943 #endif
    01944
    01945 /*
    01946  * call-seq:
    01947  *   Addrinfo.getaddrinfo(nodename, service, family, socktype, protocol, flags) => [addrinfo, ...]
    01948  *   Addrinfo.getaddrinfo(nodename, service, family, socktype, protocol)        => [addrinfo, ...]
    01949  *   Addrinfo.getaddrinfo(nodename, service, family, socktype)                  => [addrinfo, ...]
    01950  *   Addrinfo.getaddrinfo(nodename, service, family)                            => [addrinfo, ...]
    01951  *   Addrinfo.getaddrinfo(nodename, service)                                    => [addrinfo, ...]
    01952  *
    01953  * returns a list of addrinfo objects as an array.
    01954  *
    01955  * This method converts nodename (hostname) and service (port) to addrinfo.
    01956  * Since the conversion is not unique, the result is a list of addrinfo objects.
    01957  *
    01958  * nodename or service can be nil if no conversion intended.
    01959  *
    01960  * family, socktype and protocol are hint for preferred protocol.
    01961  * If the result will be used for a socket with SOCK_STREAM,
    01962  * SOCK_STREAM should be specified as socktype.
    01963  * If so, Addrinfo.getaddrinfo returns addrinfo list appropriate for SOCK_STREAM.
    01964  * If they are omitted or nil is given, the result is not restricted.
    01965  *
    01966  * Similarly, PF_INET6 as family restricts for IPv6.
    01967  *
    01968  * flags should be bitwise OR of Socket::AI_??? constants.
    01969  *
    01970  * Note that socktype should be specified whenever application knows the usage of the address.
    01971  * Some platform causes an error when socktype is omitted and servname is specified as an integer
    01972  * because some port numbers, 512 for example, are ambiguous without socktype.
    01973  *
    01974  *   Addrinfo.getaddrinfo("www.kame.net", 80, nil, :STREAM)
    01975  *   #=> [#<Addrinfo: 203.178.141.194:80 TCP (www.kame.net:80)>,
    01976  *   #    #<Addrinfo: [2001:200:0:8002:203:47ff:fea5:3085]:80 TCP (www.kame.net:80)>]
    01977  *
    01978  */
    01979 static VALUE
    01980 addrinfo_s_getaddrinfo(int argc, VALUE *argv, VALUE self)
    01981 {
    01982     VALUE node, service, family, socktype, protocol, flags;
    01983
    01984     rb_scan_args(argc, argv, "24", &node, &service, &family, &socktype, &protocol, &flags);
    01985     return addrinfo_list_new(node, service, family, socktype, protocol, flags);
    01986 }
    01987
    01988 /*
    01989  * call-seq:
    01990  *   Addrinfo.ip(host) => addrinfo
    01991  *
    01992  * returns an addrinfo object for IP address.
    01993  *
    01994  * The port, socktype, protocol of the result is filled by zero.
    01995  * So, it is not appropriate to create a socket.
    01996  *
    01997  *   Addrinfo.ip("localhost") #=> #<Addrinfo: 127.0.0.1 (localhost)>
    01998  */
    01999 static VALUE
    02000 addrinfo_s_ip(VALUE self, VALUE host)
    02001 {
    02002     VALUE ret;
    02003     rb_addrinfo_t *rai;
    02004     ret = addrinfo_firstonly_new(host, Qnil,
    02005             INT2NUM(PF_UNSPEC), INT2FIX(0), INT2FIX(0), INT2FIX(0));
    02006     rai = get_addrinfo(ret);
    02007     rai->socktype = 0;
    02008     rai->protocol = 0;
    02009     return ret;
    02010 }
    02011
    02012 /*
    02013  * call-seq:
    02014  *   Addrinfo.tcp(host, port) => addrinfo
    02015  *
    02016  * returns an addrinfo object for TCP address.
    02017  *
    02018  *   Addrinfo.tcp("localhost", "smtp") #=> #<Addrinfo: 127.0.0.1:25 TCP (localhost:smtp)>
    02019  */
    02020 static VALUE
    02021 addrinfo_s_tcp(VALUE self, VALUE host, VALUE port)
    02022 {
    02023     return addrinfo_firstonly_new(host, port,
    02024             INT2NUM(PF_UNSPEC), INT2NUM(SOCK_STREAM), INT2NUM(IPPROTO_TCP), INT2FIX(0));
    02025 }
    02026
    02027 /*
    02028  * call-seq:
    02029  *   Addrinfo.udp(host, port) => addrinfo
    02030  *
    02031  * returns an addrinfo object for UDP address.
    02032  *
    02033  *   Addrinfo.udp("localhost", "daytime") #=> #<Addrinfo: 127.0.0.1:13 UDP (localhost:daytime)>
    02034  */
    02035 static VALUE
    02036 addrinfo_s_udp(VALUE self, VALUE host, VALUE port)
    02037 {
    02038     return addrinfo_firstonly_new(host, port,
    02039             INT2NUM(PF_UNSPEC), INT2NUM(SOCK_DGRAM), INT2NUM(IPPROTO_UDP), INT2FIX(0));
    02040 }
    02041
    02042 #ifdef HAVE_SYS_UN_H
    02043
    02044 /*
    02045  * call-seq:
    02046  *   Addrinfo.unix(path [, socktype]) => addrinfo
    02047  *
    02048  * returns an addrinfo object for UNIX socket address.
    02049  *
    02050  * _socktype_ specifies the socket type.
    02051  * If it is omitted, :STREAM is used.
    02052  *
    02053  *   Addrinfo.unix("/tmp/sock")         #=> #<Addrinfo: /tmp/sock SOCK_STREAM>
    02054  *   Addrinfo.unix("/tmp/sock", :DGRAM) #=> #<Addrinfo: /tmp/sock SOCK_DGRAM>
    02055  */
    02056 static VALUE
    02057 addrinfo_s_unix(int argc, VALUE *argv, VALUE self)
    02058 {
    02059     VALUE path, vsocktype, addr;
    02060     int socktype;
    02061     rb_addrinfo_t *rai;
    02062
    02063     rb_scan_args(argc, argv, "11", &path, &vsocktype);
    02064
    02065     if (NIL_P(vsocktype))
    02066         socktype = SOCK_STREAM;
    02067     else
    02068         socktype = rsock_socktype_arg(vsocktype);
    02069
    02070     addr = addrinfo_s_allocate(rb_cAddrinfo);
    02071     DATA_PTR(addr) = rai = alloc_addrinfo();
    02072     init_unix_addrinfo(rai, path, socktype);
    02073     OBJ_INFECT(addr, path);
    02074     return addr;
    02075 }
    02076
    02077 #endif
    02078
    02079 VALUE
    02080 rsock_sockaddr_string_value(volatile VALUE *v)
    02081 {
    02082     VALUE val = *v;
    02083     if (IS_ADDRINFO(val)) {
    02084         *v = addrinfo_to_sockaddr(val);
    02085     }
    02086     StringValue(*v);
    02087     return *v;
    02088 }
    02089
    02090 char *
    02091 rsock_sockaddr_string_value_ptr(volatile VALUE *v)
    02092 {
    02093     rsock_sockaddr_string_value(v);
    02094     return RSTRING_PTR(*v);
    02095 }
    02096
    02097 VALUE
    02098 rb_check_sockaddr_string_type(VALUE val)
    02099 {
    02100     if (IS_ADDRINFO(val))
    02101         return addrinfo_to_sockaddr(val);
    02102     return rb_check_string_type(val);
    02103 }
    02104
    02105 VALUE
    02106 rsock_fd_socket_addrinfo(int fd, struct sockaddr *addr, socklen_t len)
    02107 {
    02108     int family;
    02109     int socktype;
    02110     int ret;
    02111     socklen_t optlen = (socklen_t)sizeof(socktype);
    02112
    02113     /* assumes protocol family and address family are identical */
    02114     family = get_afamily(addr, len);
    02115
    02116     ret = getsockopt(fd, SOL_SOCKET, SO_TYPE, (void*)&socktype, &optlen);
    02117     if (ret == -1) {
    02118         rb_sys_fail("getsockopt(SO_TYPE)");
    02119     }
    02120
    02121     return rsock_addrinfo_new(addr, len, family, socktype, 0, Qnil, Qnil);
    02122 }
    02123
    02124 VALUE
    02125 rsock_io_socket_addrinfo(VALUE io, struct sockaddr *addr, socklen_t len)
    02126 {
    02127     rb_io_t *fptr;
    02128
    02129     switch (TYPE(io)) {
    02130       case T_FIXNUM:
    02131         return rsock_fd_socket_addrinfo(FIX2INT(io), addr, len);
    02132
    02133       case T_BIGNUM:
    02134         return rsock_fd_socket_addrinfo(NUM2INT(io), addr, len);
    02135
    02136       case T_FILE:
    02137         GetOpenFile(io, fptr);
    02138         return rsock_fd_socket_addrinfo(fptr->fd, addr, len);
    02139
    02140       default:
    02141         rb_raise(rb_eTypeError, "neither IO nor file descriptor");
    02142     }
    02143 }
    02144
    02145 /*
    02146  * Addrinfo class
    02147  */
    02148 void
    02149 rsock_init_addrinfo(void)
    02150 {
    02151     rb_cAddrinfo = rb_define_class("Addrinfo", rb_cData);
    02152     rb_define_alloc_func(rb_cAddrinfo, addrinfo_s_allocate);
    02153     rb_define_method(rb_cAddrinfo, "initialize", addrinfo_initialize, -1);
    02154     rb_define_method(rb_cAddrinfo, "inspect", addrinfo_inspect, 0);
    02155     rb_define_method(rb_cAddrinfo, "inspect_sockaddr", addrinfo_inspect_sockaddr, 0);
    02156     rb_define_singleton_method(rb_cAddrinfo, "getaddrinfo", addrinfo_s_getaddrinfo, -1);
    02157     rb_define_singleton_method(rb_cAddrinfo, "ip", addrinfo_s_ip, 1);
    02158     rb_define_singleton_method(rb_cAddrinfo, "tcp", addrinfo_s_tcp, 2);
    02159     rb_define_singleton_method(rb_cAddrinfo, "udp", addrinfo_s_udp, 2);
    02160 #ifdef HAVE_SYS_UN_H
    02161     rb_define_singleton_method(rb_cAddrinfo, "unix", addrinfo_s_unix, -1);
    02162 #endif
    02163
    02164     rb_define_method(rb_cAddrinfo, "afamily", addrinfo_afamily, 0);
    02165     rb_define_method(rb_cAddrinfo, "pfamily", addrinfo_pfamily, 0);
    02166     rb_define_method(rb_cAddrinfo, "socktype", addrinfo_socktype, 0);
    02167     rb_define_method(rb_cAddrinfo, "protocol", addrinfo_protocol, 0);
    02168     rb_define_method(rb_cAddrinfo, "canonname", addrinfo_canonname, 0);
    02169
    02170     rb_define_method(rb_cAddrinfo, "ipv4?", addrinfo_ipv4_p, 0);
    02171     rb_define_method(rb_cAddrinfo, "ipv6?", addrinfo_ipv6_p, 0);
    02172     rb_define_method(rb_cAddrinfo, "unix?", addrinfo_unix_p, 0);
    02173
    02174     rb_define_method(rb_cAddrinfo, "ip?", addrinfo_ip_p, 0);
    02175     rb_define_method(rb_cAddrinfo, "ip_unpack", addrinfo_ip_unpack, 0);
    02176     rb_define_method(rb_cAddrinfo, "ip_address", addrinfo_ip_address, 0);
    02177     rb_define_method(rb_cAddrinfo, "ip_port", addrinfo_ip_port, 0);
    02178
    02179     rb_define_method(rb_cAddrinfo, "ipv4_private?", addrinfo_ipv4_private_p, 0);
    02180     rb_define_method(rb_cAddrinfo, "ipv4_loopback?", addrinfo_ipv4_loopback_p, 0);
    02181     rb_define_method(rb_cAddrinfo, "ipv4_multicast?", addrinfo_ipv4_multicast_p, 0);
    02182
    02183 #ifdef INET6
    02184     rb_define_method(rb_cAddrinfo, "ipv6_unspecified?", addrinfo_ipv6_unspecified_p, 0);
    02185     rb_define_method(rb_cAddrinfo, "ipv6_loopback?", addrinfo_ipv6_loopback_p, 0);
    02186     rb_define_method(rb_cAddrinfo, "ipv6_multicast?", addrinfo_ipv6_multicast_p, 0);
    02187     rb_define_method(rb_cAddrinfo, "ipv6_linklocal?", addrinfo_ipv6_linklocal_p, 0);
    02188     rb_define_method(rb_cAddrinfo, "ipv6_sitelocal?", addrinfo_ipv6_sitelocal_p, 0);
    02189     rb_define_method(rb_cAddrinfo, "ipv6_v4mapped?", addrinfo_ipv6_v4mapped_p, 0);
    02190     rb_define_method(rb_cAddrinfo, "ipv6_v4compat?", addrinfo_ipv6_v4compat_p, 0);
    02191     rb_define_method(rb_cAddrinfo, "ipv6_mc_nodelocal?", addrinfo_ipv6_mc_nodelocal_p, 0);
    02192     rb_define_method(rb_cAddrinfo, "ipv6_mc_linklocal?", addrinfo_ipv6_mc_linklocal_p, 0);
    02193     rb_define_method(rb_cAddrinfo, "ipv6_mc_sitelocal?", addrinfo_ipv6_mc_sitelocal_p, 0);
    02194     rb_define_method(rb_cAddrinfo, "ipv6_mc_orglocal?", addrinfo_ipv6_mc_orglocal_p, 0);
    02195     rb_define_method(rb_cAddrinfo, "ipv6_mc_global?", addrinfo_ipv6_mc_global_p, 0);
    02196
    02197     rb_define_method(rb_cAddrinfo, "ipv6_to_ipv4", addrinfo_ipv6_to_ipv4, 0);
    02198 #endif
    02199
    02200 #ifdef HAVE_SYS_UN_H
    02201     rb_define_method(rb_cAddrinfo, "unix_path", addrinfo_unix_path, 0);
    02202 #endif
    02203
    02204     rb_define_method(rb_cAddrinfo, "to_sockaddr", addrinfo_to_sockaddr, 0);
    02205     rb_define_method(rb_cAddrinfo, "to_s", addrinfo_to_sockaddr, 0); /* compatibility for ruby before 1.9.2 */
    02206
    02207     rb_define_method(rb_cAddrinfo, "getnameinfo", addrinfo_getnameinfo, -1);
    02208
    02209     rb_define_method(rb_cAddrinfo, "marshal_dump", addrinfo_mdump, 0);
    02210     rb_define_method(rb_cAddrinfo, "marshal_load", addrinfo_mload, 1);
    02211 }
    02212