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 && (h = gethostbyname(addr->ai_canonname))) {
00621 names = rb_ary_new();
00622 if (h->h_aliases != NULL) {
00623 for (pch = h->h_aliases; *pch; pch++) {
00624 rb_ary_push(names, rb_str_new2(*pch));
00625 }
00626 }
00627 }
00628 else {
00629 names = rb_ary_new2(0);
00630 }
00631 rb_ary_push(ary, names);
00632 rb_ary_push(ary, INT2NUM(addr->ai_family));
00633 for (ai = addr; ai; ai = ai->ai_next) {
00634 rb_ary_push(ary, (*ipaddr)(ai->ai_addr, ai->ai_addrlen));
00635 }
00636
00637 return ary;
00638 }
00639
00640 VALUE
00641 rsock_freeaddrinfo(VALUE arg)
00642 {
00643 struct rb_addrinfo *addr = (struct rb_addrinfo *)arg;
00644 rb_freeaddrinfo(addr);
00645 return Qnil;
00646 }
00647
00648 VALUE
00649 rsock_make_hostent(VALUE host, struct rb_addrinfo *addr, VALUE (*ipaddr)(struct sockaddr *, socklen_t))
00650 {
00651 struct hostent_arg arg;
00652
00653 arg.host = host;
00654 arg.addr = addr;
00655 arg.ipaddr = ipaddr;
00656 return rb_ensure(make_hostent_internal, (VALUE)&arg,
00657 rsock_freeaddrinfo, (VALUE)addr);
00658 }
00659
00660 typedef struct {
00661 VALUE inspectname;
00662 VALUE canonname;
00663 int pfamily;
00664 int socktype;
00665 int protocol;
00666 socklen_t sockaddr_len;
00667 union_sockaddr addr;
00668 } rb_addrinfo_t;
00669
00670 static void
00671 addrinfo_mark(void *ptr)
00672 {
00673 rb_addrinfo_t *rai = ptr;
00674 if (rai) {
00675 rb_gc_mark(rai->inspectname);
00676 rb_gc_mark(rai->canonname);
00677 }
00678 }
00679
00680 #define addrinfo_free RUBY_TYPED_DEFAULT_FREE
00681
00682 static size_t
00683 addrinfo_memsize(const void *ptr)
00684 {
00685 return ptr ? sizeof(rb_addrinfo_t) : 0;
00686 }
00687
00688 static const rb_data_type_t addrinfo_type = {
00689 "socket/addrinfo",
00690 {addrinfo_mark, addrinfo_free, addrinfo_memsize,},
00691 };
00692
00693 static VALUE
00694 addrinfo_s_allocate(VALUE klass)
00695 {
00696 return TypedData_Wrap_Struct(klass, &addrinfo_type, 0);
00697 }
00698
00699 #define IS_ADDRINFO(obj) rb_typeddata_is_kind_of((obj), &addrinfo_type)
00700 static inline rb_addrinfo_t *
00701 check_addrinfo(VALUE self)
00702 {
00703 return rb_check_typeddata(self, &addrinfo_type);
00704 }
00705
00706 static rb_addrinfo_t *
00707 get_addrinfo(VALUE self)
00708 {
00709 rb_addrinfo_t *rai = check_addrinfo(self);
00710
00711 if (!rai) {
00712 rb_raise(rb_eTypeError, "uninitialized socket address");
00713 }
00714 return rai;
00715 }
00716
00717
00718 static rb_addrinfo_t *
00719 alloc_addrinfo()
00720 {
00721 rb_addrinfo_t *rai = ALLOC(rb_addrinfo_t);
00722 memset(rai, 0, sizeof(rb_addrinfo_t));
00723 rai->inspectname = Qnil;
00724 rai->canonname = Qnil;
00725 return rai;
00726 }
00727
00728 static void
00729 init_addrinfo(rb_addrinfo_t *rai, struct sockaddr *sa, socklen_t len,
00730 int pfamily, int socktype, int protocol,
00731 VALUE canonname, VALUE inspectname)
00732 {
00733 if ((socklen_t)sizeof(rai->addr) < len)
00734 rb_raise(rb_eArgError, "sockaddr string too big");
00735 memcpy((void *)&rai->addr, (void *)sa, len);
00736 rai->sockaddr_len = len;
00737
00738 rai->pfamily = pfamily;
00739 rai->socktype = socktype;
00740 rai->protocol = protocol;
00741 rai->canonname = canonname;
00742 rai->inspectname = inspectname;
00743 }
00744
00745 VALUE
00746 rsock_addrinfo_new(struct sockaddr *addr, socklen_t len,
00747 int family, int socktype, int protocol,
00748 VALUE canonname, VALUE inspectname)
00749 {
00750 VALUE a;
00751 rb_addrinfo_t *rai;
00752
00753 a = addrinfo_s_allocate(rb_cAddrinfo);
00754 DATA_PTR(a) = rai = alloc_addrinfo();
00755 init_addrinfo(rai, addr, len, family, socktype, protocol, canonname, inspectname);
00756 return a;
00757 }
00758
00759 static struct rb_addrinfo *
00760 call_getaddrinfo(VALUE node, VALUE service,
00761 VALUE family, VALUE socktype, VALUE protocol, VALUE flags,
00762 int socktype_hack)
00763 {
00764 struct addrinfo hints;
00765 struct rb_addrinfo *res;
00766
00767 MEMZERO(&hints, struct addrinfo, 1);
00768 hints.ai_family = NIL_P(family) ? PF_UNSPEC : rsock_family_arg(family);
00769
00770 if (!NIL_P(socktype)) {
00771 hints.ai_socktype = rsock_socktype_arg(socktype);
00772 }
00773 if (!NIL_P(protocol)) {
00774 hints.ai_protocol = NUM2INT(protocol);
00775 }
00776 if (!NIL_P(flags)) {
00777 hints.ai_flags = NUM2INT(flags);
00778 }
00779 res = rsock_getaddrinfo(node, service, &hints, socktype_hack);
00780
00781 if (res == NULL)
00782 rb_raise(rb_eSocket, "host not found");
00783 return res;
00784 }
00785
00786 static VALUE make_inspectname(VALUE node, VALUE service, struct addrinfo *res);
00787
00788 static void
00789 init_addrinfo_getaddrinfo(rb_addrinfo_t *rai, VALUE node, VALUE service,
00790 VALUE family, VALUE socktype, VALUE protocol, VALUE flags,
00791 VALUE inspectnode, VALUE inspectservice)
00792 {
00793 struct rb_addrinfo *res = call_getaddrinfo(node, service, family, socktype, protocol, flags, 1);
00794 VALUE canonname;
00795 VALUE inspectname = rb_str_equal(node, inspectnode) ? Qnil : make_inspectname(inspectnode, inspectservice, res->ai);
00796
00797 canonname = Qnil;
00798 if (res->ai->ai_canonname) {
00799 canonname = rb_tainted_str_new_cstr(res->ai->ai_canonname);
00800 OBJ_FREEZE(canonname);
00801 }
00802
00803 init_addrinfo(rai, res->ai->ai_addr, res->ai->ai_addrlen,
00804 NUM2INT(family), NUM2INT(socktype), NUM2INT(protocol),
00805 canonname, inspectname);
00806
00807 rb_freeaddrinfo(res);
00808 }
00809
00810 static VALUE
00811 make_inspectname(VALUE node, VALUE service, struct addrinfo *res)
00812 {
00813 VALUE inspectname = Qnil;
00814
00815 if (res) {
00816
00817 char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
00818 int ret;
00819 ret = rb_getnameinfo(res->ai_addr, res->ai_addrlen, hbuf,
00820 sizeof(hbuf), pbuf, sizeof(pbuf),
00821 NI_NUMERICHOST|NI_NUMERICSERV);
00822 if (ret == 0) {
00823 if (RB_TYPE_P(node, T_STRING) && strcmp(hbuf, RSTRING_PTR(node)) == 0)
00824 node = Qnil;
00825 if (RB_TYPE_P(service, T_STRING) && strcmp(pbuf, RSTRING_PTR(service)) == 0)
00826 service = Qnil;
00827 else if (RB_TYPE_P(service, T_FIXNUM) && atoi(pbuf) == FIX2INT(service))
00828 service = Qnil;
00829 }
00830 }
00831
00832 if (RB_TYPE_P(node, T_STRING)) {
00833 inspectname = rb_str_dup(node);
00834 }
00835 if (RB_TYPE_P(service, T_STRING)) {
00836 if (NIL_P(inspectname))
00837 inspectname = rb_sprintf(":%s", StringValueCStr(service));
00838 else
00839 rb_str_catf(inspectname, ":%s", StringValueCStr(service));
00840 }
00841 else if (RB_TYPE_P(service, T_FIXNUM) && FIX2INT(service) != 0)
00842 {
00843 if (NIL_P(inspectname))
00844 inspectname = rb_sprintf(":%d", FIX2INT(service));
00845 else
00846 rb_str_catf(inspectname, ":%d", FIX2INT(service));
00847 }
00848 if (!NIL_P(inspectname)) {
00849 OBJ_INFECT(inspectname, node);
00850 OBJ_INFECT(inspectname, service);
00851 OBJ_FREEZE(inspectname);
00852 }
00853 return inspectname;
00854 }
00855
00856 static VALUE
00857 addrinfo_firstonly_new(VALUE node, VALUE service, VALUE family, VALUE socktype, VALUE protocol, VALUE flags)
00858 {
00859 VALUE ret;
00860 VALUE canonname;
00861 VALUE inspectname;
00862
00863 struct rb_addrinfo *res = call_getaddrinfo(node, service, family, socktype, protocol, flags, 0);
00864
00865 inspectname = make_inspectname(node, service, res->ai);
00866
00867 canonname = Qnil;
00868 if (res->ai->ai_canonname) {
00869 canonname = rb_tainted_str_new_cstr(res->ai->ai_canonname);
00870 OBJ_FREEZE(canonname);
00871 }
00872
00873 ret = rsock_addrinfo_new(res->ai->ai_addr, res->ai->ai_addrlen,
00874 res->ai->ai_family, res->ai->ai_socktype,
00875 res->ai->ai_protocol,
00876 canonname, inspectname);
00877
00878 rb_freeaddrinfo(res);
00879 return ret;
00880 }
00881
00882 static VALUE
00883 addrinfo_list_new(VALUE node, VALUE service, VALUE family, VALUE socktype, VALUE protocol, VALUE flags)
00884 {
00885 VALUE ret;
00886 struct addrinfo *r;
00887 VALUE inspectname;
00888
00889 struct rb_addrinfo *res = call_getaddrinfo(node, service, family, socktype, protocol, flags, 0);
00890
00891 inspectname = make_inspectname(node, service, res->ai);
00892
00893 ret = rb_ary_new();
00894 for (r = res->ai; r; r = r->ai_next) {
00895 VALUE addr;
00896 VALUE canonname = Qnil;
00897
00898 if (r->ai_canonname) {
00899 canonname = rb_tainted_str_new_cstr(r->ai_canonname);
00900 OBJ_FREEZE(canonname);
00901 }
00902
00903 addr = rsock_addrinfo_new(r->ai_addr, r->ai_addrlen,
00904 r->ai_family, r->ai_socktype, r->ai_protocol,
00905 canonname, inspectname);
00906
00907 rb_ary_push(ret, addr);
00908 }
00909
00910 rb_freeaddrinfo(res);
00911 return ret;
00912 }
00913
00914
00915 #ifdef HAVE_SYS_UN_H
00916 static void
00917 init_unix_addrinfo(rb_addrinfo_t *rai, VALUE path, int socktype)
00918 {
00919 struct sockaddr_un un;
00920 socklen_t len;
00921
00922 StringValue(path);
00923
00924 if (sizeof(un.sun_path) < (size_t)RSTRING_LEN(path))
00925 rb_raise(rb_eArgError,
00926 "too long unix socket path (%"PRIuSIZE" bytes given but %"PRIuSIZE" bytes max)",
00927 (size_t)RSTRING_LEN(path), sizeof(un.sun_path));
00928
00929 INIT_SOCKADDR_UN(&un, sizeof(struct sockaddr_un));
00930 memcpy((void*)&un.sun_path, RSTRING_PTR(path), RSTRING_LEN(path));
00931
00932 len = rsock_unix_sockaddr_len(path);
00933 init_addrinfo(rai, (struct sockaddr *)&un, len,
00934 PF_UNIX, socktype, 0, Qnil, Qnil);
00935 }
00936 #endif
00937
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 static VALUE
00985 addrinfo_initialize(int argc, VALUE *argv, VALUE self)
00986 {
00987 rb_addrinfo_t *rai;
00988 VALUE sockaddr_arg, sockaddr_ary, pfamily, socktype, protocol;
00989 int i_pfamily, i_socktype, i_protocol;
00990 struct sockaddr *sockaddr_ptr;
00991 socklen_t sockaddr_len;
00992 VALUE canonname = Qnil, inspectname = Qnil;
00993
00994 if (check_addrinfo(self))
00995 rb_raise(rb_eTypeError, "already initialized socket address");
00996 DATA_PTR(self) = rai = alloc_addrinfo();
00997
00998 rb_scan_args(argc, argv, "13", &sockaddr_arg, &pfamily, &socktype, &protocol);
00999
01000 i_pfamily = NIL_P(pfamily) ? PF_UNSPEC : rsock_family_arg(pfamily);
01001 i_socktype = NIL_P(socktype) ? 0 : rsock_socktype_arg(socktype);
01002 i_protocol = NIL_P(protocol) ? 0 : NUM2INT(protocol);
01003
01004 sockaddr_ary = rb_check_array_type(sockaddr_arg);
01005 if (!NIL_P(sockaddr_ary)) {
01006 VALUE afamily = rb_ary_entry(sockaddr_ary, 0);
01007 int af;
01008 StringValue(afamily);
01009 if (rsock_family_to_int(RSTRING_PTR(afamily), RSTRING_LEN(afamily), &af) == -1)
01010 rb_raise(rb_eSocket, "unknown address family: %s", StringValueCStr(afamily));
01011 switch (af) {
01012 case AF_INET:
01013 #ifdef INET6
01014 case AF_INET6:
01015 #endif
01016 {
01017 VALUE service = rb_ary_entry(sockaddr_ary, 1);
01018 VALUE nodename = rb_ary_entry(sockaddr_ary, 2);
01019 VALUE numericnode = rb_ary_entry(sockaddr_ary, 3);
01020 int flags;
01021
01022 service = INT2NUM(NUM2INT(service));
01023 if (!NIL_P(nodename))
01024 StringValue(nodename);
01025 StringValue(numericnode);
01026 flags = AI_NUMERICHOST;
01027 #ifdef AI_NUMERICSERV
01028 flags |= AI_NUMERICSERV;
01029 #endif
01030
01031 init_addrinfo_getaddrinfo(rai, numericnode, service,
01032 INT2NUM(i_pfamily ? i_pfamily : af), INT2NUM(i_socktype), INT2NUM(i_protocol),
01033 INT2NUM(flags),
01034 nodename, service);
01035 break;
01036 }
01037
01038 #ifdef HAVE_SYS_UN_H
01039 case AF_UNIX:
01040 {
01041 VALUE path = rb_ary_entry(sockaddr_ary, 1);
01042 StringValue(path);
01043 init_unix_addrinfo(rai, path, SOCK_STREAM);
01044 break;
01045 }
01046 #endif
01047
01048 default:
01049 rb_raise(rb_eSocket, "unexpected address family");
01050 }
01051 }
01052 else {
01053 StringValue(sockaddr_arg);
01054 sockaddr_ptr = (struct sockaddr *)RSTRING_PTR(sockaddr_arg);
01055 sockaddr_len = RSTRING_SOCKLEN(sockaddr_arg);
01056 init_addrinfo(rai, sockaddr_ptr, sockaddr_len,
01057 i_pfamily, i_socktype, i_protocol,
01058 canonname, inspectname);
01059 }
01060
01061 return self;
01062 }
01063
01064 static int
01065 get_afamily(struct sockaddr *addr, socklen_t len)
01066 {
01067 if ((socklen_t)((char*)&addr->sa_family + sizeof(addr->sa_family) - (char*)addr) <= len)
01068 return addr->sa_family;
01069 else
01070 return AF_UNSPEC;
01071 }
01072
01073 static int
01074 ai_get_afamily(rb_addrinfo_t *rai)
01075 {
01076 return get_afamily(&rai->addr.addr, rai->sockaddr_len);
01077 }
01078
01079 static VALUE
01080 inspect_sockaddr(VALUE addrinfo, VALUE ret)
01081 {
01082 rb_addrinfo_t *rai = get_addrinfo(addrinfo);
01083 union_sockaddr *sockaddr = &rai->addr;
01084 socklen_t socklen = rai->sockaddr_len;
01085 return rsock_inspect_sockaddr((struct sockaddr *)sockaddr, socklen, ret);
01086 }
01087
01088 VALUE
01089 rsock_inspect_sockaddr(struct sockaddr *sockaddr_arg, socklen_t socklen, VALUE ret)
01090 {
01091 union_sockaddr *sockaddr = (union_sockaddr *)sockaddr_arg;
01092 if (socklen == 0) {
01093 rb_str_cat2(ret, "empty-sockaddr");
01094 }
01095 else if ((long)socklen < ((char*)&sockaddr->addr.sa_family + sizeof(sockaddr->addr.sa_family)) - (char*)sockaddr)
01096 rb_str_cat2(ret, "too-short-sockaddr");
01097 else {
01098 switch (sockaddr->addr.sa_family) {
01099 case AF_UNSPEC:
01100 {
01101 rb_str_cat2(ret, "UNSPEC");
01102 break;
01103 }
01104
01105 case AF_INET:
01106 {
01107 struct sockaddr_in *addr;
01108 int port;
01109 addr = &sockaddr->in;
01110 if ((socklen_t)(((char*)&addr->sin_addr)-(char*)addr+0+1) <= socklen)
01111 rb_str_catf(ret, "%d", ((unsigned char*)&addr->sin_addr)[0]);
01112 else
01113 rb_str_cat2(ret, "?");
01114 if ((socklen_t)(((char*)&addr->sin_addr)-(char*)addr+1+1) <= socklen)
01115 rb_str_catf(ret, ".%d", ((unsigned char*)&addr->sin_addr)[1]);
01116 else
01117 rb_str_cat2(ret, ".?");
01118 if ((socklen_t)(((char*)&addr->sin_addr)-(char*)addr+2+1) <= socklen)
01119 rb_str_catf(ret, ".%d", ((unsigned char*)&addr->sin_addr)[2]);
01120 else
01121 rb_str_cat2(ret, ".?");
01122 if ((socklen_t)(((char*)&addr->sin_addr)-(char*)addr+3+1) <= socklen)
01123 rb_str_catf(ret, ".%d", ((unsigned char*)&addr->sin_addr)[3]);
01124 else
01125 rb_str_cat2(ret, ".?");
01126
01127 if ((socklen_t)(((char*)&addr->sin_port)-(char*)addr+(int)sizeof(addr->sin_port)) < socklen) {
01128 port = ntohs(addr->sin_port);
01129 if (port)
01130 rb_str_catf(ret, ":%d", port);
01131 }
01132 else {
01133 rb_str_cat2(ret, ":?");
01134 }
01135 if ((socklen_t)sizeof(struct sockaddr_in) != socklen)
01136 rb_str_catf(ret, " (%d bytes for %d bytes sockaddr_in)",
01137 (int)socklen,
01138 (int)sizeof(struct sockaddr_in));
01139 break;
01140 }
01141
01142 #ifdef AF_INET6
01143 case AF_INET6:
01144 {
01145 struct sockaddr_in6 *addr;
01146 char hbuf[1024];
01147 int port;
01148 int error;
01149 if (socklen < (socklen_t)sizeof(struct sockaddr_in6)) {
01150 rb_str_catf(ret, "too-short-AF_INET6-sockaddr %d bytes", (int)socklen);
01151 }
01152 else {
01153 addr = &sockaddr->in6;
01154
01155
01156
01157
01158 error = getnameinfo(&sockaddr->addr, socklen,
01159 hbuf, (socklen_t)sizeof(hbuf), NULL, 0,
01160 NI_NUMERICHOST|NI_NUMERICSERV);
01161 if (error) {
01162 rsock_raise_socket_error("getnameinfo", error);
01163 }
01164 if (addr->sin6_port == 0) {
01165 rb_str_cat2(ret, hbuf);
01166 }
01167 else {
01168 port = ntohs(addr->sin6_port);
01169 rb_str_catf(ret, "[%s]:%d", hbuf, port);
01170 }
01171 if ((socklen_t)sizeof(struct sockaddr_in6) < socklen)
01172 rb_str_catf(ret, "(sockaddr %d bytes too long)", (int)(socklen - sizeof(struct sockaddr_in6)));
01173 }
01174 break;
01175 }
01176 #endif
01177
01178 #ifdef HAVE_SYS_UN_H
01179 case AF_UNIX:
01180 {
01181 struct sockaddr_un *addr = &sockaddr->un;
01182 char *p, *s, *e;
01183 s = addr->sun_path;
01184 e = (char*)addr + socklen;
01185 while (s < e && *(e-1) == '\0')
01186 e--;
01187 if (e < s)
01188 rb_str_cat2(ret, "too-short-AF_UNIX-sockaddr");
01189 else if (s == e)
01190 rb_str_cat2(ret, "empty-path-AF_UNIX-sockaddr");
01191 else {
01192 int printable_only = 1;
01193 p = s;
01194 while (p < e) {
01195 printable_only = printable_only && ISPRINT(*p) && !ISSPACE(*p);
01196 p++;
01197 }
01198 if (printable_only) {
01199 if (s[0] != '/')
01200 rb_str_cat2(ret, "UNIX ");
01201 rb_str_cat(ret, s, p - s);
01202 }
01203 else {
01204 rb_str_cat2(ret, "UNIX");
01205 while (s < e)
01206 rb_str_catf(ret, ":%02x", (unsigned char)*s++);
01207 }
01208 }
01209 break;
01210 }
01211 #endif
01212
01213 #ifdef AF_PACKET
01214
01215 case AF_PACKET:
01216 {
01217 struct sockaddr_ll *addr;
01218 const char *sep = "[";
01219 #define CATSEP do { rb_str_cat2(ret, sep); sep = " "; } while (0);
01220
01221 addr = (struct sockaddr_ll *)sockaddr;
01222
01223 rb_str_cat2(ret, "PACKET");
01224
01225 if (offsetof(struct sockaddr_ll, sll_protocol) + sizeof(addr->sll_protocol) <= (size_t)socklen) {
01226 CATSEP;
01227 rb_str_catf(ret, "protocol=%d", ntohs(addr->sll_protocol));
01228 }
01229 if (offsetof(struct sockaddr_ll, sll_ifindex) + sizeof(addr->sll_ifindex) <= (size_t)socklen) {
01230 char buf[IFNAMSIZ];
01231 CATSEP;
01232 if (if_indextoname(addr->sll_ifindex, buf) == NULL)
01233 rb_str_catf(ret, "ifindex=%d", addr->sll_ifindex);
01234 else
01235 rb_str_catf(ret, "%s", buf);
01236 }
01237 if (offsetof(struct sockaddr_ll, sll_hatype) + sizeof(addr->sll_hatype) <= (size_t)socklen) {
01238 CATSEP;
01239 rb_str_catf(ret, "hatype=%d", addr->sll_hatype);
01240 }
01241 if (offsetof(struct sockaddr_ll, sll_pkttype) + sizeof(addr->sll_pkttype) <= (size_t)socklen) {
01242 CATSEP;
01243 if (addr->sll_pkttype == PACKET_HOST)
01244 rb_str_cat2(ret, "HOST");
01245 else if (addr->sll_pkttype == PACKET_BROADCAST)
01246 rb_str_cat2(ret, "BROADCAST");
01247 else if (addr->sll_pkttype == PACKET_MULTICAST)
01248 rb_str_cat2(ret, "MULTICAST");
01249 else if (addr->sll_pkttype == PACKET_OTHERHOST)
01250 rb_str_cat2(ret, "OTHERHOST");
01251 else if (addr->sll_pkttype == PACKET_OUTGOING)
01252 rb_str_cat2(ret, "OUTGOING");
01253 else
01254 rb_str_catf(ret, "pkttype=%d", addr->sll_pkttype);
01255 }
01256 if (socklen != (socklen_t)(offsetof(struct sockaddr_ll, sll_addr) + addr->sll_halen)) {
01257 CATSEP;
01258 if (offsetof(struct sockaddr_ll, sll_halen) + sizeof(addr->sll_halen) <= (size_t)socklen) {
01259 rb_str_catf(ret, "halen=%d", addr->sll_halen);
01260 }
01261 }
01262 if (offsetof(struct sockaddr_ll, sll_addr) < (size_t)socklen) {
01263 socklen_t len, i;
01264 CATSEP;
01265 rb_str_cat2(ret, "hwaddr");
01266 len = addr->sll_halen;
01267 if ((size_t)socklen < offsetof(struct sockaddr_ll, sll_addr) + len)
01268 len = socklen - offsetof(struct sockaddr_ll, sll_addr);
01269 for (i = 0; i < len; i++) {
01270 rb_str_cat2(ret, i == 0 ? "=" : ":");
01271 rb_str_catf(ret, "%02x", addr->sll_addr[i]);
01272 }
01273 }
01274
01275 if (socklen < (socklen_t)(offsetof(struct sockaddr_ll, sll_halen) + sizeof(addr->sll_halen)) ||
01276 (socklen_t)(offsetof(struct sockaddr_ll, sll_addr) + addr->sll_halen) != socklen) {
01277 CATSEP;
01278 rb_str_catf(ret, "(%d bytes for %d bytes sockaddr_ll)",
01279 (int)socklen, (int)sizeof(struct sockaddr_ll));
01280 }
01281
01282 rb_str_cat2(ret, "]");
01283 #undef CATSEP
01284
01285 break;
01286 }
01287 #endif
01288
01289 #if defined(AF_LINK) && defined(HAVE_TYPE_STRUCT_SOCKADDR_DL)
01290
01291
01292
01293
01294 case AF_LINK:
01295 {
01296
01297
01298
01299
01300
01301
01302
01303
01304 struct sockaddr_dl *addr = &sockaddr->dl;
01305 char *np = NULL, *ap = NULL, *endp;
01306 int nlen = 0, alen = 0;
01307 int i, off;
01308 const char *sep = "[";
01309 #define CATSEP do { rb_str_cat2(ret, sep); sep = " "; } while (0);
01310
01311 rb_str_cat2(ret, "LINK");
01312
01313 endp = ((char *)addr) + socklen;
01314
01315 if (offsetof(struct sockaddr_dl, sdl_data) < socklen) {
01316 np = addr->sdl_data;
01317 nlen = addr->sdl_nlen;
01318 if (endp - np < nlen)
01319 nlen = (int)(endp - np);
01320 }
01321 off = addr->sdl_nlen;
01322
01323 if (offsetof(struct sockaddr_dl, sdl_data) + off < socklen) {
01324 ap = addr->sdl_data + off;
01325 alen = addr->sdl_alen;
01326 if (endp - ap < alen)
01327 alen = (int)(endp - ap);
01328 }
01329
01330 CATSEP;
01331 if (np)
01332 rb_str_catf(ret, "%.*s", nlen, np);
01333 else
01334 rb_str_cat2(ret, "?");
01335
01336 if (ap && 0 < alen) {
01337 CATSEP;
01338 for (i = 0; i < alen; i++)
01339 rb_str_catf(ret, "%s%02x", i == 0 ? "" : ":", (unsigned char)ap[i]);
01340 }
01341
01342 if (socklen < (socklen_t)(offsetof(struct sockaddr_dl, sdl_nlen) + sizeof(addr->sdl_nlen)) ||
01343 socklen < (socklen_t)(offsetof(struct sockaddr_dl, sdl_alen) + sizeof(addr->sdl_alen)) ||
01344 socklen < (socklen_t)(offsetof(struct sockaddr_dl, sdl_slen) + sizeof(addr->sdl_slen)) ||
01345
01346
01347 socklen < (socklen_t)(offsetof(struct sockaddr_dl, sdl_data) + addr->sdl_nlen + addr->sdl_alen + addr->sdl_slen)) {
01348 CATSEP;
01349 rb_str_catf(ret, "(%d bytes for %d bytes sockaddr_dl)",
01350 (int)socklen, (int)sizeof(struct sockaddr_dl));
01351 }
01352
01353 rb_str_cat2(ret, "]");
01354 #undef CATSEP
01355 break;
01356 }
01357 #endif
01358
01359 default:
01360 {
01361 ID id = rsock_intern_family(sockaddr->addr.sa_family);
01362 if (id == 0)
01363 rb_str_catf(ret, "unknown address family %d", sockaddr->addr.sa_family);
01364 else
01365 rb_str_catf(ret, "%s address format unknown", rb_id2name(id));
01366 break;
01367 }
01368 }
01369 }
01370
01371 return ret;
01372 }
01373
01374
01375
01376
01377
01378
01379
01380
01381
01382
01383
01384 static VALUE
01385 addrinfo_inspect(VALUE self)
01386 {
01387 rb_addrinfo_t *rai = get_addrinfo(self);
01388 int internet_p;
01389 VALUE ret;
01390
01391 ret = rb_sprintf("#<%s: ", rb_obj_classname(self));
01392
01393 inspect_sockaddr(self, ret);
01394
01395 if (rai->pfamily && ai_get_afamily(rai) != rai->pfamily) {
01396 ID id = rsock_intern_protocol_family(rai->pfamily);
01397 if (id)
01398 rb_str_catf(ret, " %s", rb_id2name(id));
01399 else
01400 rb_str_catf(ret, " PF_\?\?\?(%d)", rai->pfamily);
01401 }
01402
01403 internet_p = rai->pfamily == PF_INET;
01404 #ifdef INET6
01405 internet_p = internet_p || rai->pfamily == PF_INET6;
01406 #endif
01407 if (internet_p && rai->socktype == SOCK_STREAM &&
01408 (rai->protocol == 0 || rai->protocol == IPPROTO_TCP)) {
01409 rb_str_cat2(ret, " TCP");
01410 }
01411 else if (internet_p && rai->socktype == SOCK_DGRAM &&
01412 (rai->protocol == 0 || rai->protocol == IPPROTO_UDP)) {
01413 rb_str_cat2(ret, " UDP");
01414 }
01415 else {
01416 if (rai->socktype) {
01417 ID id = rsock_intern_socktype(rai->socktype);
01418 if (id)
01419 rb_str_catf(ret, " %s", rb_id2name(id));
01420 else
01421 rb_str_catf(ret, " SOCK_\?\?\?(%d)", rai->socktype);
01422 }
01423
01424 if (rai->protocol) {
01425 if (internet_p) {
01426 ID id = rsock_intern_ipproto(rai->protocol);
01427 if (id)
01428 rb_str_catf(ret, " %s", rb_id2name(id));
01429 else
01430 goto unknown_protocol;
01431 }
01432 else {
01433 unknown_protocol:
01434 rb_str_catf(ret, " UNKNOWN_PROTOCOL(%d)", rai->protocol);
01435 }
01436 }
01437 }
01438
01439 if (!NIL_P(rai->canonname)) {
01440 VALUE name = rai->canonname;
01441 rb_str_catf(ret, " %s", StringValueCStr(name));
01442 }
01443
01444 if (!NIL_P(rai->inspectname)) {
01445 VALUE name = rai->inspectname;
01446 rb_str_catf(ret, " (%s)", StringValueCStr(name));
01447 }
01448
01449 rb_str_buf_cat2(ret, ">");
01450 return ret;
01451 }
01452
01453
01454
01455
01456
01457
01458
01459
01460
01461
01462
01463
01464 VALUE
01465 rsock_addrinfo_inspect_sockaddr(VALUE self)
01466 {
01467 return inspect_sockaddr(self, rb_str_new("", 0));
01468 }
01469
01470
01471 static VALUE
01472 addrinfo_mdump(VALUE self)
01473 {
01474 rb_addrinfo_t *rai = get_addrinfo(self);
01475 VALUE sockaddr, afamily, pfamily, socktype, protocol, canonname, inspectname;
01476 int afamily_int = ai_get_afamily(rai);
01477 ID id;
01478
01479 id = rsock_intern_protocol_family(rai->pfamily);
01480 if (id == 0)
01481 rb_raise(rb_eSocket, "unknown protocol family: %d", rai->pfamily);
01482 pfamily = rb_id2str(id);
01483
01484 if (rai->socktype == 0)
01485 socktype = INT2FIX(0);
01486 else {
01487 id = rsock_intern_socktype(rai->socktype);
01488 if (id == 0)
01489 rb_raise(rb_eSocket, "unknown socktype: %d", rai->socktype);
01490 socktype = rb_id2str(id);
01491 }
01492
01493 if (rai->protocol == 0)
01494 protocol = INT2FIX(0);
01495 else if (IS_IP_FAMILY(afamily_int)) {
01496 id = rsock_intern_ipproto(rai->protocol);
01497 if (id == 0)
01498 rb_raise(rb_eSocket, "unknown IP protocol: %d", rai->protocol);
01499 protocol = rb_id2str(id);
01500 }
01501 else {
01502 rb_raise(rb_eSocket, "unknown protocol: %d", rai->protocol);
01503 }
01504
01505 canonname = rai->canonname;
01506
01507 inspectname = rai->inspectname;
01508
01509 id = rsock_intern_family(afamily_int);
01510 if (id == 0)
01511 rb_raise(rb_eSocket, "unknown address family: %d", afamily_int);
01512 afamily = rb_id2str(id);
01513
01514 switch(afamily_int) {
01515 #ifdef HAVE_SYS_UN_H
01516 case AF_UNIX:
01517 {
01518 struct sockaddr_un *su = &rai->addr.un;
01519 char *s, *e;
01520 s = su->sun_path;
01521 e = (char*)su + rai->sockaddr_len;
01522 while (s < e && *(e-1) == '\0')
01523 e--;
01524 sockaddr = rb_str_new(s, e-s);
01525 break;
01526 }
01527 #endif
01528
01529 default:
01530 {
01531 char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
01532 int error;
01533 error = getnameinfo(&rai->addr.addr, rai->sockaddr_len,
01534 hbuf, (socklen_t)sizeof(hbuf), pbuf, (socklen_t)sizeof(pbuf),
01535 NI_NUMERICHOST|NI_NUMERICSERV);
01536 if (error) {
01537 rsock_raise_socket_error("getnameinfo", error);
01538 }
01539 sockaddr = rb_assoc_new(rb_str_new_cstr(hbuf), rb_str_new_cstr(pbuf));
01540 break;
01541 }
01542 }
01543
01544 return rb_ary_new3(7, afamily, sockaddr, pfamily, socktype, protocol, canonname, inspectname);
01545 }
01546
01547
01548 static VALUE
01549 addrinfo_mload(VALUE self, VALUE ary)
01550 {
01551 VALUE v;
01552 VALUE canonname, inspectname;
01553 int afamily, pfamily, socktype, protocol;
01554 union_sockaddr ss;
01555 socklen_t len;
01556 rb_addrinfo_t *rai;
01557
01558 if (check_addrinfo(self))
01559 rb_raise(rb_eTypeError, "already initialized socket address");
01560
01561 ary = rb_convert_type(ary, T_ARRAY, "Array", "to_ary");
01562
01563 v = rb_ary_entry(ary, 0);
01564 StringValue(v);
01565 if (rsock_family_to_int(RSTRING_PTR(v), RSTRING_LEN(v), &afamily) == -1)
01566 rb_raise(rb_eTypeError, "unexpected address family");
01567
01568 v = rb_ary_entry(ary, 2);
01569 StringValue(v);
01570 if (rsock_family_to_int(RSTRING_PTR(v), RSTRING_LEN(v), &pfamily) == -1)
01571 rb_raise(rb_eTypeError, "unexpected protocol family");
01572
01573 v = rb_ary_entry(ary, 3);
01574 if (v == INT2FIX(0))
01575 socktype = 0;
01576 else {
01577 StringValue(v);
01578 if (rsock_socktype_to_int(RSTRING_PTR(v), RSTRING_LEN(v), &socktype) == -1)
01579 rb_raise(rb_eTypeError, "unexpected socktype");
01580 }
01581
01582 v = rb_ary_entry(ary, 4);
01583 if (v == INT2FIX(0))
01584 protocol = 0;
01585 else {
01586 StringValue(v);
01587 if (IS_IP_FAMILY(afamily)) {
01588 if (rsock_ipproto_to_int(RSTRING_PTR(v), RSTRING_LEN(v), &protocol) == -1)
01589 rb_raise(rb_eTypeError, "unexpected protocol");
01590 }
01591 else {
01592 rb_raise(rb_eTypeError, "unexpected protocol");
01593 }
01594 }
01595
01596 v = rb_ary_entry(ary, 5);
01597 if (NIL_P(v))
01598 canonname = Qnil;
01599 else {
01600 StringValue(v);
01601 canonname = v;
01602 }
01603
01604 v = rb_ary_entry(ary, 6);
01605 if (NIL_P(v))
01606 inspectname = Qnil;
01607 else {
01608 StringValue(v);
01609 inspectname = v;
01610 }
01611
01612 v = rb_ary_entry(ary, 1);
01613 switch(afamily) {
01614 #ifdef HAVE_SYS_UN_H
01615 case AF_UNIX:
01616 {
01617 struct sockaddr_un uaddr;
01618 INIT_SOCKADDR_UN(&uaddr, sizeof(struct sockaddr_un));
01619
01620 StringValue(v);
01621 if (sizeof(uaddr.sun_path) < (size_t)RSTRING_LEN(v))
01622 rb_raise(rb_eSocket,
01623 "too long AF_UNIX path (%"PRIuSIZE" bytes given but %"PRIuSIZE" bytes max)",
01624 (size_t)RSTRING_LEN(v), sizeof(uaddr.sun_path));
01625 memcpy(uaddr.sun_path, RSTRING_PTR(v), RSTRING_LEN(v));
01626 len = (socklen_t)sizeof(uaddr);
01627 memcpy(&ss, &uaddr, len);
01628 break;
01629 }
01630 #endif
01631
01632 default:
01633 {
01634 VALUE pair = rb_convert_type(v, T_ARRAY, "Array", "to_ary");
01635 struct rb_addrinfo *res;
01636 int flags = AI_NUMERICHOST;
01637 #ifdef AI_NUMERICSERV
01638 flags |= AI_NUMERICSERV;
01639 #endif
01640 res = call_getaddrinfo(rb_ary_entry(pair, 0), rb_ary_entry(pair, 1),
01641 INT2NUM(pfamily), INT2NUM(socktype), INT2NUM(protocol),
01642 INT2NUM(flags), 1);
01643
01644 len = res->ai->ai_addrlen;
01645 memcpy(&ss, res->ai->ai_addr, res->ai->ai_addrlen);
01646 break;
01647 }
01648 }
01649
01650 DATA_PTR(self) = rai = alloc_addrinfo();
01651 init_addrinfo(rai, &ss.addr, len,
01652 pfamily, socktype, protocol,
01653 canonname, inspectname);
01654 return self;
01655 }
01656
01657
01658
01659
01660
01661
01662
01663
01664
01665
01666 static VALUE
01667 addrinfo_afamily(VALUE self)
01668 {
01669 rb_addrinfo_t *rai = get_addrinfo(self);
01670 return INT2NUM(ai_get_afamily(rai));
01671 }
01672
01673
01674
01675
01676
01677
01678
01679
01680
01681
01682 static VALUE
01683 addrinfo_pfamily(VALUE self)
01684 {
01685 rb_addrinfo_t *rai = get_addrinfo(self);
01686 return INT2NUM(rai->pfamily);
01687 }
01688
01689
01690
01691
01692
01693
01694
01695
01696
01697
01698 static VALUE
01699 addrinfo_socktype(VALUE self)
01700 {
01701 rb_addrinfo_t *rai = get_addrinfo(self);
01702 return INT2NUM(rai->socktype);
01703 }
01704
01705
01706
01707
01708
01709
01710
01711
01712
01713
01714 static VALUE
01715 addrinfo_protocol(VALUE self)
01716 {
01717 rb_addrinfo_t *rai = get_addrinfo(self);
01718 return INT2NUM(rai->protocol);
01719 }
01720
01721
01722
01723
01724
01725
01726
01727
01728
01729
01730
01731
01732 static VALUE
01733 addrinfo_to_sockaddr(VALUE self)
01734 {
01735 rb_addrinfo_t *rai = get_addrinfo(self);
01736 VALUE ret;
01737 ret = rb_str_new((char*)&rai->addr, rai->sockaddr_len);
01738 OBJ_INFECT(ret, self);
01739 return ret;
01740 }
01741
01742
01743
01744
01745
01746
01747
01748
01749
01750
01751
01752
01753
01754
01755
01756
01757 static VALUE
01758 addrinfo_canonname(VALUE self)
01759 {
01760 rb_addrinfo_t *rai = get_addrinfo(self);
01761 return rai->canonname;
01762 }
01763
01764
01765
01766
01767
01768
01769
01770
01771
01772
01773
01774
01775
01776 static VALUE
01777 addrinfo_ip_p(VALUE self)
01778 {
01779 rb_addrinfo_t *rai = get_addrinfo(self);
01780 int family = ai_get_afamily(rai);
01781 return IS_IP_FAMILY(family) ? Qtrue : Qfalse;
01782 }
01783
01784
01785
01786
01787
01788
01789
01790
01791
01792
01793
01794
01795
01796 static VALUE
01797 addrinfo_ipv4_p(VALUE self)
01798 {
01799 rb_addrinfo_t *rai = get_addrinfo(self);
01800 return ai_get_afamily(rai) == AF_INET ? Qtrue : Qfalse;
01801 }
01802
01803
01804
01805
01806
01807
01808
01809
01810
01811
01812
01813
01814
01815 static VALUE
01816 addrinfo_ipv6_p(VALUE self)
01817 {
01818 #ifdef AF_INET6
01819 rb_addrinfo_t *rai = get_addrinfo(self);
01820 return ai_get_afamily(rai) == AF_INET6 ? Qtrue : Qfalse;
01821 #else
01822 return Qfalse;
01823 #endif
01824 }
01825
01826
01827
01828
01829
01830
01831
01832
01833
01834
01835
01836
01837
01838 static VALUE
01839 addrinfo_unix_p(VALUE self)
01840 {
01841 rb_addrinfo_t *rai = get_addrinfo(self);
01842 #ifdef AF_UNIX
01843 return ai_get_afamily(rai) == AF_UNIX ? Qtrue : Qfalse;
01844 #else
01845 return Qfalse;
01846 #endif
01847 }
01848
01849
01850
01851
01852
01853
01854
01855
01856
01857
01858
01859
01860
01861
01862
01863
01864 static VALUE
01865 addrinfo_getnameinfo(int argc, VALUE *argv, VALUE self)
01866 {
01867 rb_addrinfo_t *rai = get_addrinfo(self);
01868 VALUE vflags;
01869 char hbuf[1024], pbuf[1024];
01870 int flags, error;
01871
01872 rb_scan_args(argc, argv, "01", &vflags);
01873
01874 flags = NIL_P(vflags) ? 0 : NUM2INT(vflags);
01875
01876 if (rai->socktype == SOCK_DGRAM)
01877 flags |= NI_DGRAM;
01878
01879 error = getnameinfo(&rai->addr.addr, rai->sockaddr_len,
01880 hbuf, (socklen_t)sizeof(hbuf), pbuf, (socklen_t)sizeof(pbuf),
01881 flags);
01882 if (error) {
01883 rsock_raise_socket_error("getnameinfo", error);
01884 }
01885
01886 return rb_assoc_new(rb_str_new2(hbuf), rb_str_new2(pbuf));
01887 }
01888
01889
01890
01891
01892
01893
01894
01895
01896
01897
01898 static VALUE
01899 addrinfo_ip_unpack(VALUE self)
01900 {
01901 rb_addrinfo_t *rai = get_addrinfo(self);
01902 int family = ai_get_afamily(rai);
01903 VALUE vflags;
01904 VALUE ret, portstr;
01905
01906 if (!IS_IP_FAMILY(family))
01907 rb_raise(rb_eSocket, "need IPv4 or IPv6 address");
01908
01909 vflags = INT2NUM(NI_NUMERICHOST|NI_NUMERICSERV);
01910 ret = addrinfo_getnameinfo(1, &vflags, self);
01911 portstr = rb_ary_entry(ret, 1);
01912 rb_ary_store(ret, 1, INT2NUM(atoi(StringValueCStr(portstr))));
01913 return ret;
01914 }
01915
01916
01917
01918
01919
01920
01921
01922
01923
01924
01925 static VALUE
01926 addrinfo_ip_address(VALUE self)
01927 {
01928 rb_addrinfo_t *rai = get_addrinfo(self);
01929 int family = ai_get_afamily(rai);
01930 VALUE vflags;
01931 VALUE ret;
01932
01933 if (!IS_IP_FAMILY(family))
01934 rb_raise(rb_eSocket, "need IPv4 or IPv6 address");
01935
01936 vflags = INT2NUM(NI_NUMERICHOST|NI_NUMERICSERV);
01937 ret = addrinfo_getnameinfo(1, &vflags, self);
01938 return rb_ary_entry(ret, 0);
01939 }
01940
01941
01942
01943
01944
01945
01946
01947
01948
01949
01950 static VALUE
01951 addrinfo_ip_port(VALUE self)
01952 {
01953 rb_addrinfo_t *rai = get_addrinfo(self);
01954 int family = ai_get_afamily(rai);
01955 int port;
01956
01957 if (!IS_IP_FAMILY(family)) {
01958 bad_family:
01959 #ifdef AF_INET6
01960 rb_raise(rb_eSocket, "need IPv4 or IPv6 address");
01961 #else
01962 rb_raise(rb_eSocket, "need IPv4 address");
01963 #endif
01964 }
01965
01966 switch (family) {
01967 case AF_INET:
01968 if (rai->sockaddr_len != sizeof(struct sockaddr_in))
01969 rb_raise(rb_eSocket, "unexpected sockaddr size for IPv4");
01970 port = ntohs(rai->addr.in.sin_port);
01971 break;
01972
01973 #ifdef AF_INET6
01974 case AF_INET6:
01975 if (rai->sockaddr_len != sizeof(struct sockaddr_in6))
01976 rb_raise(rb_eSocket, "unexpected sockaddr size for IPv6");
01977 port = ntohs(rai->addr.in6.sin6_port);
01978 break;
01979 #endif
01980
01981 default:
01982 goto bad_family;
01983 }
01984
01985 return INT2NUM(port);
01986 }
01987
01988 static int
01989 extract_in_addr(VALUE self, uint32_t *addrp)
01990 {
01991 rb_addrinfo_t *rai = get_addrinfo(self);
01992 int family = ai_get_afamily(rai);
01993 if (family != AF_INET) return 0;
01994 *addrp = ntohl(rai->addr.in.sin_addr.s_addr);
01995 return 1;
01996 }
01997
01998
01999
02000
02001
02002 static VALUE
02003 addrinfo_ipv4_private_p(VALUE self)
02004 {
02005 uint32_t a;
02006 if (!extract_in_addr(self, &a)) return Qfalse;
02007 if ((a & 0xff000000) == 0x0a000000 ||
02008 (a & 0xfff00000) == 0xac100000 ||
02009 (a & 0xffff0000) == 0xc0a80000)
02010 return Qtrue;
02011 return Qfalse;
02012 }
02013
02014
02015
02016
02017
02018 static VALUE
02019 addrinfo_ipv4_loopback_p(VALUE self)
02020 {
02021 uint32_t a;
02022 if (!extract_in_addr(self, &a)) return Qfalse;
02023 if ((a & 0xff000000) == 0x7f000000)
02024 return Qtrue;
02025 return Qfalse;
02026 }
02027
02028
02029
02030
02031
02032 static VALUE
02033 addrinfo_ipv4_multicast_p(VALUE self)
02034 {
02035 uint32_t a;
02036 if (!extract_in_addr(self, &a)) return Qfalse;
02037 if ((a & 0xf0000000) == 0xe0000000)
02038 return Qtrue;
02039 return Qfalse;
02040 }
02041
02042 #ifdef INET6
02043
02044 static struct in6_addr *
02045 extract_in6_addr(VALUE self)
02046 {
02047 rb_addrinfo_t *rai = get_addrinfo(self);
02048 int family = ai_get_afamily(rai);
02049 if (family != AF_INET6) return NULL;
02050 return &rai->addr.in6.sin6_addr;
02051 }
02052
02053
02054
02055
02056
02057 static VALUE
02058 addrinfo_ipv6_unspecified_p(VALUE self)
02059 {
02060 struct in6_addr *addr = extract_in6_addr(self);
02061 if (addr && IN6_IS_ADDR_UNSPECIFIED(addr)) return Qtrue;
02062 return Qfalse;
02063 }
02064
02065
02066
02067
02068
02069 static VALUE
02070 addrinfo_ipv6_loopback_p(VALUE self)
02071 {
02072 struct in6_addr *addr = extract_in6_addr(self);
02073 if (addr && IN6_IS_ADDR_LOOPBACK(addr)) return Qtrue;
02074 return Qfalse;
02075 }
02076
02077
02078
02079
02080
02081 static VALUE
02082 addrinfo_ipv6_multicast_p(VALUE self)
02083 {
02084 struct in6_addr *addr = extract_in6_addr(self);
02085 if (addr && IN6_IS_ADDR_MULTICAST(addr)) return Qtrue;
02086 return Qfalse;
02087 }
02088
02089
02090
02091
02092
02093 static VALUE
02094 addrinfo_ipv6_linklocal_p(VALUE self)
02095 {
02096 struct in6_addr *addr = extract_in6_addr(self);
02097 if (addr && IN6_IS_ADDR_LINKLOCAL(addr)) return Qtrue;
02098 return Qfalse;
02099 }
02100
02101
02102
02103
02104
02105 static VALUE
02106 addrinfo_ipv6_sitelocal_p(VALUE self)
02107 {
02108 struct in6_addr *addr = extract_in6_addr(self);
02109 if (addr && IN6_IS_ADDR_SITELOCAL(addr)) return Qtrue;
02110 return Qfalse;
02111 }
02112
02113
02114
02115
02116
02117 static VALUE
02118 addrinfo_ipv6_unique_local_p(VALUE self)
02119 {
02120 struct in6_addr *addr = extract_in6_addr(self);
02121 if (addr && IN6_IS_ADDR_UNIQUE_LOCAL(addr)) return Qtrue;
02122 return Qfalse;
02123 }
02124
02125
02126
02127
02128
02129 static VALUE
02130 addrinfo_ipv6_v4mapped_p(VALUE self)
02131 {
02132 struct in6_addr *addr = extract_in6_addr(self);
02133 if (addr && IN6_IS_ADDR_V4MAPPED(addr)) return Qtrue;
02134 return Qfalse;
02135 }
02136
02137
02138
02139
02140
02141 static VALUE
02142 addrinfo_ipv6_v4compat_p(VALUE self)
02143 {
02144 struct in6_addr *addr = extract_in6_addr(self);
02145 if (addr && IN6_IS_ADDR_V4COMPAT(addr)) return Qtrue;
02146 return Qfalse;
02147 }
02148
02149
02150
02151
02152
02153 static VALUE
02154 addrinfo_ipv6_mc_nodelocal_p(VALUE self)
02155 {
02156 struct in6_addr *addr = extract_in6_addr(self);
02157 if (addr && IN6_IS_ADDR_MC_NODELOCAL(addr)) return Qtrue;
02158 return Qfalse;
02159 }
02160
02161
02162
02163
02164
02165 static VALUE
02166 addrinfo_ipv6_mc_linklocal_p(VALUE self)
02167 {
02168 struct in6_addr *addr = extract_in6_addr(self);
02169 if (addr && IN6_IS_ADDR_MC_LINKLOCAL(addr)) return Qtrue;
02170 return Qfalse;
02171 }
02172
02173
02174
02175
02176
02177 static VALUE
02178 addrinfo_ipv6_mc_sitelocal_p(VALUE self)
02179 {
02180 struct in6_addr *addr = extract_in6_addr(self);
02181 if (addr && IN6_IS_ADDR_MC_SITELOCAL(addr)) return Qtrue;
02182 return Qfalse;
02183 }
02184
02185
02186
02187
02188
02189 static VALUE
02190 addrinfo_ipv6_mc_orglocal_p(VALUE self)
02191 {
02192 struct in6_addr *addr = extract_in6_addr(self);
02193 if (addr && IN6_IS_ADDR_MC_ORGLOCAL(addr)) return Qtrue;
02194 return Qfalse;
02195 }
02196
02197
02198
02199
02200
02201 static VALUE
02202 addrinfo_ipv6_mc_global_p(VALUE self)
02203 {
02204 struct in6_addr *addr = extract_in6_addr(self);
02205 if (addr && IN6_IS_ADDR_MC_GLOBAL(addr)) return Qtrue;
02206 return Qfalse;
02207 }
02208
02209
02210
02211
02212
02213
02214
02215
02216
02217
02218
02219 static VALUE
02220 addrinfo_ipv6_to_ipv4(VALUE self)
02221 {
02222 rb_addrinfo_t *rai = get_addrinfo(self);
02223 struct in6_addr *addr;
02224 int family = ai_get_afamily(rai);
02225 if (family != AF_INET6) return Qnil;
02226 addr = &rai->addr.in6.sin6_addr;
02227 if (IN6_IS_ADDR_V4MAPPED(addr) || IN6_IS_ADDR_V4COMPAT(addr)) {
02228 struct sockaddr_in sin4;
02229 INIT_SOCKADDR_IN(&sin4, sizeof(sin4));
02230 memcpy(&sin4.sin_addr, (char*)addr + sizeof(*addr) - sizeof(sin4.sin_addr), sizeof(sin4.sin_addr));
02231 return rsock_addrinfo_new((struct sockaddr *)&sin4, (socklen_t)sizeof(sin4),
02232 PF_INET, rai->socktype, rai->protocol,
02233 rai->canonname, rai->inspectname);
02234 }
02235 else {
02236 return Qnil;
02237 }
02238 }
02239
02240 #endif
02241
02242 #ifdef HAVE_SYS_UN_H
02243
02244
02245
02246
02247
02248
02249
02250
02251 static VALUE
02252 addrinfo_unix_path(VALUE self)
02253 {
02254 rb_addrinfo_t *rai = get_addrinfo(self);
02255 int family = ai_get_afamily(rai);
02256 struct sockaddr_un *addr;
02257 char *s, *e;
02258
02259 if (family != AF_UNIX)
02260 rb_raise(rb_eSocket, "need AF_UNIX address");
02261
02262 addr = &rai->addr.un;
02263
02264 s = addr->sun_path;
02265 e = (char*)addr + rai->sockaddr_len;
02266 if (e < s)
02267 rb_raise(rb_eSocket, "too short AF_UNIX address: %"PRIuSIZE" bytes given for minimum %"PRIuSIZE" bytes.",
02268 (size_t)rai->sockaddr_len, (size_t)(s - (char *)addr));
02269 if (addr->sun_path + sizeof(addr->sun_path) < e)
02270 rb_raise(rb_eSocket,
02271 "too long AF_UNIX path (%"PRIuSIZE" bytes given but %"PRIuSIZE" bytes max)",
02272 (size_t)(e - addr->sun_path), sizeof(addr->sun_path));
02273 while (s < e && *(e-1) == '\0')
02274 e--;
02275 return rb_str_new(s, e-s);
02276 }
02277 #endif
02278
02279
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 static VALUE
02323 addrinfo_s_getaddrinfo(int argc, VALUE *argv, VALUE self)
02324 {
02325 VALUE node, service, family, socktype, protocol, flags;
02326
02327 rb_scan_args(argc, argv, "24", &node, &service, &family, &socktype, &protocol, &flags);
02328 return addrinfo_list_new(node, service, family, socktype, protocol, flags);
02329 }
02330
02331
02332
02333
02334
02335
02336
02337
02338
02339
02340
02341
02342 static VALUE
02343 addrinfo_s_ip(VALUE self, VALUE host)
02344 {
02345 VALUE ret;
02346 rb_addrinfo_t *rai;
02347 ret = addrinfo_firstonly_new(host, Qnil,
02348 INT2NUM(PF_UNSPEC), INT2FIX(0), INT2FIX(0), INT2FIX(0));
02349 rai = get_addrinfo(ret);
02350 rai->socktype = 0;
02351 rai->protocol = 0;
02352 return ret;
02353 }
02354
02355
02356
02357
02358
02359
02360
02361
02362
02363 static VALUE
02364 addrinfo_s_tcp(VALUE self, VALUE host, VALUE port)
02365 {
02366 return addrinfo_firstonly_new(host, port,
02367 INT2NUM(PF_UNSPEC), INT2NUM(SOCK_STREAM), INT2NUM(IPPROTO_TCP), INT2FIX(0));
02368 }
02369
02370
02371
02372
02373
02374
02375
02376
02377
02378 static VALUE
02379 addrinfo_s_udp(VALUE self, VALUE host, VALUE port)
02380 {
02381 return addrinfo_firstonly_new(host, port,
02382 INT2NUM(PF_UNSPEC), INT2NUM(SOCK_DGRAM), INT2NUM(IPPROTO_UDP), INT2FIX(0));
02383 }
02384
02385 #ifdef HAVE_SYS_UN_H
02386
02387
02388
02389
02390
02391
02392
02393
02394
02395
02396
02397
02398
02399 static VALUE
02400 addrinfo_s_unix(int argc, VALUE *argv, VALUE self)
02401 {
02402 VALUE path, vsocktype, addr;
02403 int socktype;
02404 rb_addrinfo_t *rai;
02405
02406 rb_scan_args(argc, argv, "11", &path, &vsocktype);
02407
02408 if (NIL_P(vsocktype))
02409 socktype = SOCK_STREAM;
02410 else
02411 socktype = rsock_socktype_arg(vsocktype);
02412
02413 addr = addrinfo_s_allocate(rb_cAddrinfo);
02414 DATA_PTR(addr) = rai = alloc_addrinfo();
02415 init_unix_addrinfo(rai, path, socktype);
02416 OBJ_INFECT(addr, path);
02417 return addr;
02418 }
02419
02420 #endif
02421
02422 VALUE
02423 rsock_sockaddr_string_value(volatile VALUE *v)
02424 {
02425 VALUE val = *v;
02426 if (IS_ADDRINFO(val)) {
02427 *v = addrinfo_to_sockaddr(val);
02428 }
02429 StringValue(*v);
02430 return *v;
02431 }
02432
02433 VALUE
02434 rsock_sockaddr_string_value_with_addrinfo(volatile VALUE *v, VALUE *rai_ret)
02435 {
02436 VALUE val = *v;
02437 *rai_ret = Qnil;
02438 if (IS_ADDRINFO(val)) {
02439 *v = addrinfo_to_sockaddr(val);
02440 *rai_ret = val;
02441 }
02442 StringValue(*v);
02443 return *v;
02444 }
02445
02446 char *
02447 rsock_sockaddr_string_value_ptr(volatile VALUE *v)
02448 {
02449 rsock_sockaddr_string_value(v);
02450 return RSTRING_PTR(*v);
02451 }
02452
02453 VALUE
02454 rb_check_sockaddr_string_type(VALUE val)
02455 {
02456 if (IS_ADDRINFO(val))
02457 return addrinfo_to_sockaddr(val);
02458 return rb_check_string_type(val);
02459 }
02460
02461 VALUE
02462 rsock_fd_socket_addrinfo(int fd, struct sockaddr *addr, socklen_t len)
02463 {
02464 int family;
02465 int socktype;
02466 int ret;
02467 socklen_t optlen = (socklen_t)sizeof(socktype);
02468
02469
02470 family = get_afamily(addr, len);
02471
02472 ret = getsockopt(fd, SOL_SOCKET, SO_TYPE, (void*)&socktype, &optlen);
02473 if (ret == -1) {
02474 rb_sys_fail("getsockopt(SO_TYPE)");
02475 }
02476
02477 return rsock_addrinfo_new(addr, len, family, socktype, 0, Qnil, Qnil);
02478 }
02479
02480 VALUE
02481 rsock_io_socket_addrinfo(VALUE io, struct sockaddr *addr, socklen_t len)
02482 {
02483 rb_io_t *fptr;
02484
02485 switch (TYPE(io)) {
02486 case T_FIXNUM:
02487 return rsock_fd_socket_addrinfo(FIX2INT(io), addr, len);
02488
02489 case T_BIGNUM:
02490 return rsock_fd_socket_addrinfo(NUM2INT(io), addr, len);
02491
02492 case T_FILE:
02493 GetOpenFile(io, fptr);
02494 return rsock_fd_socket_addrinfo(fptr->fd, addr, len);
02495
02496 default:
02497 rb_raise(rb_eTypeError, "neither IO nor file descriptor");
02498 }
02499
02500 UNREACHABLE;
02501 }
02502
02503
02504
02505
02506 void
02507 rsock_init_addrinfo(void)
02508 {
02509
02510
02511
02512
02513 rb_cAddrinfo = rb_define_class("Addrinfo", rb_cData);
02514 rb_define_alloc_func(rb_cAddrinfo, addrinfo_s_allocate);
02515 rb_define_method(rb_cAddrinfo, "initialize", addrinfo_initialize, -1);
02516 rb_define_method(rb_cAddrinfo, "inspect", addrinfo_inspect, 0);
02517 rb_define_method(rb_cAddrinfo, "inspect_sockaddr", rsock_addrinfo_inspect_sockaddr, 0);
02518 rb_define_singleton_method(rb_cAddrinfo, "getaddrinfo", addrinfo_s_getaddrinfo, -1);
02519 rb_define_singleton_method(rb_cAddrinfo, "ip", addrinfo_s_ip, 1);
02520 rb_define_singleton_method(rb_cAddrinfo, "tcp", addrinfo_s_tcp, 2);
02521 rb_define_singleton_method(rb_cAddrinfo, "udp", addrinfo_s_udp, 2);
02522 #ifdef HAVE_SYS_UN_H
02523 rb_define_singleton_method(rb_cAddrinfo, "unix", addrinfo_s_unix, -1);
02524 #endif
02525
02526 rb_define_method(rb_cAddrinfo, "afamily", addrinfo_afamily, 0);
02527 rb_define_method(rb_cAddrinfo, "pfamily", addrinfo_pfamily, 0);
02528 rb_define_method(rb_cAddrinfo, "socktype", addrinfo_socktype, 0);
02529 rb_define_method(rb_cAddrinfo, "protocol", addrinfo_protocol, 0);
02530 rb_define_method(rb_cAddrinfo, "canonname", addrinfo_canonname, 0);
02531
02532 rb_define_method(rb_cAddrinfo, "ipv4?", addrinfo_ipv4_p, 0);
02533 rb_define_method(rb_cAddrinfo, "ipv6?", addrinfo_ipv6_p, 0);
02534 rb_define_method(rb_cAddrinfo, "unix?", addrinfo_unix_p, 0);
02535
02536 rb_define_method(rb_cAddrinfo, "ip?", addrinfo_ip_p, 0);
02537 rb_define_method(rb_cAddrinfo, "ip_unpack", addrinfo_ip_unpack, 0);
02538 rb_define_method(rb_cAddrinfo, "ip_address", addrinfo_ip_address, 0);
02539 rb_define_method(rb_cAddrinfo, "ip_port", addrinfo_ip_port, 0);
02540
02541 rb_define_method(rb_cAddrinfo, "ipv4_private?", addrinfo_ipv4_private_p, 0);
02542 rb_define_method(rb_cAddrinfo, "ipv4_loopback?", addrinfo_ipv4_loopback_p, 0);
02543 rb_define_method(rb_cAddrinfo, "ipv4_multicast?", addrinfo_ipv4_multicast_p, 0);
02544
02545 #ifdef INET6
02546 rb_define_method(rb_cAddrinfo, "ipv6_unspecified?", addrinfo_ipv6_unspecified_p, 0);
02547 rb_define_method(rb_cAddrinfo, "ipv6_loopback?", addrinfo_ipv6_loopback_p, 0);
02548 rb_define_method(rb_cAddrinfo, "ipv6_multicast?", addrinfo_ipv6_multicast_p, 0);
02549 rb_define_method(rb_cAddrinfo, "ipv6_linklocal?", addrinfo_ipv6_linklocal_p, 0);
02550 rb_define_method(rb_cAddrinfo, "ipv6_sitelocal?", addrinfo_ipv6_sitelocal_p, 0);
02551 rb_define_method(rb_cAddrinfo, "ipv6_unique_local?", addrinfo_ipv6_unique_local_p, 0);
02552 rb_define_method(rb_cAddrinfo, "ipv6_v4mapped?", addrinfo_ipv6_v4mapped_p, 0);
02553 rb_define_method(rb_cAddrinfo, "ipv6_v4compat?", addrinfo_ipv6_v4compat_p, 0);
02554 rb_define_method(rb_cAddrinfo, "ipv6_mc_nodelocal?", addrinfo_ipv6_mc_nodelocal_p, 0);
02555 rb_define_method(rb_cAddrinfo, "ipv6_mc_linklocal?", addrinfo_ipv6_mc_linklocal_p, 0);
02556 rb_define_method(rb_cAddrinfo, "ipv6_mc_sitelocal?", addrinfo_ipv6_mc_sitelocal_p, 0);
02557 rb_define_method(rb_cAddrinfo, "ipv6_mc_orglocal?", addrinfo_ipv6_mc_orglocal_p, 0);
02558 rb_define_method(rb_cAddrinfo, "ipv6_mc_global?", addrinfo_ipv6_mc_global_p, 0);
02559
02560 rb_define_method(rb_cAddrinfo, "ipv6_to_ipv4", addrinfo_ipv6_to_ipv4, 0);
02561 #endif
02562
02563 #ifdef HAVE_SYS_UN_H
02564 rb_define_method(rb_cAddrinfo, "unix_path", addrinfo_unix_path, 0);
02565 #endif
02566
02567 rb_define_method(rb_cAddrinfo, "to_sockaddr", addrinfo_to_sockaddr, 0);
02568 rb_define_method(rb_cAddrinfo, "to_s", addrinfo_to_sockaddr, 0);
02569
02570 rb_define_method(rb_cAddrinfo, "getnameinfo", addrinfo_getnameinfo, -1);
02571
02572 rb_define_method(rb_cAddrinfo, "marshal_dump", addrinfo_mdump, 0);
02573 rb_define_method(rb_cAddrinfo, "marshal_load", addrinfo_mload, 1);
02574 }
02575