00001
00002
00003
00004
00005
00006
00007
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
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 const 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 static int
00104 ruby_getaddrinfo__darwin(const char *nodename, const char *servname,
00105 const struct addrinfo *hints, struct addrinfo **res)
00106 {
00107
00108 const char *tmp_servname;
00109 struct addrinfo tmp_hints;
00110 int error;
00111
00112 tmp_servname = servname;
00113 MEMCPY(&tmp_hints, hints, struct addrinfo, 1);
00114 if (nodename && servname) {
00115 if (str_is_number(tmp_servname) && atoi(servname) == 0) {
00116 tmp_servname = NULL;
00117 #ifdef AI_NUMERICSERV
00118 if (tmp_hints.ai_flags) tmp_hints.ai_flags &= ~AI_NUMERICSERV;
00119 #endif
00120 }
00121 }
00122
00123 error = getaddrinfo(nodename, tmp_servname, &tmp_hints, res);
00124 if (error == 0) {
00125
00126 struct addrinfo *r;
00127 r = *res;
00128 while (r) {
00129 if (! r->ai_socktype) r->ai_socktype = hints->ai_socktype;
00130 if (! r->ai_protocol) {
00131 if (r->ai_socktype == SOCK_DGRAM) {
00132 r->ai_protocol = IPPROTO_UDP;
00133 }
00134 else if (r->ai_socktype == SOCK_STREAM) {
00135 r->ai_protocol = IPPROTO_TCP;
00136 }
00137 }
00138 r = r->ai_next;
00139 }
00140 }
00141
00142 return error;
00143 }
00144 #undef getaddrinfo
00145 #define getaddrinfo(node,serv,hints,res) ruby_getaddrinfo__darwin((node),(serv),(hints),(res))
00146 #endif
00147
00148 #ifndef GETADDRINFO_EMU
00149 struct getaddrinfo_arg
00150 {
00151 const char *node;
00152 const char *service;
00153 const struct addrinfo *hints;
00154 struct addrinfo **res;
00155 };
00156
00157 static void *
00158 nogvl_getaddrinfo(void *arg)
00159 {
00160 int ret;
00161 struct getaddrinfo_arg *ptr = arg;
00162 ret = getaddrinfo(ptr->node, ptr->service, ptr->hints, ptr->res);
00163 #ifdef __linux__
00164
00165
00166
00167 if (ret == EAI_SYSTEM && errno == ENOENT)
00168 ret = EAI_NONAME;
00169 #endif
00170 return (void *)(VALUE)ret;
00171 }
00172 #endif
00173
00174 static int
00175 numeric_getaddrinfo(const char *node, const char *service,
00176 const struct addrinfo *hints,
00177 struct addrinfo **res)
00178 {
00179 #ifdef HAVE_INET_PTON
00180 # if defined __MINGW64__
00181 # define inet_pton(f,s,d) rb_w32_inet_pton(f,s,d)
00182 # endif
00183
00184 if (node && (!service || strspn(service, "0123456789") == strlen(service))) {
00185 static const struct {
00186 int socktype;
00187 int protocol;
00188 } list[] = {
00189 { SOCK_STREAM, IPPROTO_TCP },
00190 { SOCK_DGRAM, IPPROTO_UDP },
00191 { SOCK_RAW, 0 }
00192 };
00193 struct addrinfo *ai = NULL;
00194 int port = service ? (unsigned short)atoi(service): 0;
00195 int hint_family = hints ? hints->ai_family : PF_UNSPEC;
00196 int hint_socktype = hints ? hints->ai_socktype : 0;
00197 int hint_protocol = hints ? hints->ai_protocol : 0;
00198 char ipv4addr[4];
00199 #ifdef AF_INET6
00200 char ipv6addr[16];
00201 if ((hint_family == PF_UNSPEC || hint_family == PF_INET6) &&
00202 strspn(node, "0123456789abcdefABCDEF.:") == strlen(node) &&
00203 inet_pton(AF_INET6, node, ipv6addr)) {
00204 int i;
00205 for (i = numberof(list)-1; 0 <= i; i--) {
00206 if ((hint_socktype == 0 || hint_socktype == list[i].socktype) &&
00207 (hint_protocol == 0 || list[i].protocol == 0 || hint_protocol == list[i].protocol)) {
00208 struct addrinfo *ai0 = xcalloc(1, sizeof(struct addrinfo));
00209 struct sockaddr_in6 *sa = xmalloc(sizeof(struct sockaddr_in6));
00210 INIT_SOCKADDR_IN6(sa, sizeof(struct sockaddr_in6));
00211 memcpy(&sa->sin6_addr, ipv6addr, sizeof(ipv6addr));
00212 sa->sin6_port = htons(port);
00213 ai0->ai_family = PF_INET6;
00214 ai0->ai_socktype = list[i].socktype;
00215 ai0->ai_protocol = hint_protocol ? hint_protocol : list[i].protocol;
00216 ai0->ai_addrlen = sizeof(struct sockaddr_in6);
00217 ai0->ai_addr = (struct sockaddr *)sa;
00218 ai0->ai_canonname = NULL;
00219 ai0->ai_next = ai;
00220 ai = ai0;
00221 }
00222 }
00223 }
00224 else
00225 #endif
00226 if ((hint_family == PF_UNSPEC || hint_family == PF_INET) &&
00227 strspn(node, "0123456789.") == strlen(node) &&
00228 inet_pton(AF_INET, node, ipv4addr)) {
00229 int i;
00230 for (i = numberof(list)-1; 0 <= i; i--) {
00231 if ((hint_socktype == 0 || hint_socktype == list[i].socktype) &&
00232 (hint_protocol == 0 || list[i].protocol == 0 || hint_protocol == list[i].protocol)) {
00233 struct addrinfo *ai0 = xcalloc(1, sizeof(struct addrinfo));
00234 struct sockaddr_in *sa = xmalloc(sizeof(struct sockaddr_in));
00235 INIT_SOCKADDR_IN(sa, sizeof(struct sockaddr_in));
00236 memcpy(&sa->sin_addr, ipv4addr, sizeof(ipv4addr));
00237 sa->sin_port = htons(port);
00238 ai0->ai_family = PF_INET;
00239 ai0->ai_socktype = list[i].socktype;
00240 ai0->ai_protocol = hint_protocol ? hint_protocol : list[i].protocol;
00241 ai0->ai_addrlen = sizeof(struct sockaddr_in);
00242 ai0->ai_addr = (struct sockaddr *)sa;
00243 ai0->ai_canonname = NULL;
00244 ai0->ai_next = ai;
00245 ai = ai0;
00246 }
00247 }
00248 }
00249 if (ai) {
00250 *res = ai;
00251 return 0;
00252 }
00253 }
00254 #endif
00255 return EAI_FAIL;
00256 }
00257
00258 int
00259 rb_getaddrinfo(const char *node, const char *service,
00260 const struct addrinfo *hints,
00261 struct rb_addrinfo **res)
00262 {
00263 struct addrinfo *ai;
00264 int ret;
00265 int allocated_by_malloc = 0;
00266
00267 ret = numeric_getaddrinfo(node, service, hints, &ai);
00268 if (ret == 0)
00269 allocated_by_malloc = 1;
00270 else {
00271 #ifdef GETADDRINFO_EMU
00272 ret = getaddrinfo(node, service, hints, &ai);
00273 #else
00274 struct getaddrinfo_arg arg;
00275 MEMZERO(&arg, struct getaddrinfo_arg, 1);
00276 arg.node = node;
00277 arg.service = service;
00278 arg.hints = hints;
00279 arg.res = &ai;
00280 ret = (int)(VALUE)rb_thread_call_without_gvl(nogvl_getaddrinfo, &arg, RUBY_UBF_IO, 0);
00281 #endif
00282 }
00283
00284 if (ret == 0) {
00285 *res = (struct rb_addrinfo *)xmalloc(sizeof(struct rb_addrinfo));
00286 (*res)->allocated_by_malloc = allocated_by_malloc;
00287 (*res)->ai = ai;
00288 }
00289 return ret;
00290 }
00291
00292 void
00293 rb_freeaddrinfo(struct rb_addrinfo *ai)
00294 {
00295 if (!ai->allocated_by_malloc)
00296 freeaddrinfo(ai->ai);
00297 else {
00298 struct addrinfo *ai1, *ai2;
00299 ai1 = ai->ai;
00300 while (ai1) {
00301 ai2 = ai1->ai_next;
00302 xfree(ai1->ai_addr);
00303 xfree(ai1);
00304 ai1 = ai2;
00305 }
00306 }
00307 xfree(ai);
00308 }
00309
00310 #ifndef GETADDRINFO_EMU
00311 struct getnameinfo_arg
00312 {
00313 const struct sockaddr *sa;
00314 socklen_t salen;
00315 char *host;
00316 size_t hostlen;
00317 char *serv;
00318 size_t servlen;
00319 int flags;
00320 };
00321
00322 static void *
00323 nogvl_getnameinfo(void *arg)
00324 {
00325 struct getnameinfo_arg *ptr = arg;
00326 return (void *)(VALUE)getnameinfo(ptr->sa, ptr->salen,
00327 ptr->host, (socklen_t)ptr->hostlen,
00328 ptr->serv, (socklen_t)ptr->servlen,
00329 ptr->flags);
00330 }
00331 #endif
00332
00333 int
00334 rb_getnameinfo(const struct sockaddr *sa, socklen_t salen,
00335 char *host, size_t hostlen,
00336 char *serv, size_t servlen, int flags)
00337 {
00338 #ifdef GETADDRINFO_EMU
00339 return getnameinfo(sa, salen, host, hostlen, serv, servlen, flags);
00340 #else
00341 struct getnameinfo_arg arg;
00342 int ret;
00343 arg.sa = sa;
00344 arg.salen = salen;
00345 arg.host = host;
00346 arg.hostlen = hostlen;
00347 arg.serv = serv;
00348 arg.servlen = servlen;
00349 arg.flags = flags;
00350 ret = (int)(VALUE)rb_thread_call_without_gvl(nogvl_getnameinfo, &arg, RUBY_UBF_IO, 0);
00351 return ret;
00352 #endif
00353 }
00354
00355 static void
00356 make_ipaddr0(struct sockaddr *addr, socklen_t addrlen, char *buf, size_t buflen)
00357 {
00358 int error;
00359
00360 error = rb_getnameinfo(addr, addrlen, buf, buflen, NULL, 0, NI_NUMERICHOST);
00361 if (error) {
00362 rsock_raise_socket_error("getnameinfo", error);
00363 }
00364 }
00365
00366 VALUE
00367 rsock_make_ipaddr(struct sockaddr *addr, socklen_t addrlen)
00368 {
00369 char hbuf[1024];
00370
00371 make_ipaddr0(addr, addrlen, hbuf, sizeof(hbuf));
00372 return rb_str_new2(hbuf);
00373 }
00374
00375 static void
00376 make_inetaddr(unsigned int host, char *buf, size_t buflen)
00377 {
00378 struct sockaddr_in sin;
00379
00380 INIT_SOCKADDR_IN(&sin, sizeof(sin));
00381 sin.sin_addr.s_addr = host;
00382 make_ipaddr0((struct sockaddr*)&sin, sizeof(sin), buf, buflen);
00383 }
00384
00385 static int
00386 str_is_number(const char *p)
00387 {
00388 char *ep;
00389
00390 if (!p || *p == '\0')
00391 return 0;
00392 ep = NULL;
00393 (void)STRTOUL(p, &ep, 10);
00394 if (ep && *ep == '\0')
00395 return 1;
00396 else
00397 return 0;
00398 }
00399
00400 static char*
00401 host_str(VALUE host, char *hbuf, size_t hbuflen, int *flags_ptr)
00402 {
00403 if (NIL_P(host)) {
00404 return NULL;
00405 }
00406 else if (rb_obj_is_kind_of(host, rb_cInteger)) {
00407 unsigned int i = NUM2UINT(host);
00408
00409 make_inetaddr(htonl(i), hbuf, hbuflen);
00410 if (flags_ptr) *flags_ptr |= AI_NUMERICHOST;
00411 return hbuf;
00412 }
00413 else {
00414 char *name;
00415
00416 SafeStringValue(host);
00417 name = RSTRING_PTR(host);
00418 if (!name || *name == 0 || (name[0] == '<' && strcmp(name, "<any>") == 0)) {
00419 make_inetaddr(INADDR_ANY, hbuf, hbuflen);
00420 if (flags_ptr) *flags_ptr |= AI_NUMERICHOST;
00421 }
00422 else if (name[0] == '<' && strcmp(name, "<broadcast>") == 0) {
00423 make_inetaddr(INADDR_BROADCAST, hbuf, hbuflen);
00424 if (flags_ptr) *flags_ptr |= AI_NUMERICHOST;
00425 }
00426 else if (strlen(name) >= hbuflen) {
00427 rb_raise(rb_eArgError, "hostname too long (%"PRIuSIZE")",
00428 strlen(name));
00429 }
00430 else {
00431 strcpy(hbuf, name);
00432 }
00433 return hbuf;
00434 }
00435 }
00436
00437 static char*
00438 port_str(VALUE port, char *pbuf, size_t pbuflen, int *flags_ptr)
00439 {
00440 if (NIL_P(port)) {
00441 return 0;
00442 }
00443 else if (FIXNUM_P(port)) {
00444 snprintf(pbuf, pbuflen, "%ld", FIX2LONG(port));
00445 #ifdef AI_NUMERICSERV
00446 if (flags_ptr) *flags_ptr |= AI_NUMERICSERV;
00447 #endif
00448 return pbuf;
00449 }
00450 else {
00451 char *serv;
00452
00453 SafeStringValue(port);
00454 serv = RSTRING_PTR(port);
00455 if (strlen(serv) >= pbuflen) {
00456 rb_raise(rb_eArgError, "service name too long (%"PRIuSIZE")",
00457 strlen(serv));
00458 }
00459 strcpy(pbuf, serv);
00460 return pbuf;
00461 }
00462 }
00463
00464 struct rb_addrinfo*
00465 rsock_getaddrinfo(VALUE host, VALUE port, struct addrinfo *hints, int socktype_hack)
00466 {
00467 struct rb_addrinfo* res = NULL;
00468 char *hostp, *portp;
00469 int error;
00470 char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
00471 int additional_flags = 0;
00472
00473 hostp = host_str(host, hbuf, sizeof(hbuf), &additional_flags);
00474 portp = port_str(port, pbuf, sizeof(pbuf), &additional_flags);
00475
00476 if (socktype_hack && hints->ai_socktype == 0 && str_is_number(portp)) {
00477 hints->ai_socktype = SOCK_DGRAM;
00478 }
00479 hints->ai_flags |= additional_flags;
00480
00481 error = rb_getaddrinfo(hostp, portp, hints, &res);
00482 if (error) {
00483 if (hostp && hostp[strlen(hostp)-1] == '\n') {
00484 rb_raise(rb_eSocket, "newline at the end of hostname");
00485 }
00486 rsock_raise_socket_error("getaddrinfo", error);
00487 }
00488
00489 return res;
00490 }
00491
00492 struct rb_addrinfo*
00493 rsock_addrinfo(VALUE host, VALUE port, int socktype, int flags)
00494 {
00495 struct addrinfo hints;
00496
00497 MEMZERO(&hints, struct addrinfo, 1);
00498 hints.ai_family = AF_UNSPEC;
00499 hints.ai_socktype = socktype;
00500 hints.ai_flags = flags;
00501 return rsock_getaddrinfo(host, port, &hints, 1);
00502 }
00503
00504 VALUE
00505 rsock_ipaddr(struct sockaddr *sockaddr, socklen_t sockaddrlen, int norevlookup)
00506 {
00507 VALUE family, port, addr1, addr2;
00508 VALUE ary;
00509 int error;
00510 char hbuf[1024], pbuf[1024];
00511 ID id;
00512
00513 id = rsock_intern_family(sockaddr->sa_family);
00514 if (id) {
00515 family = rb_str_dup(rb_id2str(id));
00516 }
00517 else {
00518 sprintf(pbuf, "unknown:%d", sockaddr->sa_family);
00519 family = rb_str_new2(pbuf);
00520 }
00521
00522 addr1 = Qnil;
00523 if (!norevlookup) {
00524 error = rb_getnameinfo(sockaddr, sockaddrlen, hbuf, sizeof(hbuf),
00525 NULL, 0, 0);
00526 if (! error) {
00527 addr1 = rb_str_new2(hbuf);
00528 }
00529 }
00530 error = rb_getnameinfo(sockaddr, sockaddrlen, hbuf, sizeof(hbuf),
00531 pbuf, sizeof(pbuf), NI_NUMERICHOST | NI_NUMERICSERV);
00532 if (error) {
00533 rsock_raise_socket_error("getnameinfo", error);
00534 }
00535 addr2 = rb_str_new2(hbuf);
00536 if (addr1 == Qnil) {
00537 addr1 = addr2;
00538 }
00539 port = INT2FIX(atoi(pbuf));
00540 ary = rb_ary_new3(4, family, port, addr1, addr2);
00541
00542 return ary;
00543 }
00544
00545 #ifdef HAVE_SYS_UN_H
00546 VALUE
00547 rsock_unixpath_str(struct sockaddr_un *sockaddr, socklen_t len)
00548 {
00549 char *s, *e;
00550 s = sockaddr->sun_path;
00551 e = (char *)sockaddr + len;
00552 while (s < e && *(e-1) == '\0')
00553 e--;
00554 if (s <= e)
00555 return rb_str_new(s, e-s);
00556 else
00557 return rb_str_new2("");
00558 }
00559
00560 VALUE
00561 rsock_unixaddr(struct sockaddr_un *sockaddr, socklen_t len)
00562 {
00563 return rb_assoc_new(rb_str_new2("AF_UNIX"),
00564 rsock_unixpath_str(sockaddr, len));
00565 }
00566
00567 socklen_t
00568 rsock_unix_sockaddr_len(VALUE path)
00569 {
00570 #ifdef __linux__
00571 if (RSTRING_LEN(path) == 0) {
00572
00573 return (socklen_t) sizeof(sa_family_t);
00574 }
00575 else if (RSTRING_PTR(path)[0] == '\0') {
00576
00577 if (SOCKLEN_MAX - offsetof(struct sockaddr_un, sun_path) < (size_t)RSTRING_LEN(path))
00578 rb_raise(rb_eArgError, "Linux abstract socket too long");
00579 return (socklen_t) offsetof(struct sockaddr_un, sun_path) +
00580 RSTRING_SOCKLEN(path);
00581 }
00582 else {
00583 #endif
00584 return (socklen_t) sizeof(struct sockaddr_un);
00585 #ifdef __linux__
00586 }
00587 #endif
00588 }
00589 #endif
00590
00591 struct hostent_arg {
00592 VALUE host;
00593 struct rb_addrinfo* addr;
00594 VALUE (*ipaddr)(struct sockaddr*, socklen_t);
00595 };
00596
00597 static VALUE
00598 make_hostent_internal(struct hostent_arg *arg)
00599 {
00600 VALUE host = arg->host;
00601 struct addrinfo* addr = arg->addr->ai;
00602 VALUE (*ipaddr)(struct sockaddr*, socklen_t) = arg->ipaddr;
00603
00604 struct addrinfo *ai;
00605 struct hostent *h;
00606 VALUE ary, names;
00607 char **pch;
00608 const char* hostp;
00609 char hbuf[NI_MAXHOST];
00610
00611 ary = rb_ary_new();
00612 if (addr->ai_canonname) {
00613 hostp = addr->ai_canonname;
00614 }
00615 else {
00616 hostp = host_str(host, hbuf, sizeof(hbuf), NULL);
00617 }
00618 rb_ary_push(ary, rb_str_new2(hostp));
00619
00620 if (addr->ai_canonname && strlen(addr->ai_canonname) < NI_MAXHOST &&
00621 (h = gethostbyname(addr->ai_canonname))) {
00622 names = rb_ary_new();
00623 if (h->h_aliases != NULL) {
00624 for (pch = h->h_aliases; *pch; pch++) {
00625 rb_ary_push(names, rb_str_new2(*pch));
00626 }
00627 }
00628 }
00629 else {
00630 names = rb_ary_new2(0);
00631 }
00632 rb_ary_push(ary, names);
00633 rb_ary_push(ary, INT2NUM(addr->ai_family));
00634 for (ai = addr; ai; ai = ai->ai_next) {
00635 rb_ary_push(ary, (*ipaddr)(ai->ai_addr, ai->ai_addrlen));
00636 }
00637
00638 return ary;
00639 }
00640
00641 VALUE
00642 rsock_freeaddrinfo(VALUE arg)
00643 {
00644 struct rb_addrinfo *addr = (struct rb_addrinfo *)arg;
00645 rb_freeaddrinfo(addr);
00646 return Qnil;
00647 }
00648
00649 VALUE
00650 rsock_make_hostent(VALUE host, struct rb_addrinfo *addr, VALUE (*ipaddr)(struct sockaddr *, socklen_t))
00651 {
00652 struct hostent_arg arg;
00653
00654 arg.host = host;
00655 arg.addr = addr;
00656 arg.ipaddr = ipaddr;
00657 return rb_ensure(make_hostent_internal, (VALUE)&arg,
00658 rsock_freeaddrinfo, (VALUE)addr);
00659 }
00660
00661 typedef struct {
00662 VALUE inspectname;
00663 VALUE canonname;
00664 int pfamily;
00665 int socktype;
00666 int protocol;
00667 socklen_t sockaddr_len;
00668 union_sockaddr addr;
00669 } rb_addrinfo_t;
00670
00671 static void
00672 addrinfo_mark(void *ptr)
00673 {
00674 rb_addrinfo_t *rai = ptr;
00675 if (rai) {
00676 rb_gc_mark(rai->inspectname);
00677 rb_gc_mark(rai->canonname);
00678 }
00679 }
00680
00681 #define addrinfo_free RUBY_TYPED_DEFAULT_FREE
00682
00683 static size_t
00684 addrinfo_memsize(const void *ptr)
00685 {
00686 return ptr ? sizeof(rb_addrinfo_t) : 0;
00687 }
00688
00689 static const rb_data_type_t addrinfo_type = {
00690 "socket/addrinfo",
00691 {addrinfo_mark, addrinfo_free, addrinfo_memsize,},
00692 };
00693
00694 static VALUE
00695 addrinfo_s_allocate(VALUE klass)
00696 {
00697 return TypedData_Wrap_Struct(klass, &addrinfo_type, 0);
00698 }
00699
00700 #define IS_ADDRINFO(obj) rb_typeddata_is_kind_of((obj), &addrinfo_type)
00701 static inline rb_addrinfo_t *
00702 check_addrinfo(VALUE self)
00703 {
00704 return rb_check_typeddata(self, &addrinfo_type);
00705 }
00706
00707 static rb_addrinfo_t *
00708 get_addrinfo(VALUE self)
00709 {
00710 rb_addrinfo_t *rai = check_addrinfo(self);
00711
00712 if (!rai) {
00713 rb_raise(rb_eTypeError, "uninitialized socket address");
00714 }
00715 return rai;
00716 }
00717
00718
00719 static rb_addrinfo_t *
00720 alloc_addrinfo()
00721 {
00722 rb_addrinfo_t *rai = ALLOC(rb_addrinfo_t);
00723 memset(rai, 0, sizeof(rb_addrinfo_t));
00724 rai->inspectname = Qnil;
00725 rai->canonname = Qnil;
00726 return rai;
00727 }
00728
00729 static void
00730 init_addrinfo(rb_addrinfo_t *rai, struct sockaddr *sa, socklen_t len,
00731 int pfamily, int socktype, int protocol,
00732 VALUE canonname, VALUE inspectname)
00733 {
00734 if ((socklen_t)sizeof(rai->addr) < len)
00735 rb_raise(rb_eArgError, "sockaddr string too big");
00736 memcpy((void *)&rai->addr, (void *)sa, len);
00737 rai->sockaddr_len = len;
00738
00739 rai->pfamily = pfamily;
00740 rai->socktype = socktype;
00741 rai->protocol = protocol;
00742 rai->canonname = canonname;
00743 rai->inspectname = inspectname;
00744 }
00745
00746 VALUE
00747 rsock_addrinfo_new(struct sockaddr *addr, socklen_t len,
00748 int family, int socktype, int protocol,
00749 VALUE canonname, VALUE inspectname)
00750 {
00751 VALUE a;
00752 rb_addrinfo_t *rai;
00753
00754 a = addrinfo_s_allocate(rb_cAddrinfo);
00755 DATA_PTR(a) = rai = alloc_addrinfo();
00756 init_addrinfo(rai, addr, len, family, socktype, protocol, canonname, inspectname);
00757 return a;
00758 }
00759
00760 static struct rb_addrinfo *
00761 call_getaddrinfo(VALUE node, VALUE service,
00762 VALUE family, VALUE socktype, VALUE protocol, VALUE flags,
00763 int socktype_hack)
00764 {
00765 struct addrinfo hints;
00766 struct rb_addrinfo *res;
00767
00768 MEMZERO(&hints, struct addrinfo, 1);
00769 hints.ai_family = NIL_P(family) ? PF_UNSPEC : rsock_family_arg(family);
00770
00771 if (!NIL_P(socktype)) {
00772 hints.ai_socktype = rsock_socktype_arg(socktype);
00773 }
00774 if (!NIL_P(protocol)) {
00775 hints.ai_protocol = NUM2INT(protocol);
00776 }
00777 if (!NIL_P(flags)) {
00778 hints.ai_flags = NUM2INT(flags);
00779 }
00780 res = rsock_getaddrinfo(node, service, &hints, socktype_hack);
00781
00782 if (res == NULL)
00783 rb_raise(rb_eSocket, "host not found");
00784 return res;
00785 }
00786
00787 static VALUE make_inspectname(VALUE node, VALUE service, struct addrinfo *res);
00788
00789 static void
00790 init_addrinfo_getaddrinfo(rb_addrinfo_t *rai, VALUE node, VALUE service,
00791 VALUE family, VALUE socktype, VALUE protocol, VALUE flags,
00792 VALUE inspectnode, VALUE inspectservice)
00793 {
00794 struct rb_addrinfo *res = call_getaddrinfo(node, service, family, socktype, protocol, flags, 1);
00795 VALUE canonname;
00796 VALUE inspectname = rb_str_equal(node, inspectnode) ? Qnil : make_inspectname(inspectnode, inspectservice, res->ai);
00797
00798 canonname = Qnil;
00799 if (res->ai->ai_canonname) {
00800 canonname = rb_tainted_str_new_cstr(res->ai->ai_canonname);
00801 OBJ_FREEZE(canonname);
00802 }
00803
00804 init_addrinfo(rai, res->ai->ai_addr, res->ai->ai_addrlen,
00805 NUM2INT(family), NUM2INT(socktype), NUM2INT(protocol),
00806 canonname, inspectname);
00807
00808 rb_freeaddrinfo(res);
00809 }
00810
00811 static VALUE
00812 make_inspectname(VALUE node, VALUE service, struct addrinfo *res)
00813 {
00814 VALUE inspectname = Qnil;
00815
00816 if (res) {
00817
00818 char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
00819 int ret;
00820 ret = rb_getnameinfo(res->ai_addr, res->ai_addrlen, hbuf,
00821 sizeof(hbuf), pbuf, sizeof(pbuf),
00822 NI_NUMERICHOST|NI_NUMERICSERV);
00823 if (ret == 0) {
00824 if (RB_TYPE_P(node, T_STRING) && strcmp(hbuf, RSTRING_PTR(node)) == 0)
00825 node = Qnil;
00826 if (RB_TYPE_P(service, T_STRING) && strcmp(pbuf, RSTRING_PTR(service)) == 0)
00827 service = Qnil;
00828 else if (RB_TYPE_P(service, T_FIXNUM) && atoi(pbuf) == FIX2INT(service))
00829 service = Qnil;
00830 }
00831 }
00832
00833 if (RB_TYPE_P(node, T_STRING)) {
00834 inspectname = rb_str_dup(node);
00835 }
00836 if (RB_TYPE_P(service, T_STRING)) {
00837 if (NIL_P(inspectname))
00838 inspectname = rb_sprintf(":%s", StringValueCStr(service));
00839 else
00840 rb_str_catf(inspectname, ":%s", StringValueCStr(service));
00841 }
00842 else if (RB_TYPE_P(service, T_FIXNUM) && FIX2INT(service) != 0)
00843 {
00844 if (NIL_P(inspectname))
00845 inspectname = rb_sprintf(":%d", FIX2INT(service));
00846 else
00847 rb_str_catf(inspectname, ":%d", FIX2INT(service));
00848 }
00849 if (!NIL_P(inspectname)) {
00850 OBJ_INFECT(inspectname, node);
00851 OBJ_INFECT(inspectname, service);
00852 OBJ_FREEZE(inspectname);
00853 }
00854 return inspectname;
00855 }
00856
00857 static VALUE
00858 addrinfo_firstonly_new(VALUE node, VALUE service, VALUE family, VALUE socktype, VALUE protocol, VALUE flags)
00859 {
00860 VALUE ret;
00861 VALUE canonname;
00862 VALUE inspectname;
00863
00864 struct rb_addrinfo *res = call_getaddrinfo(node, service, family, socktype, protocol, flags, 0);
00865
00866 inspectname = make_inspectname(node, service, res->ai);
00867
00868 canonname = Qnil;
00869 if (res->ai->ai_canonname) {
00870 canonname = rb_tainted_str_new_cstr(res->ai->ai_canonname);
00871 OBJ_FREEZE(canonname);
00872 }
00873
00874 ret = rsock_addrinfo_new(res->ai->ai_addr, res->ai->ai_addrlen,
00875 res->ai->ai_family, res->ai->ai_socktype,
00876 res->ai->ai_protocol,
00877 canonname, inspectname);
00878
00879 rb_freeaddrinfo(res);
00880 return ret;
00881 }
00882
00883 static VALUE
00884 addrinfo_list_new(VALUE node, VALUE service, VALUE family, VALUE socktype, VALUE protocol, VALUE flags)
00885 {
00886 VALUE ret;
00887 struct addrinfo *r;
00888 VALUE inspectname;
00889
00890 struct rb_addrinfo *res = call_getaddrinfo(node, service, family, socktype, protocol, flags, 0);
00891
00892 inspectname = make_inspectname(node, service, res->ai);
00893
00894 ret = rb_ary_new();
00895 for (r = res->ai; r; r = r->ai_next) {
00896 VALUE addr;
00897 VALUE canonname = Qnil;
00898
00899 if (r->ai_canonname) {
00900 canonname = rb_tainted_str_new_cstr(r->ai_canonname);
00901 OBJ_FREEZE(canonname);
00902 }
00903
00904 addr = rsock_addrinfo_new(r->ai_addr, r->ai_addrlen,
00905 r->ai_family, r->ai_socktype, r->ai_protocol,
00906 canonname, inspectname);
00907
00908 rb_ary_push(ret, addr);
00909 }
00910
00911 rb_freeaddrinfo(res);
00912 return ret;
00913 }
00914
00915
00916 #ifdef HAVE_SYS_UN_H
00917 static void
00918 init_unix_addrinfo(rb_addrinfo_t *rai, VALUE path, int socktype)
00919 {
00920 struct sockaddr_un un;
00921 socklen_t len;
00922
00923 StringValue(path);
00924
00925 if (sizeof(un.sun_path) < (size_t)RSTRING_LEN(path))
00926 rb_raise(rb_eArgError,
00927 "too long unix socket path (%"PRIuSIZE" bytes given but %"PRIuSIZE" bytes max)",
00928 (size_t)RSTRING_LEN(path), sizeof(un.sun_path));
00929
00930 INIT_SOCKADDR_UN(&un, sizeof(struct sockaddr_un));
00931 memcpy((void*)&un.sun_path, RSTRING_PTR(path), RSTRING_LEN(path));
00932
00933 len = rsock_unix_sockaddr_len(path);
00934 init_addrinfo(rai, (struct sockaddr *)&un, len,
00935 PF_UNIX, socktype, 0, Qnil, Qnil);
00936 }
00937 #endif
00938
00939
00940
00941
00942
00943
00944
00945
00946
00947
00948
00949
00950
00951
00952
00953
00954
00955
00956
00957
00958
00959
00960
00961
00962
00963
00964
00965
00966
00967
00968
00969
00970
00971
00972
00973
00974
00975
00976
00977
00978
00979
00980
00981
00982
00983
00984
00985 static VALUE
00986 addrinfo_initialize(int argc, VALUE *argv, VALUE self)
00987 {
00988 rb_addrinfo_t *rai;
00989 VALUE sockaddr_arg, sockaddr_ary, pfamily, socktype, protocol;
00990 int i_pfamily, i_socktype, i_protocol;
00991 struct sockaddr *sockaddr_ptr;
00992 socklen_t sockaddr_len;
00993 VALUE canonname = Qnil, inspectname = Qnil;
00994
00995 if (check_addrinfo(self))
00996 rb_raise(rb_eTypeError, "already initialized socket address");
00997 DATA_PTR(self) = rai = alloc_addrinfo();
00998
00999 rb_scan_args(argc, argv, "13", &sockaddr_arg, &pfamily, &socktype, &protocol);
01000
01001 i_pfamily = NIL_P(pfamily) ? PF_UNSPEC : rsock_family_arg(pfamily);
01002 i_socktype = NIL_P(socktype) ? 0 : rsock_socktype_arg(socktype);
01003 i_protocol = NIL_P(protocol) ? 0 : NUM2INT(protocol);
01004
01005 sockaddr_ary = rb_check_array_type(sockaddr_arg);
01006 if (!NIL_P(sockaddr_ary)) {
01007 VALUE afamily = rb_ary_entry(sockaddr_ary, 0);
01008 int af;
01009 StringValue(afamily);
01010 if (rsock_family_to_int(RSTRING_PTR(afamily), RSTRING_LEN(afamily), &af) == -1)
01011 rb_raise(rb_eSocket, "unknown address family: %s", StringValueCStr(afamily));
01012 switch (af) {
01013 case AF_INET:
01014 #ifdef INET6
01015 case AF_INET6:
01016 #endif
01017 {
01018 VALUE service = rb_ary_entry(sockaddr_ary, 1);
01019 VALUE nodename = rb_ary_entry(sockaddr_ary, 2);
01020 VALUE numericnode = rb_ary_entry(sockaddr_ary, 3);
01021 int flags;
01022
01023 service = INT2NUM(NUM2INT(service));
01024 if (!NIL_P(nodename))
01025 StringValue(nodename);
01026 StringValue(numericnode);
01027 flags = AI_NUMERICHOST;
01028 #ifdef AI_NUMERICSERV
01029 flags |= AI_NUMERICSERV;
01030 #endif
01031
01032 init_addrinfo_getaddrinfo(rai, numericnode, service,
01033 INT2NUM(i_pfamily ? i_pfamily : af), INT2NUM(i_socktype), INT2NUM(i_protocol),
01034 INT2NUM(flags),
01035 nodename, service);
01036 break;
01037 }
01038
01039 #ifdef HAVE_SYS_UN_H
01040 case AF_UNIX:
01041 {
01042 VALUE path = rb_ary_entry(sockaddr_ary, 1);
01043 StringValue(path);
01044 init_unix_addrinfo(rai, path, SOCK_STREAM);
01045 break;
01046 }
01047 #endif
01048
01049 default:
01050 rb_raise(rb_eSocket, "unexpected address family");
01051 }
01052 }
01053 else {
01054 StringValue(sockaddr_arg);
01055 sockaddr_ptr = (struct sockaddr *)RSTRING_PTR(sockaddr_arg);
01056 sockaddr_len = RSTRING_SOCKLEN(sockaddr_arg);
01057 init_addrinfo(rai, sockaddr_ptr, sockaddr_len,
01058 i_pfamily, i_socktype, i_protocol,
01059 canonname, inspectname);
01060 }
01061
01062 return self;
01063 }
01064
01065 static int
01066 get_afamily(struct sockaddr *addr, socklen_t len)
01067 {
01068 if ((socklen_t)((char*)&addr->sa_family + sizeof(addr->sa_family) - (char*)addr) <= len)
01069 return addr->sa_family;
01070 else
01071 return AF_UNSPEC;
01072 }
01073
01074 static int
01075 ai_get_afamily(rb_addrinfo_t *rai)
01076 {
01077 return get_afamily(&rai->addr.addr, rai->sockaddr_len);
01078 }
01079
01080 static VALUE
01081 inspect_sockaddr(VALUE addrinfo, VALUE ret)
01082 {
01083 rb_addrinfo_t *rai = get_addrinfo(addrinfo);
01084 union_sockaddr *sockaddr = &rai->addr;
01085 socklen_t socklen = rai->sockaddr_len;
01086 return rsock_inspect_sockaddr((struct sockaddr *)sockaddr, socklen, ret);
01087 }
01088
01089 VALUE
01090 rsock_inspect_sockaddr(struct sockaddr *sockaddr_arg, socklen_t socklen, VALUE ret)
01091 {
01092 union_sockaddr *sockaddr = (union_sockaddr *)sockaddr_arg;
01093 if (socklen == 0) {
01094 rb_str_cat2(ret, "empty-sockaddr");
01095 }
01096 else if ((long)socklen < ((char*)&sockaddr->addr.sa_family + sizeof(sockaddr->addr.sa_family)) - (char*)sockaddr)
01097 rb_str_cat2(ret, "too-short-sockaddr");
01098 else {
01099 switch (sockaddr->addr.sa_family) {
01100 case AF_UNSPEC:
01101 {
01102 rb_str_cat2(ret, "UNSPEC");
01103 break;
01104 }
01105
01106 case AF_INET:
01107 {
01108 struct sockaddr_in *addr;
01109 int port;
01110 addr = &sockaddr->in;
01111 if ((socklen_t)(((char*)&addr->sin_addr)-(char*)addr+0+1) <= socklen)
01112 rb_str_catf(ret, "%d", ((unsigned char*)&addr->sin_addr)[0]);
01113 else
01114 rb_str_cat2(ret, "?");
01115 if ((socklen_t)(((char*)&addr->sin_addr)-(char*)addr+1+1) <= socklen)
01116 rb_str_catf(ret, ".%d", ((unsigned char*)&addr->sin_addr)[1]);
01117 else
01118 rb_str_cat2(ret, ".?");
01119 if ((socklen_t)(((char*)&addr->sin_addr)-(char*)addr+2+1) <= socklen)
01120 rb_str_catf(ret, ".%d", ((unsigned char*)&addr->sin_addr)[2]);
01121 else
01122 rb_str_cat2(ret, ".?");
01123 if ((socklen_t)(((char*)&addr->sin_addr)-(char*)addr+3+1) <= socklen)
01124 rb_str_catf(ret, ".%d", ((unsigned char*)&addr->sin_addr)[3]);
01125 else
01126 rb_str_cat2(ret, ".?");
01127
01128 if ((socklen_t)(((char*)&addr->sin_port)-(char*)addr+(int)sizeof(addr->sin_port)) < socklen) {
01129 port = ntohs(addr->sin_port);
01130 if (port)
01131 rb_str_catf(ret, ":%d", port);
01132 }
01133 else {
01134 rb_str_cat2(ret, ":?");
01135 }
01136 if ((socklen_t)sizeof(struct sockaddr_in) != socklen)
01137 rb_str_catf(ret, " (%d bytes for %d bytes sockaddr_in)",
01138 (int)socklen,
01139 (int)sizeof(struct sockaddr_in));
01140 break;
01141 }
01142
01143 #ifdef AF_INET6
01144 case AF_INET6:
01145 {
01146 struct sockaddr_in6 *addr;
01147 char hbuf[1024];
01148 int port;
01149 int error;
01150 if (socklen < (socklen_t)sizeof(struct sockaddr_in6)) {
01151 rb_str_catf(ret, "too-short-AF_INET6-sockaddr %d bytes", (int)socklen);
01152 }
01153 else {
01154 addr = &sockaddr->in6;
01155
01156
01157
01158
01159 error = getnameinfo(&sockaddr->addr, socklen,
01160 hbuf, (socklen_t)sizeof(hbuf), NULL, 0,
01161 NI_NUMERICHOST|NI_NUMERICSERV);
01162 if (error) {
01163 rsock_raise_socket_error("getnameinfo", error);
01164 }
01165 if (addr->sin6_port == 0) {
01166 rb_str_cat2(ret, hbuf);
01167 }
01168 else {
01169 port = ntohs(addr->sin6_port);
01170 rb_str_catf(ret, "[%s]:%d", hbuf, port);
01171 }
01172 if ((socklen_t)sizeof(struct sockaddr_in6) < socklen)
01173 rb_str_catf(ret, "(sockaddr %d bytes too long)", (int)(socklen - sizeof(struct sockaddr_in6)));
01174 }
01175 break;
01176 }
01177 #endif
01178
01179 #ifdef HAVE_SYS_UN_H
01180 case AF_UNIX:
01181 {
01182 struct sockaddr_un *addr = &sockaddr->un;
01183 char *p, *s, *e;
01184 s = addr->sun_path;
01185 e = (char*)addr + socklen;
01186 while (s < e && *(e-1) == '\0')
01187 e--;
01188 if (e < s)
01189 rb_str_cat2(ret, "too-short-AF_UNIX-sockaddr");
01190 else if (s == e)
01191 rb_str_cat2(ret, "empty-path-AF_UNIX-sockaddr");
01192 else {
01193 int printable_only = 1;
01194 p = s;
01195 while (p < e) {
01196 printable_only = printable_only && ISPRINT(*p) && !ISSPACE(*p);
01197 p++;
01198 }
01199 if (printable_only) {
01200 if (s[0] != '/')
01201 rb_str_cat2(ret, "UNIX ");
01202 rb_str_cat(ret, s, p - s);
01203 }
01204 else {
01205 rb_str_cat2(ret, "UNIX");
01206 while (s < e)
01207 rb_str_catf(ret, ":%02x", (unsigned char)*s++);
01208 }
01209 }
01210 break;
01211 }
01212 #endif
01213
01214 #ifdef AF_PACKET
01215
01216 case AF_PACKET:
01217 {
01218 struct sockaddr_ll *addr;
01219 const char *sep = "[";
01220 #define CATSEP do { rb_str_cat2(ret, sep); sep = " "; } while (0);
01221
01222 addr = (struct sockaddr_ll *)sockaddr;
01223
01224 rb_str_cat2(ret, "PACKET");
01225
01226 if (offsetof(struct sockaddr_ll, sll_protocol) + sizeof(addr->sll_protocol) <= (size_t)socklen) {
01227 CATSEP;
01228 rb_str_catf(ret, "protocol=%d", ntohs(addr->sll_protocol));
01229 }
01230 if (offsetof(struct sockaddr_ll, sll_ifindex) + sizeof(addr->sll_ifindex) <= (size_t)socklen) {
01231 char buf[IFNAMSIZ];
01232 CATSEP;
01233 if (if_indextoname(addr->sll_ifindex, buf) == NULL)
01234 rb_str_catf(ret, "ifindex=%d", addr->sll_ifindex);
01235 else
01236 rb_str_catf(ret, "%s", buf);
01237 }
01238 if (offsetof(struct sockaddr_ll, sll_hatype) + sizeof(addr->sll_hatype) <= (size_t)socklen) {
01239 CATSEP;
01240 rb_str_catf(ret, "hatype=%d", addr->sll_hatype);
01241 }
01242 if (offsetof(struct sockaddr_ll, sll_pkttype) + sizeof(addr->sll_pkttype) <= (size_t)socklen) {
01243 CATSEP;
01244 if (addr->sll_pkttype == PACKET_HOST)
01245 rb_str_cat2(ret, "HOST");
01246 else if (addr->sll_pkttype == PACKET_BROADCAST)
01247 rb_str_cat2(ret, "BROADCAST");
01248 else if (addr->sll_pkttype == PACKET_MULTICAST)
01249 rb_str_cat2(ret, "MULTICAST");
01250 else if (addr->sll_pkttype == PACKET_OTHERHOST)
01251 rb_str_cat2(ret, "OTHERHOST");
01252 else if (addr->sll_pkttype == PACKET_OUTGOING)
01253 rb_str_cat2(ret, "OUTGOING");
01254 else
01255 rb_str_catf(ret, "pkttype=%d", addr->sll_pkttype);
01256 }
01257 if (socklen != (socklen_t)(offsetof(struct sockaddr_ll, sll_addr) + addr->sll_halen)) {
01258 CATSEP;
01259 if (offsetof(struct sockaddr_ll, sll_halen) + sizeof(addr->sll_halen) <= (size_t)socklen) {
01260 rb_str_catf(ret, "halen=%d", addr->sll_halen);
01261 }
01262 }
01263 if (offsetof(struct sockaddr_ll, sll_addr) < (size_t)socklen) {
01264 socklen_t len, i;
01265 CATSEP;
01266 rb_str_cat2(ret, "hwaddr");
01267 len = addr->sll_halen;
01268 if ((size_t)socklen < offsetof(struct sockaddr_ll, sll_addr) + len)
01269 len = socklen - offsetof(struct sockaddr_ll, sll_addr);
01270 for (i = 0; i < len; i++) {
01271 rb_str_cat2(ret, i == 0 ? "=" : ":");
01272 rb_str_catf(ret, "%02x", addr->sll_addr[i]);
01273 }
01274 }
01275
01276 if (socklen < (socklen_t)(offsetof(struct sockaddr_ll, sll_halen) + sizeof(addr->sll_halen)) ||
01277 (socklen_t)(offsetof(struct sockaddr_ll, sll_addr) + addr->sll_halen) != socklen) {
01278 CATSEP;
01279 rb_str_catf(ret, "(%d bytes for %d bytes sockaddr_ll)",
01280 (int)socklen, (int)sizeof(struct sockaddr_ll));
01281 }
01282
01283 rb_str_cat2(ret, "]");
01284 #undef CATSEP
01285
01286 break;
01287 }
01288 #endif
01289
01290 #if defined(AF_LINK) && defined(HAVE_TYPE_STRUCT_SOCKADDR_DL)
01291
01292
01293
01294
01295 case AF_LINK:
01296 {
01297
01298
01299
01300
01301
01302
01303
01304
01305 struct sockaddr_dl *addr = &sockaddr->dl;
01306 char *np = NULL, *ap = NULL, *endp;
01307 int nlen = 0, alen = 0;
01308 int i, off;
01309 const char *sep = "[";
01310 #define CATSEP do { rb_str_cat2(ret, sep); sep = " "; } while (0);
01311
01312 rb_str_cat2(ret, "LINK");
01313
01314 endp = ((char *)addr) + socklen;
01315
01316 if (offsetof(struct sockaddr_dl, sdl_data) < socklen) {
01317 np = addr->sdl_data;
01318 nlen = addr->sdl_nlen;
01319 if (endp - np < nlen)
01320 nlen = (int)(endp - np);
01321 }
01322 off = addr->sdl_nlen;
01323
01324 if (offsetof(struct sockaddr_dl, sdl_data) + off < socklen) {
01325 ap = addr->sdl_data + off;
01326 alen = addr->sdl_alen;
01327 if (endp - ap < alen)
01328 alen = (int)(endp - ap);
01329 }
01330
01331 CATSEP;
01332 if (np)
01333 rb_str_catf(ret, "%.*s", nlen, np);
01334 else
01335 rb_str_cat2(ret, "?");
01336
01337 if (ap && 0 < alen) {
01338 CATSEP;
01339 for (i = 0; i < alen; i++)
01340 rb_str_catf(ret, "%s%02x", i == 0 ? "" : ":", (unsigned char)ap[i]);
01341 }
01342
01343 if (socklen < (socklen_t)(offsetof(struct sockaddr_dl, sdl_nlen) + sizeof(addr->sdl_nlen)) ||
01344 socklen < (socklen_t)(offsetof(struct sockaddr_dl, sdl_alen) + sizeof(addr->sdl_alen)) ||
01345 socklen < (socklen_t)(offsetof(struct sockaddr_dl, sdl_slen) + sizeof(addr->sdl_slen)) ||
01346
01347
01348 socklen < (socklen_t)(offsetof(struct sockaddr_dl, sdl_data) + addr->sdl_nlen + addr->sdl_alen + addr->sdl_slen)) {
01349 CATSEP;
01350 rb_str_catf(ret, "(%d bytes for %d bytes sockaddr_dl)",
01351 (int)socklen, (int)sizeof(struct sockaddr_dl));
01352 }
01353
01354 rb_str_cat2(ret, "]");
01355 #undef CATSEP
01356 break;
01357 }
01358 #endif
01359
01360 default:
01361 {
01362 ID id = rsock_intern_family(sockaddr->addr.sa_family);
01363 if (id == 0)
01364 rb_str_catf(ret, "unknown address family %d", sockaddr->addr.sa_family);
01365 else
01366 rb_str_catf(ret, "%s address format unknown", rb_id2name(id));
01367 break;
01368 }
01369 }
01370 }
01371
01372 return ret;
01373 }
01374
01375
01376
01377
01378
01379
01380
01381
01382
01383
01384
01385 static VALUE
01386 addrinfo_inspect(VALUE self)
01387 {
01388 rb_addrinfo_t *rai = get_addrinfo(self);
01389 int internet_p;
01390 VALUE ret;
01391
01392 ret = rb_sprintf("#<%s: ", rb_obj_classname(self));
01393
01394 inspect_sockaddr(self, ret);
01395
01396 if (rai->pfamily && ai_get_afamily(rai) != rai->pfamily) {
01397 ID id = rsock_intern_protocol_family(rai->pfamily);
01398 if (id)
01399 rb_str_catf(ret, " %s", rb_id2name(id));
01400 else
01401 rb_str_catf(ret, " PF_\?\?\?(%d)", rai->pfamily);
01402 }
01403
01404 internet_p = rai->pfamily == PF_INET;
01405 #ifdef INET6
01406 internet_p = internet_p || rai->pfamily == PF_INET6;
01407 #endif
01408 if (internet_p && rai->socktype == SOCK_STREAM &&
01409 (rai->protocol == 0 || rai->protocol == IPPROTO_TCP)) {
01410 rb_str_cat2(ret, " TCP");
01411 }
01412 else if (internet_p && rai->socktype == SOCK_DGRAM &&
01413 (rai->protocol == 0 || rai->protocol == IPPROTO_UDP)) {
01414 rb_str_cat2(ret, " UDP");
01415 }
01416 else {
01417 if (rai->socktype) {
01418 ID id = rsock_intern_socktype(rai->socktype);
01419 if (id)
01420 rb_str_catf(ret, " %s", rb_id2name(id));
01421 else
01422 rb_str_catf(ret, " SOCK_\?\?\?(%d)", rai->socktype);
01423 }
01424
01425 if (rai->protocol) {
01426 if (internet_p) {
01427 ID id = rsock_intern_ipproto(rai->protocol);
01428 if (id)
01429 rb_str_catf(ret, " %s", rb_id2name(id));
01430 else
01431 goto unknown_protocol;
01432 }
01433 else {
01434 unknown_protocol:
01435 rb_str_catf(ret, " UNKNOWN_PROTOCOL(%d)", rai->protocol);
01436 }
01437 }
01438 }
01439
01440 if (!NIL_P(rai->canonname)) {
01441 VALUE name = rai->canonname;
01442 rb_str_catf(ret, " %s", StringValueCStr(name));
01443 }
01444
01445 if (!NIL_P(rai->inspectname)) {
01446 VALUE name = rai->inspectname;
01447 rb_str_catf(ret, " (%s)", StringValueCStr(name));
01448 }
01449
01450 rb_str_buf_cat2(ret, ">");
01451 return ret;
01452 }
01453
01454
01455
01456
01457
01458
01459
01460
01461
01462
01463
01464
01465 VALUE
01466 rsock_addrinfo_inspect_sockaddr(VALUE self)
01467 {
01468 return inspect_sockaddr(self, rb_str_new("", 0));
01469 }
01470
01471
01472 static VALUE
01473 addrinfo_mdump(VALUE self)
01474 {
01475 rb_addrinfo_t *rai = get_addrinfo(self);
01476 VALUE sockaddr, afamily, pfamily, socktype, protocol, canonname, inspectname;
01477 int afamily_int = ai_get_afamily(rai);
01478 ID id;
01479
01480 id = rsock_intern_protocol_family(rai->pfamily);
01481 if (id == 0)
01482 rb_raise(rb_eSocket, "unknown protocol family: %d", rai->pfamily);
01483 pfamily = rb_id2str(id);
01484
01485 if (rai->socktype == 0)
01486 socktype = INT2FIX(0);
01487 else {
01488 id = rsock_intern_socktype(rai->socktype);
01489 if (id == 0)
01490 rb_raise(rb_eSocket, "unknown socktype: %d", rai->socktype);
01491 socktype = rb_id2str(id);
01492 }
01493
01494 if (rai->protocol == 0)
01495 protocol = INT2FIX(0);
01496 else if (IS_IP_FAMILY(afamily_int)) {
01497 id = rsock_intern_ipproto(rai->protocol);
01498 if (id == 0)
01499 rb_raise(rb_eSocket, "unknown IP protocol: %d", rai->protocol);
01500 protocol = rb_id2str(id);
01501 }
01502 else {
01503 rb_raise(rb_eSocket, "unknown protocol: %d", rai->protocol);
01504 }
01505
01506 canonname = rai->canonname;
01507
01508 inspectname = rai->inspectname;
01509
01510 id = rsock_intern_family(afamily_int);
01511 if (id == 0)
01512 rb_raise(rb_eSocket, "unknown address family: %d", afamily_int);
01513 afamily = rb_id2str(id);
01514
01515 switch(afamily_int) {
01516 #ifdef HAVE_SYS_UN_H
01517 case AF_UNIX:
01518 {
01519 struct sockaddr_un *su = &rai->addr.un;
01520 char *s, *e;
01521 s = su->sun_path;
01522 e = (char*)su + rai->sockaddr_len;
01523 while (s < e && *(e-1) == '\0')
01524 e--;
01525 sockaddr = rb_str_new(s, e-s);
01526 break;
01527 }
01528 #endif
01529
01530 default:
01531 {
01532 char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
01533 int error;
01534 error = getnameinfo(&rai->addr.addr, rai->sockaddr_len,
01535 hbuf, (socklen_t)sizeof(hbuf), pbuf, (socklen_t)sizeof(pbuf),
01536 NI_NUMERICHOST|NI_NUMERICSERV);
01537 if (error) {
01538 rsock_raise_socket_error("getnameinfo", error);
01539 }
01540 sockaddr = rb_assoc_new(rb_str_new_cstr(hbuf), rb_str_new_cstr(pbuf));
01541 break;
01542 }
01543 }
01544
01545 return rb_ary_new3(7, afamily, sockaddr, pfamily, socktype, protocol, canonname, inspectname);
01546 }
01547
01548
01549 static VALUE
01550 addrinfo_mload(VALUE self, VALUE ary)
01551 {
01552 VALUE v;
01553 VALUE canonname, inspectname;
01554 int afamily, pfamily, socktype, protocol;
01555 union_sockaddr ss;
01556 socklen_t len;
01557 rb_addrinfo_t *rai;
01558
01559 if (check_addrinfo(self))
01560 rb_raise(rb_eTypeError, "already initialized socket address");
01561
01562 ary = rb_convert_type(ary, T_ARRAY, "Array", "to_ary");
01563
01564 v = rb_ary_entry(ary, 0);
01565 StringValue(v);
01566 if (rsock_family_to_int(RSTRING_PTR(v), RSTRING_LEN(v), &afamily) == -1)
01567 rb_raise(rb_eTypeError, "unexpected address family");
01568
01569 v = rb_ary_entry(ary, 2);
01570 StringValue(v);
01571 if (rsock_family_to_int(RSTRING_PTR(v), RSTRING_LEN(v), &pfamily) == -1)
01572 rb_raise(rb_eTypeError, "unexpected protocol family");
01573
01574 v = rb_ary_entry(ary, 3);
01575 if (v == INT2FIX(0))
01576 socktype = 0;
01577 else {
01578 StringValue(v);
01579 if (rsock_socktype_to_int(RSTRING_PTR(v), RSTRING_LEN(v), &socktype) == -1)
01580 rb_raise(rb_eTypeError, "unexpected socktype");
01581 }
01582
01583 v = rb_ary_entry(ary, 4);
01584 if (v == INT2FIX(0))
01585 protocol = 0;
01586 else {
01587 StringValue(v);
01588 if (IS_IP_FAMILY(afamily)) {
01589 if (rsock_ipproto_to_int(RSTRING_PTR(v), RSTRING_LEN(v), &protocol) == -1)
01590 rb_raise(rb_eTypeError, "unexpected protocol");
01591 }
01592 else {
01593 rb_raise(rb_eTypeError, "unexpected protocol");
01594 }
01595 }
01596
01597 v = rb_ary_entry(ary, 5);
01598 if (NIL_P(v))
01599 canonname = Qnil;
01600 else {
01601 StringValue(v);
01602 canonname = v;
01603 }
01604
01605 v = rb_ary_entry(ary, 6);
01606 if (NIL_P(v))
01607 inspectname = Qnil;
01608 else {
01609 StringValue(v);
01610 inspectname = v;
01611 }
01612
01613 v = rb_ary_entry(ary, 1);
01614 switch(afamily) {
01615 #ifdef HAVE_SYS_UN_H
01616 case AF_UNIX:
01617 {
01618 struct sockaddr_un uaddr;
01619 INIT_SOCKADDR_UN(&uaddr, sizeof(struct sockaddr_un));
01620
01621 StringValue(v);
01622 if (sizeof(uaddr.sun_path) < (size_t)RSTRING_LEN(v))
01623 rb_raise(rb_eSocket,
01624 "too long AF_UNIX path (%"PRIuSIZE" bytes given but %"PRIuSIZE" bytes max)",
01625 (size_t)RSTRING_LEN(v), sizeof(uaddr.sun_path));
01626 memcpy(uaddr.sun_path, RSTRING_PTR(v), RSTRING_LEN(v));
01627 len = (socklen_t)sizeof(uaddr);
01628 memcpy(&ss, &uaddr, len);
01629 break;
01630 }
01631 #endif
01632
01633 default:
01634 {
01635 VALUE pair = rb_convert_type(v, T_ARRAY, "Array", "to_ary");
01636 struct rb_addrinfo *res;
01637 int flags = AI_NUMERICHOST;
01638 #ifdef AI_NUMERICSERV
01639 flags |= AI_NUMERICSERV;
01640 #endif
01641 res = call_getaddrinfo(rb_ary_entry(pair, 0), rb_ary_entry(pair, 1),
01642 INT2NUM(pfamily), INT2NUM(socktype), INT2NUM(protocol),
01643 INT2NUM(flags), 1);
01644
01645 len = res->ai->ai_addrlen;
01646 memcpy(&ss, res->ai->ai_addr, res->ai->ai_addrlen);
01647 rb_freeaddrinfo(res);
01648 break;
01649 }
01650 }
01651
01652 DATA_PTR(self) = rai = alloc_addrinfo();
01653 init_addrinfo(rai, &ss.addr, len,
01654 pfamily, socktype, protocol,
01655 canonname, inspectname);
01656 return self;
01657 }
01658
01659
01660
01661
01662
01663
01664
01665
01666
01667
01668 static VALUE
01669 addrinfo_afamily(VALUE self)
01670 {
01671 rb_addrinfo_t *rai = get_addrinfo(self);
01672 return INT2NUM(ai_get_afamily(rai));
01673 }
01674
01675
01676
01677
01678
01679
01680
01681
01682
01683
01684 static VALUE
01685 addrinfo_pfamily(VALUE self)
01686 {
01687 rb_addrinfo_t *rai = get_addrinfo(self);
01688 return INT2NUM(rai->pfamily);
01689 }
01690
01691
01692
01693
01694
01695
01696
01697
01698
01699
01700 static VALUE
01701 addrinfo_socktype(VALUE self)
01702 {
01703 rb_addrinfo_t *rai = get_addrinfo(self);
01704 return INT2NUM(rai->socktype);
01705 }
01706
01707
01708
01709
01710
01711
01712
01713
01714
01715
01716 static VALUE
01717 addrinfo_protocol(VALUE self)
01718 {
01719 rb_addrinfo_t *rai = get_addrinfo(self);
01720 return INT2NUM(rai->protocol);
01721 }
01722
01723
01724
01725
01726
01727
01728
01729
01730
01731
01732
01733
01734 static VALUE
01735 addrinfo_to_sockaddr(VALUE self)
01736 {
01737 rb_addrinfo_t *rai = get_addrinfo(self);
01738 VALUE ret;
01739 ret = rb_str_new((char*)&rai->addr, rai->sockaddr_len);
01740 OBJ_INFECT(ret, self);
01741 return ret;
01742 }
01743
01744
01745
01746
01747
01748
01749
01750
01751
01752
01753
01754
01755
01756
01757
01758
01759 static VALUE
01760 addrinfo_canonname(VALUE self)
01761 {
01762 rb_addrinfo_t *rai = get_addrinfo(self);
01763 return rai->canonname;
01764 }
01765
01766
01767
01768
01769
01770
01771
01772
01773
01774
01775
01776
01777
01778 static VALUE
01779 addrinfo_ip_p(VALUE self)
01780 {
01781 rb_addrinfo_t *rai = get_addrinfo(self);
01782 int family = ai_get_afamily(rai);
01783 return IS_IP_FAMILY(family) ? Qtrue : Qfalse;
01784 }
01785
01786
01787
01788
01789
01790
01791
01792
01793
01794
01795
01796
01797
01798 static VALUE
01799 addrinfo_ipv4_p(VALUE self)
01800 {
01801 rb_addrinfo_t *rai = get_addrinfo(self);
01802 return ai_get_afamily(rai) == AF_INET ? Qtrue : Qfalse;
01803 }
01804
01805
01806
01807
01808
01809
01810
01811
01812
01813
01814
01815
01816
01817 static VALUE
01818 addrinfo_ipv6_p(VALUE self)
01819 {
01820 #ifdef AF_INET6
01821 rb_addrinfo_t *rai = get_addrinfo(self);
01822 return ai_get_afamily(rai) == AF_INET6 ? Qtrue : Qfalse;
01823 #else
01824 return Qfalse;
01825 #endif
01826 }
01827
01828
01829
01830
01831
01832
01833
01834
01835
01836
01837
01838
01839
01840 static VALUE
01841 addrinfo_unix_p(VALUE self)
01842 {
01843 rb_addrinfo_t *rai = get_addrinfo(self);
01844 #ifdef AF_UNIX
01845 return ai_get_afamily(rai) == AF_UNIX ? Qtrue : Qfalse;
01846 #else
01847 return Qfalse;
01848 #endif
01849 }
01850
01851
01852
01853
01854
01855
01856
01857
01858
01859
01860
01861
01862
01863
01864
01865
01866 static VALUE
01867 addrinfo_getnameinfo(int argc, VALUE *argv, VALUE self)
01868 {
01869 rb_addrinfo_t *rai = get_addrinfo(self);
01870 VALUE vflags;
01871 char hbuf[1024], pbuf[1024];
01872 int flags, error;
01873
01874 rb_scan_args(argc, argv, "01", &vflags);
01875
01876 flags = NIL_P(vflags) ? 0 : NUM2INT(vflags);
01877
01878 if (rai->socktype == SOCK_DGRAM)
01879 flags |= NI_DGRAM;
01880
01881 error = getnameinfo(&rai->addr.addr, rai->sockaddr_len,
01882 hbuf, (socklen_t)sizeof(hbuf), pbuf, (socklen_t)sizeof(pbuf),
01883 flags);
01884 if (error) {
01885 rsock_raise_socket_error("getnameinfo", error);
01886 }
01887
01888 return rb_assoc_new(rb_str_new2(hbuf), rb_str_new2(pbuf));
01889 }
01890
01891
01892
01893
01894
01895
01896
01897
01898
01899
01900 static VALUE
01901 addrinfo_ip_unpack(VALUE self)
01902 {
01903 rb_addrinfo_t *rai = get_addrinfo(self);
01904 int family = ai_get_afamily(rai);
01905 VALUE vflags;
01906 VALUE ret, portstr;
01907
01908 if (!IS_IP_FAMILY(family))
01909 rb_raise(rb_eSocket, "need IPv4 or IPv6 address");
01910
01911 vflags = INT2NUM(NI_NUMERICHOST|NI_NUMERICSERV);
01912 ret = addrinfo_getnameinfo(1, &vflags, self);
01913 portstr = rb_ary_entry(ret, 1);
01914 rb_ary_store(ret, 1, INT2NUM(atoi(StringValueCStr(portstr))));
01915 return ret;
01916 }
01917
01918
01919
01920
01921
01922
01923
01924
01925
01926
01927 static VALUE
01928 addrinfo_ip_address(VALUE self)
01929 {
01930 rb_addrinfo_t *rai = get_addrinfo(self);
01931 int family = ai_get_afamily(rai);
01932 VALUE vflags;
01933 VALUE ret;
01934
01935 if (!IS_IP_FAMILY(family))
01936 rb_raise(rb_eSocket, "need IPv4 or IPv6 address");
01937
01938 vflags = INT2NUM(NI_NUMERICHOST|NI_NUMERICSERV);
01939 ret = addrinfo_getnameinfo(1, &vflags, self);
01940 return rb_ary_entry(ret, 0);
01941 }
01942
01943
01944
01945
01946
01947
01948
01949
01950
01951
01952 static VALUE
01953 addrinfo_ip_port(VALUE self)
01954 {
01955 rb_addrinfo_t *rai = get_addrinfo(self);
01956 int family = ai_get_afamily(rai);
01957 int port;
01958
01959 if (!IS_IP_FAMILY(family)) {
01960 bad_family:
01961 #ifdef AF_INET6
01962 rb_raise(rb_eSocket, "need IPv4 or IPv6 address");
01963 #else
01964 rb_raise(rb_eSocket, "need IPv4 address");
01965 #endif
01966 }
01967
01968 switch (family) {
01969 case AF_INET:
01970 if (rai->sockaddr_len != sizeof(struct sockaddr_in))
01971 rb_raise(rb_eSocket, "unexpected sockaddr size for IPv4");
01972 port = ntohs(rai->addr.in.sin_port);
01973 break;
01974
01975 #ifdef AF_INET6
01976 case AF_INET6:
01977 if (rai->sockaddr_len != sizeof(struct sockaddr_in6))
01978 rb_raise(rb_eSocket, "unexpected sockaddr size for IPv6");
01979 port = ntohs(rai->addr.in6.sin6_port);
01980 break;
01981 #endif
01982
01983 default:
01984 goto bad_family;
01985 }
01986
01987 return INT2NUM(port);
01988 }
01989
01990 static int
01991 extract_in_addr(VALUE self, uint32_t *addrp)
01992 {
01993 rb_addrinfo_t *rai = get_addrinfo(self);
01994 int family = ai_get_afamily(rai);
01995 if (family != AF_INET) return 0;
01996 *addrp = ntohl(rai->addr.in.sin_addr.s_addr);
01997 return 1;
01998 }
01999
02000
02001
02002
02003
02004 static VALUE
02005 addrinfo_ipv4_private_p(VALUE self)
02006 {
02007 uint32_t a;
02008 if (!extract_in_addr(self, &a)) return Qfalse;
02009 if ((a & 0xff000000) == 0x0a000000 ||
02010 (a & 0xfff00000) == 0xac100000 ||
02011 (a & 0xffff0000) == 0xc0a80000)
02012 return Qtrue;
02013 return Qfalse;
02014 }
02015
02016
02017
02018
02019
02020 static VALUE
02021 addrinfo_ipv4_loopback_p(VALUE self)
02022 {
02023 uint32_t a;
02024 if (!extract_in_addr(self, &a)) return Qfalse;
02025 if ((a & 0xff000000) == 0x7f000000)
02026 return Qtrue;
02027 return Qfalse;
02028 }
02029
02030
02031
02032
02033
02034 static VALUE
02035 addrinfo_ipv4_multicast_p(VALUE self)
02036 {
02037 uint32_t a;
02038 if (!extract_in_addr(self, &a)) return Qfalse;
02039 if ((a & 0xf0000000) == 0xe0000000)
02040 return Qtrue;
02041 return Qfalse;
02042 }
02043
02044 #ifdef INET6
02045
02046 static struct in6_addr *
02047 extract_in6_addr(VALUE self)
02048 {
02049 rb_addrinfo_t *rai = get_addrinfo(self);
02050 int family = ai_get_afamily(rai);
02051 if (family != AF_INET6) return NULL;
02052 return &rai->addr.in6.sin6_addr;
02053 }
02054
02055
02056
02057
02058
02059 static VALUE
02060 addrinfo_ipv6_unspecified_p(VALUE self)
02061 {
02062 struct in6_addr *addr = extract_in6_addr(self);
02063 if (addr && IN6_IS_ADDR_UNSPECIFIED(addr)) return Qtrue;
02064 return Qfalse;
02065 }
02066
02067
02068
02069
02070
02071 static VALUE
02072 addrinfo_ipv6_loopback_p(VALUE self)
02073 {
02074 struct in6_addr *addr = extract_in6_addr(self);
02075 if (addr && IN6_IS_ADDR_LOOPBACK(addr)) return Qtrue;
02076 return Qfalse;
02077 }
02078
02079
02080
02081
02082
02083 static VALUE
02084 addrinfo_ipv6_multicast_p(VALUE self)
02085 {
02086 struct in6_addr *addr = extract_in6_addr(self);
02087 if (addr && IN6_IS_ADDR_MULTICAST(addr)) return Qtrue;
02088 return Qfalse;
02089 }
02090
02091
02092
02093
02094
02095 static VALUE
02096 addrinfo_ipv6_linklocal_p(VALUE self)
02097 {
02098 struct in6_addr *addr = extract_in6_addr(self);
02099 if (addr && IN6_IS_ADDR_LINKLOCAL(addr)) return Qtrue;
02100 return Qfalse;
02101 }
02102
02103
02104
02105
02106
02107 static VALUE
02108 addrinfo_ipv6_sitelocal_p(VALUE self)
02109 {
02110 struct in6_addr *addr = extract_in6_addr(self);
02111 if (addr && IN6_IS_ADDR_SITELOCAL(addr)) return Qtrue;
02112 return Qfalse;
02113 }
02114
02115
02116
02117
02118
02119 static VALUE
02120 addrinfo_ipv6_unique_local_p(VALUE self)
02121 {
02122 struct in6_addr *addr = extract_in6_addr(self);
02123 if (addr && IN6_IS_ADDR_UNIQUE_LOCAL(addr)) return Qtrue;
02124 return Qfalse;
02125 }
02126
02127
02128
02129
02130
02131 static VALUE
02132 addrinfo_ipv6_v4mapped_p(VALUE self)
02133 {
02134 struct in6_addr *addr = extract_in6_addr(self);
02135 if (addr && IN6_IS_ADDR_V4MAPPED(addr)) return Qtrue;
02136 return Qfalse;
02137 }
02138
02139
02140
02141
02142
02143 static VALUE
02144 addrinfo_ipv6_v4compat_p(VALUE self)
02145 {
02146 struct in6_addr *addr = extract_in6_addr(self);
02147 if (addr && IN6_IS_ADDR_V4COMPAT(addr)) return Qtrue;
02148 return Qfalse;
02149 }
02150
02151
02152
02153
02154
02155 static VALUE
02156 addrinfo_ipv6_mc_nodelocal_p(VALUE self)
02157 {
02158 struct in6_addr *addr = extract_in6_addr(self);
02159 if (addr && IN6_IS_ADDR_MC_NODELOCAL(addr)) return Qtrue;
02160 return Qfalse;
02161 }
02162
02163
02164
02165
02166
02167 static VALUE
02168 addrinfo_ipv6_mc_linklocal_p(VALUE self)
02169 {
02170 struct in6_addr *addr = extract_in6_addr(self);
02171 if (addr && IN6_IS_ADDR_MC_LINKLOCAL(addr)) return Qtrue;
02172 return Qfalse;
02173 }
02174
02175
02176
02177
02178
02179 static VALUE
02180 addrinfo_ipv6_mc_sitelocal_p(VALUE self)
02181 {
02182 struct in6_addr *addr = extract_in6_addr(self);
02183 if (addr && IN6_IS_ADDR_MC_SITELOCAL(addr)) return Qtrue;
02184 return Qfalse;
02185 }
02186
02187
02188
02189
02190
02191 static VALUE
02192 addrinfo_ipv6_mc_orglocal_p(VALUE self)
02193 {
02194 struct in6_addr *addr = extract_in6_addr(self);
02195 if (addr && IN6_IS_ADDR_MC_ORGLOCAL(addr)) return Qtrue;
02196 return Qfalse;
02197 }
02198
02199
02200
02201
02202
02203 static VALUE
02204 addrinfo_ipv6_mc_global_p(VALUE self)
02205 {
02206 struct in6_addr *addr = extract_in6_addr(self);
02207 if (addr && IN6_IS_ADDR_MC_GLOBAL(addr)) return Qtrue;
02208 return Qfalse;
02209 }
02210
02211
02212
02213
02214
02215
02216
02217
02218
02219
02220
02221 static VALUE
02222 addrinfo_ipv6_to_ipv4(VALUE self)
02223 {
02224 rb_addrinfo_t *rai = get_addrinfo(self);
02225 struct in6_addr *addr;
02226 int family = ai_get_afamily(rai);
02227 if (family != AF_INET6) return Qnil;
02228 addr = &rai->addr.in6.sin6_addr;
02229 if (IN6_IS_ADDR_V4MAPPED(addr) || IN6_IS_ADDR_V4COMPAT(addr)) {
02230 struct sockaddr_in sin4;
02231 INIT_SOCKADDR_IN(&sin4, sizeof(sin4));
02232 memcpy(&sin4.sin_addr, (char*)addr + sizeof(*addr) - sizeof(sin4.sin_addr), sizeof(sin4.sin_addr));
02233 return rsock_addrinfo_new((struct sockaddr *)&sin4, (socklen_t)sizeof(sin4),
02234 PF_INET, rai->socktype, rai->protocol,
02235 rai->canonname, rai->inspectname);
02236 }
02237 else {
02238 return Qnil;
02239 }
02240 }
02241
02242 #endif
02243
02244 #ifdef HAVE_SYS_UN_H
02245
02246
02247
02248
02249
02250
02251
02252
02253 static VALUE
02254 addrinfo_unix_path(VALUE self)
02255 {
02256 rb_addrinfo_t *rai = get_addrinfo(self);
02257 int family = ai_get_afamily(rai);
02258 struct sockaddr_un *addr;
02259 char *s, *e;
02260
02261 if (family != AF_UNIX)
02262 rb_raise(rb_eSocket, "need AF_UNIX address");
02263
02264 addr = &rai->addr.un;
02265
02266 s = addr->sun_path;
02267 e = (char*)addr + rai->sockaddr_len;
02268 if (e < s)
02269 rb_raise(rb_eSocket, "too short AF_UNIX address: %"PRIuSIZE" bytes given for minimum %"PRIuSIZE" bytes.",
02270 (size_t)rai->sockaddr_len, (size_t)(s - (char *)addr));
02271 if (addr->sun_path + sizeof(addr->sun_path) < e)
02272 rb_raise(rb_eSocket,
02273 "too long AF_UNIX path (%"PRIuSIZE" bytes given but %"PRIuSIZE" bytes max)",
02274 (size_t)(e - addr->sun_path), sizeof(addr->sun_path));
02275 while (s < e && *(e-1) == '\0')
02276 e--;
02277 return rb_str_new(s, e-s);
02278 }
02279 #endif
02280
02281
02282
02283
02284
02285
02286
02287
02288
02289
02290
02291
02292
02293
02294
02295
02296
02297
02298
02299
02300
02301
02302
02303
02304
02305
02306
02307
02308
02309
02310
02311
02312
02313
02314
02315
02316
02317
02318
02319
02320
02321
02322
02323
02324 static VALUE
02325 addrinfo_s_getaddrinfo(int argc, VALUE *argv, VALUE self)
02326 {
02327 VALUE node, service, family, socktype, protocol, flags;
02328
02329 rb_scan_args(argc, argv, "24", &node, &service, &family, &socktype, &protocol, &flags);
02330 return addrinfo_list_new(node, service, family, socktype, protocol, flags);
02331 }
02332
02333
02334
02335
02336
02337
02338
02339
02340
02341
02342
02343
02344 static VALUE
02345 addrinfo_s_ip(VALUE self, VALUE host)
02346 {
02347 VALUE ret;
02348 rb_addrinfo_t *rai;
02349 ret = addrinfo_firstonly_new(host, Qnil,
02350 INT2NUM(PF_UNSPEC), INT2FIX(0), INT2FIX(0), INT2FIX(0));
02351 rai = get_addrinfo(ret);
02352 rai->socktype = 0;
02353 rai->protocol = 0;
02354 return ret;
02355 }
02356
02357
02358
02359
02360
02361
02362
02363
02364
02365 static VALUE
02366 addrinfo_s_tcp(VALUE self, VALUE host, VALUE port)
02367 {
02368 return addrinfo_firstonly_new(host, port,
02369 INT2NUM(PF_UNSPEC), INT2NUM(SOCK_STREAM), INT2NUM(IPPROTO_TCP), INT2FIX(0));
02370 }
02371
02372
02373
02374
02375
02376
02377
02378
02379
02380 static VALUE
02381 addrinfo_s_udp(VALUE self, VALUE host, VALUE port)
02382 {
02383 return addrinfo_firstonly_new(host, port,
02384 INT2NUM(PF_UNSPEC), INT2NUM(SOCK_DGRAM), INT2NUM(IPPROTO_UDP), INT2FIX(0));
02385 }
02386
02387 #ifdef HAVE_SYS_UN_H
02388
02389
02390
02391
02392
02393
02394
02395
02396
02397
02398
02399
02400
02401 static VALUE
02402 addrinfo_s_unix(int argc, VALUE *argv, VALUE self)
02403 {
02404 VALUE path, vsocktype, addr;
02405 int socktype;
02406 rb_addrinfo_t *rai;
02407
02408 rb_scan_args(argc, argv, "11", &path, &vsocktype);
02409
02410 if (NIL_P(vsocktype))
02411 socktype = SOCK_STREAM;
02412 else
02413 socktype = rsock_socktype_arg(vsocktype);
02414
02415 addr = addrinfo_s_allocate(rb_cAddrinfo);
02416 DATA_PTR(addr) = rai = alloc_addrinfo();
02417 init_unix_addrinfo(rai, path, socktype);
02418 OBJ_INFECT(addr, path);
02419 return addr;
02420 }
02421
02422 #endif
02423
02424 VALUE
02425 rsock_sockaddr_string_value(volatile VALUE *v)
02426 {
02427 VALUE val = *v;
02428 if (IS_ADDRINFO(val)) {
02429 *v = addrinfo_to_sockaddr(val);
02430 }
02431 StringValue(*v);
02432 return *v;
02433 }
02434
02435 VALUE
02436 rsock_sockaddr_string_value_with_addrinfo(volatile VALUE *v, VALUE *rai_ret)
02437 {
02438 VALUE val = *v;
02439 *rai_ret = Qnil;
02440 if (IS_ADDRINFO(val)) {
02441 *v = addrinfo_to_sockaddr(val);
02442 *rai_ret = val;
02443 }
02444 StringValue(*v);
02445 return *v;
02446 }
02447
02448 char *
02449 rsock_sockaddr_string_value_ptr(volatile VALUE *v)
02450 {
02451 rsock_sockaddr_string_value(v);
02452 return RSTRING_PTR(*v);
02453 }
02454
02455 VALUE
02456 rb_check_sockaddr_string_type(VALUE val)
02457 {
02458 if (IS_ADDRINFO(val))
02459 return addrinfo_to_sockaddr(val);
02460 return rb_check_string_type(val);
02461 }
02462
02463 VALUE
02464 rsock_fd_socket_addrinfo(int fd, struct sockaddr *addr, socklen_t len)
02465 {
02466 int family;
02467 int socktype;
02468 int ret;
02469 socklen_t optlen = (socklen_t)sizeof(socktype);
02470
02471
02472 family = get_afamily(addr, len);
02473
02474 ret = getsockopt(fd, SOL_SOCKET, SO_TYPE, (void*)&socktype, &optlen);
02475 if (ret == -1) {
02476 rb_sys_fail("getsockopt(SO_TYPE)");
02477 }
02478
02479 return rsock_addrinfo_new(addr, len, family, socktype, 0, Qnil, Qnil);
02480 }
02481
02482 VALUE
02483 rsock_io_socket_addrinfo(VALUE io, struct sockaddr *addr, socklen_t len)
02484 {
02485 rb_io_t *fptr;
02486
02487 switch (TYPE(io)) {
02488 case T_FIXNUM:
02489 return rsock_fd_socket_addrinfo(FIX2INT(io), addr, len);
02490
02491 case T_BIGNUM:
02492 return rsock_fd_socket_addrinfo(NUM2INT(io), addr, len);
02493
02494 case T_FILE:
02495 GetOpenFile(io, fptr);
02496 return rsock_fd_socket_addrinfo(fptr->fd, addr, len);
02497
02498 default:
02499 rb_raise(rb_eTypeError, "neither IO nor file descriptor");
02500 }
02501
02502 UNREACHABLE;
02503 }
02504
02505
02506
02507
02508 void
02509 rsock_init_addrinfo(void)
02510 {
02511
02512
02513
02514
02515 rb_cAddrinfo = rb_define_class("Addrinfo", rb_cData);
02516 rb_define_alloc_func(rb_cAddrinfo, addrinfo_s_allocate);
02517 rb_define_method(rb_cAddrinfo, "initialize", addrinfo_initialize, -1);
02518 rb_define_method(rb_cAddrinfo, "inspect", addrinfo_inspect, 0);
02519 rb_define_method(rb_cAddrinfo, "inspect_sockaddr", rsock_addrinfo_inspect_sockaddr, 0);
02520 rb_define_singleton_method(rb_cAddrinfo, "getaddrinfo", addrinfo_s_getaddrinfo, -1);
02521 rb_define_singleton_method(rb_cAddrinfo, "ip", addrinfo_s_ip, 1);
02522 rb_define_singleton_method(rb_cAddrinfo, "tcp", addrinfo_s_tcp, 2);
02523 rb_define_singleton_method(rb_cAddrinfo, "udp", addrinfo_s_udp, 2);
02524 #ifdef HAVE_SYS_UN_H
02525 rb_define_singleton_method(rb_cAddrinfo, "unix", addrinfo_s_unix, -1);
02526 #endif
02527
02528 rb_define_method(rb_cAddrinfo, "afamily", addrinfo_afamily, 0);
02529 rb_define_method(rb_cAddrinfo, "pfamily", addrinfo_pfamily, 0);
02530 rb_define_method(rb_cAddrinfo, "socktype", addrinfo_socktype, 0);
02531 rb_define_method(rb_cAddrinfo, "protocol", addrinfo_protocol, 0);
02532 rb_define_method(rb_cAddrinfo, "canonname", addrinfo_canonname, 0);
02533
02534 rb_define_method(rb_cAddrinfo, "ipv4?", addrinfo_ipv4_p, 0);
02535 rb_define_method(rb_cAddrinfo, "ipv6?", addrinfo_ipv6_p, 0);
02536 rb_define_method(rb_cAddrinfo, "unix?", addrinfo_unix_p, 0);
02537
02538 rb_define_method(rb_cAddrinfo, "ip?", addrinfo_ip_p, 0);
02539 rb_define_method(rb_cAddrinfo, "ip_unpack", addrinfo_ip_unpack, 0);
02540 rb_define_method(rb_cAddrinfo, "ip_address", addrinfo_ip_address, 0);
02541 rb_define_method(rb_cAddrinfo, "ip_port", addrinfo_ip_port, 0);
02542
02543 rb_define_method(rb_cAddrinfo, "ipv4_private?", addrinfo_ipv4_private_p, 0);
02544 rb_define_method(rb_cAddrinfo, "ipv4_loopback?", addrinfo_ipv4_loopback_p, 0);
02545 rb_define_method(rb_cAddrinfo, "ipv4_multicast?", addrinfo_ipv4_multicast_p, 0);
02546
02547 #ifdef INET6
02548 rb_define_method(rb_cAddrinfo, "ipv6_unspecified?", addrinfo_ipv6_unspecified_p, 0);
02549 rb_define_method(rb_cAddrinfo, "ipv6_loopback?", addrinfo_ipv6_loopback_p, 0);
02550 rb_define_method(rb_cAddrinfo, "ipv6_multicast?", addrinfo_ipv6_multicast_p, 0);
02551 rb_define_method(rb_cAddrinfo, "ipv6_linklocal?", addrinfo_ipv6_linklocal_p, 0);
02552 rb_define_method(rb_cAddrinfo, "ipv6_sitelocal?", addrinfo_ipv6_sitelocal_p, 0);
02553 rb_define_method(rb_cAddrinfo, "ipv6_unique_local?", addrinfo_ipv6_unique_local_p, 0);
02554 rb_define_method(rb_cAddrinfo, "ipv6_v4mapped?", addrinfo_ipv6_v4mapped_p, 0);
02555 rb_define_method(rb_cAddrinfo, "ipv6_v4compat?", addrinfo_ipv6_v4compat_p, 0);
02556 rb_define_method(rb_cAddrinfo, "ipv6_mc_nodelocal?", addrinfo_ipv6_mc_nodelocal_p, 0);
02557 rb_define_method(rb_cAddrinfo, "ipv6_mc_linklocal?", addrinfo_ipv6_mc_linklocal_p, 0);
02558 rb_define_method(rb_cAddrinfo, "ipv6_mc_sitelocal?", addrinfo_ipv6_mc_sitelocal_p, 0);
02559 rb_define_method(rb_cAddrinfo, "ipv6_mc_orglocal?", addrinfo_ipv6_mc_orglocal_p, 0);
02560 rb_define_method(rb_cAddrinfo, "ipv6_mc_global?", addrinfo_ipv6_mc_global_p, 0);
02561
02562 rb_define_method(rb_cAddrinfo, "ipv6_to_ipv4", addrinfo_ipv6_to_ipv4, 0);
02563 #endif
02564
02565 #ifdef HAVE_SYS_UN_H
02566 rb_define_method(rb_cAddrinfo, "unix_path", addrinfo_unix_path, 0);
02567 #endif
02568
02569 rb_define_method(rb_cAddrinfo, "to_sockaddr", addrinfo_to_sockaddr, 0);
02570 rb_define_method(rb_cAddrinfo, "to_s", addrinfo_to_sockaddr, 0);
02571
02572 rb_define_method(rb_cAddrinfo, "getnameinfo", addrinfo_getnameinfo, -1);
02573
02574 rb_define_method(rb_cAddrinfo, "marshal_dump", addrinfo_mdump, 0);
02575 rb_define_method(rb_cAddrinfo, "marshal_load", addrinfo_mload, 1);
02576 }
02577