Ruby 2.7.6p219 (2022-04-12 revision c9c2245c0a25176072e02db9254f0e0c84c805cd)
raddrinfo.c
Go to the documentation of this file.
1/************************************************
2
3 raddrinfo.c -
4
5 created at: Thu Mar 31 12:21:29 JST 1994
6
7 Copyright (C) 1993-2007 Yukihiro Matsumoto
8
9************************************************/
10
11#include "rubysocket.h"
12
13#if defined(INET6) && (defined(LOOKUP_ORDER_HACK_INET) || defined(LOOKUP_ORDER_HACK_INET6))
14#define LOOKUP_ORDERS (sizeof(lookup_order_table) / sizeof(lookup_order_table[0]))
15static const int lookup_order_table[] = {
16#if defined(LOOKUP_ORDER_HACK_INET)
17 PF_INET, PF_INET6, PF_UNSPEC,
18#elif defined(LOOKUP_ORDER_HACK_INET6)
19 PF_INET6, PF_INET, PF_UNSPEC,
20#else
21 /* should not happen */
22#endif
23};
24
25static int
26ruby_getaddrinfo(const char *nodename, const char *servname,
27 const struct addrinfo *hints, struct addrinfo **res)
28{
29 struct addrinfo tmp_hints;
30 int i, af, error;
31
32 if (hints->ai_family != PF_UNSPEC) {
33 return getaddrinfo(nodename, servname, hints, res);
34 }
35
36 for (i = 0; i < LOOKUP_ORDERS; i++) {
37 af = lookup_order_table[i];
38 MEMCPY(&tmp_hints, hints, struct addrinfo, 1);
39 tmp_hints.ai_family = af;
40 error = getaddrinfo(nodename, servname, &tmp_hints, res);
41 if (error) {
42 if (tmp_hints.ai_family == PF_UNSPEC) {
43 break;
44 }
45 }
46 else {
47 break;
48 }
49 }
50
51 return error;
52}
53#define getaddrinfo(node,serv,hints,res) ruby_getaddrinfo((node),(serv),(hints),(res))
54#endif
55
56#if defined(_AIX)
57static int
58ruby_getaddrinfo__aix(const char *nodename, const char *servname,
59 const struct addrinfo *hints, struct addrinfo **res)
60{
61 int error = getaddrinfo(nodename, servname, hints, res);
62 struct addrinfo *r;
63 if (error)
64 return error;
65 for (r = *res; r != NULL; r = r->ai_next) {
66 if (r->ai_addr->sa_family == 0)
67 r->ai_addr->sa_family = r->ai_family;
68 if (r->ai_addr->sa_len == 0)
69 r->ai_addr->sa_len = r->ai_addrlen;
70 }
71 return 0;
72}
73#undef getaddrinfo
74#define getaddrinfo(node,serv,hints,res) ruby_getaddrinfo__aix((node),(serv),(hints),(res))
75static int
76ruby_getnameinfo__aix(const struct sockaddr *sa, size_t salen,
77 char *host, size_t hostlen,
78 char *serv, size_t servlen, int flags)
79{
80 struct sockaddr_in6 *sa6;
81 u_int32_t *a6;
82
83 if (sa->sa_family == AF_INET6) {
84 sa6 = (struct sockaddr_in6 *)sa;
85 a6 = sa6->sin6_addr.u6_addr.u6_addr32;
86
87 if (a6[0] == 0 && a6[1] == 0 && a6[2] == 0 && a6[3] == 0) {
88 strncpy(host, "::", hostlen);
89 snprintf(serv, servlen, "%d", sa6->sin6_port);
90 return 0;
91 }
92 }
93 return getnameinfo(sa, salen, host, hostlen, serv, servlen, flags);
94}
95#undef getnameinfo
96#define getnameinfo(sa, salen, host, hostlen, serv, servlen, flags) \
97 ruby_getnameinfo__aix((sa), (salen), (host), (hostlen), (serv), (servlen), (flags))
98#endif
99
100static int str_is_number(const char *);
101
102#if defined(__APPLE__)
103static int
104ruby_getaddrinfo__darwin(const char *nodename, const char *servname,
105 const struct addrinfo *hints, struct addrinfo **res)
106{
107 /* fix [ruby-core:29427] */
108 const char *tmp_servname;
109 struct addrinfo tmp_hints;
110 int error;
111
112 tmp_servname = servname;
113 MEMCPY(&tmp_hints, hints, struct addrinfo, 1);
114 if (nodename && servname) {
115 if (str_is_number(tmp_servname) && atoi(servname) == 0) {
116 tmp_servname = NULL;
117#ifdef AI_NUMERICSERV
118 if (tmp_hints.ai_flags) tmp_hints.ai_flags &= ~AI_NUMERICSERV;
119#endif
120 }
121 }
122
123 error = getaddrinfo(nodename, tmp_servname, &tmp_hints, res);
124 if (error == 0) {
125 /* [ruby-dev:23164] */
126 struct addrinfo *r;
127 r = *res;
128 while (r) {
129 if (! r->ai_socktype) r->ai_socktype = hints->ai_socktype;
130 if (! r->ai_protocol) {
131 if (r->ai_socktype == SOCK_DGRAM) {
133 }
134 else if (r->ai_socktype == SOCK_STREAM) {
136 }
137 }
138 r = r->ai_next;
139 }
140 }
141
142 return error;
143}
144#undef getaddrinfo
145#define getaddrinfo(node,serv,hints,res) ruby_getaddrinfo__darwin((node),(serv),(hints),(res))
146#endif
147
148#ifdef HAVE_INET_PTON
149static int
150parse_numeric_port(const char *service, int *portp)
151{
152 unsigned long u;
153
154 if (!service) {
155 *portp = 0;
156 return 1;
157 }
158
159 if (strspn(service, "0123456789") != strlen(service))
160 return 0;
161
162 errno = 0;
163 u = STRTOUL(service, NULL, 10);
164 if (errno)
165 return 0;
166
167 if (0x10000 <= u)
168 return 0;
169
170 *portp = (int)u;
171
172 return 1;
173}
174#endif
175
176#ifndef GETADDRINFO_EMU
178{
179 const char *node;
180 const char *service;
181 const struct addrinfo *hints;
182 struct addrinfo **res;
183};
184
185static void *
186nogvl_getaddrinfo(void *arg)
187{
188 int ret;
189 struct getaddrinfo_arg *ptr = arg;
190 ret = getaddrinfo(ptr->node, ptr->service, ptr->hints, ptr->res);
191#ifdef __linux__
192 /* On Linux (mainly Ubuntu 13.04) /etc/nsswitch.conf has mdns4 and
193 * it cause getaddrinfo to return EAI_SYSTEM/ENOENT. [ruby-list:49420]
194 */
195 if (ret == EAI_SYSTEM && errno == ENOENT)
196 ret = EAI_NONAME;
197#endif
198 return (void *)(VALUE)ret;
199}
200#endif
201
202#ifdef HAVE_GETADDRINFO_A
203struct gai_suspend_arg
204{
205 struct gaicb *req;
206 struct timespec *timeout;
207};
208
209static void *
210nogvl_gai_suspend(void *arg)
211{
212 int ret;
213 struct gai_suspend_arg *ptr = arg;
214 struct gaicb const *wait_reqs[1];
215
216 wait_reqs[0] = ptr->req;
217 ret = gai_suspend(wait_reqs, 1, ptr->timeout);
218
219 return (void *)(VALUE)ret;
220}
221#endif
222
223static int
224numeric_getaddrinfo(const char *node, const char *service,
225 const struct addrinfo *hints,
226 struct addrinfo **res)
227{
228#ifdef HAVE_INET_PTON
229# if defined __MINGW64__
230# define inet_pton(f,s,d) rb_w32_inet_pton(f,s,d)
231# endif
232
233 int port;
234
235 if (node && parse_numeric_port(service, &port)) {
236 static const struct {
237 int socktype;
238 int protocol;
239 } list[] = {
240 { SOCK_STREAM, IPPROTO_TCP },
241 { SOCK_DGRAM, IPPROTO_UDP },
242 { SOCK_RAW, 0 }
243 };
244 struct addrinfo *ai = NULL;
245 int hint_family = hints ? hints->ai_family : PF_UNSPEC;
246 int hint_socktype = hints ? hints->ai_socktype : 0;
247 int hint_protocol = hints ? hints->ai_protocol : 0;
248 char ipv4addr[4];
249#ifdef AF_INET6
250 char ipv6addr[16];
251 if ((hint_family == PF_UNSPEC || hint_family == PF_INET6) &&
252 strspn(node, "0123456789abcdefABCDEF.:") == strlen(node) &&
253 inet_pton(AF_INET6, node, ipv6addr)) {
254 int i;
255 for (i = numberof(list)-1; 0 <= i; i--) {
256 if ((hint_socktype == 0 || hint_socktype == list[i].socktype) &&
257 (hint_protocol == 0 || list[i].protocol == 0 || hint_protocol == list[i].protocol)) {
258 struct addrinfo *ai0 = xcalloc(1, sizeof(struct addrinfo));
259 struct sockaddr_in6 *sa = xmalloc(sizeof(struct sockaddr_in6));
260 INIT_SOCKADDR_IN6(sa, sizeof(struct sockaddr_in6));
261 memcpy(&sa->sin6_addr, ipv6addr, sizeof(ipv6addr));
262 sa->sin6_port = htons(port);
263 ai0->ai_family = PF_INET6;
264 ai0->ai_socktype = list[i].socktype;
265 ai0->ai_protocol = hint_protocol ? hint_protocol : list[i].protocol;
266 ai0->ai_addrlen = sizeof(struct sockaddr_in6);
267 ai0->ai_addr = (struct sockaddr *)sa;
268 ai0->ai_canonname = NULL;
269 ai0->ai_next = ai;
270 ai = ai0;
271 }
272 }
273 }
274 else
275#endif
276 if ((hint_family == PF_UNSPEC || hint_family == PF_INET) &&
277 strspn(node, "0123456789.") == strlen(node) &&
278 inet_pton(AF_INET, node, ipv4addr)) {
279 int i;
280 for (i = numberof(list)-1; 0 <= i; i--) {
281 if ((hint_socktype == 0 || hint_socktype == list[i].socktype) &&
282 (hint_protocol == 0 || list[i].protocol == 0 || hint_protocol == list[i].protocol)) {
283 struct addrinfo *ai0 = xcalloc(1, sizeof(struct addrinfo));
284 struct sockaddr_in *sa = xmalloc(sizeof(struct sockaddr_in));
285 INIT_SOCKADDR_IN(sa, sizeof(struct sockaddr_in));
286 memcpy(&sa->sin_addr, ipv4addr, sizeof(ipv4addr));
287 sa->sin_port = htons(port);
288 ai0->ai_family = PF_INET;
289 ai0->ai_socktype = list[i].socktype;
290 ai0->ai_protocol = hint_protocol ? hint_protocol : list[i].protocol;
291 ai0->ai_addrlen = sizeof(struct sockaddr_in);
292 ai0->ai_addr = (struct sockaddr *)sa;
293 ai0->ai_canonname = NULL;
294 ai0->ai_next = ai;
295 ai = ai0;
296 }
297 }
298 }
299 if (ai) {
300 *res = ai;
301 return 0;
302 }
303 }
304#endif
305 return EAI_FAIL;
306}
307
308int
309rb_getaddrinfo(const char *node, const char *service,
310 const struct addrinfo *hints,
311 struct rb_addrinfo **res)
312{
313 struct addrinfo *ai;
314 int ret;
315 int allocated_by_malloc = 0;
316
317 ret = numeric_getaddrinfo(node, service, hints, &ai);
318 if (ret == 0)
319 allocated_by_malloc = 1;
320 else {
321#ifdef GETADDRINFO_EMU
322 ret = getaddrinfo(node, service, hints, &ai);
323#else
324 struct getaddrinfo_arg arg;
325 MEMZERO(&arg, struct getaddrinfo_arg, 1);
326 arg.node = node;
327 arg.service = service;
328 arg.hints = hints;
329 arg.res = &ai;
330 ret = (int)(VALUE)rb_thread_call_without_gvl(nogvl_getaddrinfo, &arg, RUBY_UBF_IO, 0);
331#endif
332 }
333
334 if (ret == 0) {
335 *res = (struct rb_addrinfo *)xmalloc(sizeof(struct rb_addrinfo));
336 (*res)->allocated_by_malloc = allocated_by_malloc;
337 (*res)->ai = ai;
338 }
339 return ret;
340}
341
342#ifdef HAVE_GETADDRINFO_A
343int
344rb_getaddrinfo_a(const char *node, const char *service,
345 const struct addrinfo *hints,
346 struct rb_addrinfo **res, struct timespec *timeout)
347{
348 struct addrinfo *ai;
349 int ret;
350 int allocated_by_malloc = 0;
351
352 ret = numeric_getaddrinfo(node, service, hints, &ai);
353 if (ret == 0)
354 allocated_by_malloc = 1;
355 else {
356 struct gai_suspend_arg arg;
357 struct gaicb *reqs[1];
358 struct gaicb req;
359
360 req.ar_name = node;
361 req.ar_service = service;
362 req.ar_request = hints;
363
364 reqs[0] = &req;
365 ret = getaddrinfo_a(GAI_NOWAIT, reqs, 1, NULL);
366 if (ret) return ret;
367
368 arg.req = &req;
369 arg.timeout = timeout;
370
371 ret = (int)(VALUE)rb_thread_call_without_gvl(nogvl_gai_suspend, &arg, RUBY_UBF_IO, 0);
372
373 if (ret) {
374 /* on Ubuntu 18.04 (or other systems), gai_suspend(3) returns EAI_SYSTEM/ENOENT on timeout */
375 if (ret == EAI_SYSTEM && errno == ENOENT) {
376 return EAI_AGAIN;
377 } else {
378 return ret;
379 }
380 }
381
382 ret = gai_error(reqs[0]);
383 ai = reqs[0]->ar_result;
384 }
385
386 if (ret == 0) {
387 *res = (struct rb_addrinfo *)xmalloc(sizeof(struct rb_addrinfo));
388 (*res)->allocated_by_malloc = allocated_by_malloc;
389 (*res)->ai = ai;
390 }
391 return ret;
392}
393#endif
394
395void
397{
398 if (!ai->allocated_by_malloc)
399 freeaddrinfo(ai->ai);
400 else {
401 struct addrinfo *ai1, *ai2;
402 ai1 = ai->ai;
403 while (ai1) {
404 ai2 = ai1->ai_next;
405 xfree(ai1->ai_addr);
406 xfree(ai1);
407 ai1 = ai2;
408 }
409 }
410 xfree(ai);
411}
412
413#ifndef GETADDRINFO_EMU
415{
416 const struct sockaddr *sa;
418 int flags;
419 char *host;
420 size_t hostlen;
421 char *serv;
422 size_t servlen;
423};
424
425static void *
426nogvl_getnameinfo(void *arg)
427{
428 struct getnameinfo_arg *ptr = arg;
429 return (void *)(VALUE)getnameinfo(ptr->sa, ptr->salen,
430 ptr->host, (socklen_t)ptr->hostlen,
431 ptr->serv, (socklen_t)ptr->servlen,
432 ptr->flags);
433}
434#endif
435
436int
437rb_getnameinfo(const struct sockaddr *sa, socklen_t salen,
438 char *host, size_t hostlen,
439 char *serv, size_t servlen, int flags)
440{
441#ifdef GETADDRINFO_EMU
443#else
444 struct getnameinfo_arg arg;
445 int ret;
446 arg.sa = sa;
447 arg.salen = salen;
448 arg.host = host;
449 arg.hostlen = hostlen;
450 arg.serv = serv;
451 arg.servlen = servlen;
452 arg.flags = flags;
453 ret = (int)(VALUE)rb_thread_call_without_gvl(nogvl_getnameinfo, &arg, RUBY_UBF_IO, 0);
454 return ret;
455#endif
456}
457
458static void
459make_ipaddr0(struct sockaddr *addr, socklen_t addrlen, char *buf, size_t buflen)
460{
461 int error;
462
463 error = rb_getnameinfo(addr, addrlen, buf, buflen, NULL, 0, NI_NUMERICHOST);
464 if (error) {
465 rsock_raise_socket_error("getnameinfo", error);
466 }
467}
468
469VALUE
470rsock_make_ipaddr(struct sockaddr *addr, socklen_t addrlen)
471{
472 char hbuf[1024];
473
474 make_ipaddr0(addr, addrlen, hbuf, sizeof(hbuf));
475 return rb_str_new2(hbuf);
476}
477
478static void
479make_inetaddr(unsigned int host, char *buf, size_t buflen)
480{
481 struct sockaddr_in sin;
482
483 INIT_SOCKADDR_IN(&sin, sizeof(sin));
484 sin.sin_addr.s_addr = host;
485 make_ipaddr0((struct sockaddr*)&sin, sizeof(sin), buf, buflen);
486}
487
488static int
489str_is_number(const char *p)
490{
491 char *ep;
492
493 if (!p || *p == '\0')
494 return 0;
495 ep = NULL;
496 (void)STRTOUL(p, &ep, 10);
497 if (ep && *ep == '\0')
498 return 1;
499 else
500 return 0;
501}
502
503#define str_equal(ptr, len, name) \
504 ((ptr)[0] == name[0] && \
505 rb_strlen_lit(name) == (len) && memcmp(ptr, name, len) == 0)
506
507static char*
508host_str(VALUE host, char *hbuf, size_t hbuflen, int *flags_ptr)
509{
510 if (NIL_P(host)) {
511 return NULL;
512 }
513 else if (rb_obj_is_kind_of(host, rb_cInteger)) {
514 unsigned int i = NUM2UINT(host);
515
516 make_inetaddr(htonl(i), hbuf, hbuflen);
517 if (flags_ptr) *flags_ptr |= AI_NUMERICHOST;
518 return hbuf;
519 }
520 else {
521 const char *name;
522 size_t len;
523
524 StringValueCStr(host);
525 RSTRING_GETMEM(host, name, len);
526 if (!len || str_equal(name, len, "<any>")) {
527 make_inetaddr(INADDR_ANY, hbuf, hbuflen);
528 if (flags_ptr) *flags_ptr |= AI_NUMERICHOST;
529 }
530 else if (str_equal(name, len, "<broadcast>")) {
531 make_inetaddr(INADDR_BROADCAST, hbuf, hbuflen);
532 if (flags_ptr) *flags_ptr |= AI_NUMERICHOST;
533 }
534 else if (len >= hbuflen) {
535 rb_raise(rb_eArgError, "hostname too long (%"PRIuSIZE")",
536 len);
537 }
538 else {
539 memcpy(hbuf, name, len);
540 hbuf[len] = '\0';
541 }
542 return hbuf;
543 }
544}
545
546static char*
547port_str(VALUE port, char *pbuf, size_t pbuflen, int *flags_ptr)
548{
549 if (NIL_P(port)) {
550 return 0;
551 }
552 else if (FIXNUM_P(port)) {
553 snprintf(pbuf, pbuflen, "%ld", FIX2LONG(port));
554#ifdef AI_NUMERICSERV
555 if (flags_ptr) *flags_ptr |= AI_NUMERICSERV;
556#endif
557 return pbuf;
558 }
559 else {
560 const char *serv;
561 size_t len;
562
563 StringValueCStr(port);
564 RSTRING_GETMEM(port, serv, len);
565 if (len >= pbuflen) {
566 rb_raise(rb_eArgError, "service name too long (%"PRIuSIZE")",
567 len);
568 }
569 memcpy(pbuf, serv, len);
570 pbuf[len] = '\0';
571 return pbuf;
572 }
573}
574
575struct rb_addrinfo*
576rsock_getaddrinfo(VALUE host, VALUE port, struct addrinfo *hints, int socktype_hack)
577{
578 struct rb_addrinfo* res = NULL;
579 char *hostp, *portp;
580 int error;
581 char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
582 int additional_flags = 0;
583
584 hostp = host_str(host, hbuf, sizeof(hbuf), &additional_flags);
585 portp = port_str(port, pbuf, sizeof(pbuf), &additional_flags);
586
587 if (socktype_hack && hints->ai_socktype == 0 && str_is_number(portp)) {
588 hints->ai_socktype = SOCK_DGRAM;
589 }
590 hints->ai_flags |= additional_flags;
591
592 error = rb_getaddrinfo(hostp, portp, hints, &res);
593 if (error) {
594 if (hostp && hostp[strlen(hostp)-1] == '\n') {
595 rb_raise(rb_eSocket, "newline at the end of hostname");
596 }
597 rsock_raise_socket_error("getaddrinfo", error);
598 }
599
600 return res;
601}
602
603#ifdef HAVE_GETADDRINFO_A
604static struct rb_addrinfo*
605rsock_getaddrinfo_a(VALUE host, VALUE port, struct addrinfo *hints, int socktype_hack, VALUE timeout)
606{
607 struct rb_addrinfo* res = NULL;
608 char *hostp, *portp;
609 int error;
610 char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
611 int additional_flags = 0;
612
613 hostp = host_str(host, hbuf, sizeof(hbuf), &additional_flags);
614 portp = port_str(port, pbuf, sizeof(pbuf), &additional_flags);
615
616 if (socktype_hack && hints->ai_socktype == 0 && str_is_number(portp)) {
617 hints->ai_socktype = SOCK_DGRAM;
618 }
619 hints->ai_flags |= additional_flags;
620
621 if (NIL_P(timeout)) {
622 error = rb_getaddrinfo(hostp, portp, hints, &res);
623 } else {
624 struct timespec _timeout = rb_time_timespec_interval(timeout);
625 error = rb_getaddrinfo_a(hostp, portp, hints, &res, &_timeout);
626 }
627
628 if (error) {
629 if (hostp && hostp[strlen(hostp)-1] == '\n') {
630 rb_raise(rb_eSocket, "newline at the end of hostname");
631 }
632 rsock_raise_socket_error("getaddrinfo_a", error);
633 }
634
635 return res;
636}
637#endif
638
639int
641{
642 struct sockaddr sa = { 0 };
643 socklen_t sa_len = sizeof(sa);
644
645 if (fd < 0 || getsockname(fd, &sa, &sa_len) != 0 ||
646 (size_t)sa_len < offsetof(struct sockaddr, sa_family) + sizeof(sa.sa_family)) {
647 return AF_UNSPEC;
648 }
649 return sa.sa_family;
650}
651
652struct rb_addrinfo*
653rsock_addrinfo(VALUE host, VALUE port, int family, int socktype, int flags)
654{
655 struct addrinfo hints;
656
657 MEMZERO(&hints, struct addrinfo, 1);
658 hints.ai_family = family;
659 hints.ai_socktype = socktype;
660 hints.ai_flags = flags;
661 return rsock_getaddrinfo(host, port, &hints, 1);
662}
663
664VALUE
665rsock_ipaddr(struct sockaddr *sockaddr, socklen_t sockaddrlen, int norevlookup)
666{
667 VALUE family, port, addr1, addr2;
668 VALUE ary;
669 int error;
670 char hbuf[1024], pbuf[1024];
671 ID id;
672
673 id = rsock_intern_family(sockaddr->sa_family);
674 if (id) {
675 family = rb_str_dup(rb_id2str(id));
676 }
677 else {
678 sprintf(pbuf, "unknown:%d", sockaddr->sa_family);
679 family = rb_str_new2(pbuf);
680 }
681
682 addr1 = Qnil;
683 if (!norevlookup) {
684 error = rb_getnameinfo(sockaddr, sockaddrlen, hbuf, sizeof(hbuf),
685 NULL, 0, 0);
686 if (! error) {
687 addr1 = rb_str_new2(hbuf);
688 }
689 }
690 error = rb_getnameinfo(sockaddr, sockaddrlen, hbuf, sizeof(hbuf),
691 pbuf, sizeof(pbuf), NI_NUMERICHOST | NI_NUMERICSERV);
692 if (error) {
693 rsock_raise_socket_error("getnameinfo", error);
694 }
695 addr2 = rb_str_new2(hbuf);
696 if (addr1 == Qnil) {
697 addr1 = addr2;
698 }
699 port = INT2FIX(atoi(pbuf));
700 ary = rb_ary_new3(4, family, port, addr1, addr2);
701
702 return ary;
703}
704
705#ifdef HAVE_SYS_UN_H
706static long
707unixsocket_len(const struct sockaddr_un *su, socklen_t socklen)
708{
709 const char *s = su->sun_path, *e = (const char*)su + socklen;
710 while (s < e && *(e-1) == '\0')
711 e--;
712 return e - s;
713}
714
715VALUE
716rsock_unixpath_str(struct sockaddr_un *sockaddr, socklen_t len)
717{
718 long n = unixsocket_len(sockaddr, len);
719 if (n >= 0)
720 return rb_str_new(sockaddr->sun_path, n);
721 else
722 return rb_str_new2("");
723}
724
725VALUE
726rsock_unixaddr(struct sockaddr_un *sockaddr, socklen_t len)
727{
728 return rb_assoc_new(rb_str_new2("AF_UNIX"),
729 rsock_unixpath_str(sockaddr, len));
730}
731
733rsock_unix_sockaddr_len(VALUE path)
734{
735#ifdef __linux__
736 if (RSTRING_LEN(path) == 0) {
737 /* autobind; see unix(7) for details. */
738 return (socklen_t) sizeof(sa_family_t);
739 }
740 else if (RSTRING_PTR(path)[0] == '\0') {
741 /* abstract namespace; see unix(7) for details. */
742 if (SOCKLEN_MAX - offsetof(struct sockaddr_un, sun_path) < (size_t)RSTRING_LEN(path))
743 rb_raise(rb_eArgError, "Linux abstract socket too long");
744 return (socklen_t) offsetof(struct sockaddr_un, sun_path) +
746 }
747 else {
748#endif
749 return (socklen_t) sizeof(struct sockaddr_un);
750#ifdef __linux__
751 }
752#endif
753}
754#endif
755
759 VALUE (*ipaddr)(struct sockaddr*, socklen_t);
760};
761
762static VALUE
763make_hostent_internal(VALUE v)
764{
765 struct hostent_arg *arg = (void *)v;
766 VALUE host = arg->host;
767 struct addrinfo* addr = arg->addr->ai;
768 VALUE (*ipaddr)(struct sockaddr*, socklen_t) = arg->ipaddr;
769
770 struct addrinfo *ai;
771 struct hostent *h;
772 VALUE ary, names;
773 char **pch;
774 const char* hostp;
775 char hbuf[NI_MAXHOST];
776
777 ary = rb_ary_new();
778 if (addr->ai_canonname) {
779 hostp = addr->ai_canonname;
780 }
781 else {
782 hostp = host_str(host, hbuf, sizeof(hbuf), NULL);
783 }
784 rb_ary_push(ary, rb_str_new2(hostp));
785
786 if (addr->ai_canonname && strlen(addr->ai_canonname) < NI_MAXHOST &&
787 (h = gethostbyname(addr->ai_canonname))) {
788 names = rb_ary_new();
789 if (h->h_aliases != NULL) {
790 for (pch = h->h_aliases; *pch; pch++) {
792 }
793 }
794 }
795 else {
796 names = rb_ary_new2(0);
797 }
798 rb_ary_push(ary, names);
799 rb_ary_push(ary, INT2NUM(addr->ai_family));
800 for (ai = addr; ai; ai = ai->ai_next) {
801 rb_ary_push(ary, (*ipaddr)(ai->ai_addr, ai->ai_addrlen));
802 }
803
804 return ary;
805}
806
807VALUE
809{
810 struct rb_addrinfo *addr = (struct rb_addrinfo *)arg;
811 rb_freeaddrinfo(addr);
812 return Qnil;
813}
814
815VALUE
816rsock_make_hostent(VALUE host, struct rb_addrinfo *addr, VALUE (*ipaddr)(struct sockaddr *, socklen_t))
817{
818 struct hostent_arg arg;
819
820 arg.host = host;
821 arg.addr = addr;
822 arg.ipaddr = ipaddr;
823 return rb_ensure(make_hostent_internal, (VALUE)&arg,
825}
826
827typedef struct {
836
837static void
838addrinfo_mark(void *ptr)
839{
840 rb_addrinfo_t *rai = ptr;
842 rb_gc_mark(rai->canonname);
843}
844
845#define addrinfo_free RUBY_TYPED_DEFAULT_FREE
846
847static size_t
848addrinfo_memsize(const void *ptr)
849{
850 return sizeof(rb_addrinfo_t);
851}
852
853static const rb_data_type_t addrinfo_type = {
854 "socket/addrinfo",
855 {addrinfo_mark, addrinfo_free, addrinfo_memsize,},
856};
857
858static VALUE
859addrinfo_s_allocate(VALUE klass)
860{
861 return TypedData_Wrap_Struct(klass, &addrinfo_type, 0);
862}
863
864#define IS_ADDRINFO(obj) rb_typeddata_is_kind_of((obj), &addrinfo_type)
865static inline rb_addrinfo_t *
866check_addrinfo(VALUE self)
867{
868 return rb_check_typeddata(self, &addrinfo_type);
869}
870
871static rb_addrinfo_t *
872get_addrinfo(VALUE self)
873{
874 rb_addrinfo_t *rai = check_addrinfo(self);
875
876 if (!rai) {
877 rb_raise(rb_eTypeError, "uninitialized socket address");
878 }
879 return rai;
880}
881
882
883static rb_addrinfo_t *
884alloc_addrinfo(void)
885{
887 rai->inspectname = Qnil;
888 rai->canonname = Qnil;
889 return rai;
890}
891
892static void
893init_addrinfo(rb_addrinfo_t *rai, struct sockaddr *sa, socklen_t len,
894 int pfamily, int socktype, int protocol,
895 VALUE canonname, VALUE inspectname)
896{
897 if ((socklen_t)sizeof(rai->addr) < len)
898 rb_raise(rb_eArgError, "sockaddr string too big");
899 memcpy((void *)&rai->addr, (void *)sa, len);
900 rai->sockaddr_len = len;
901
902 rai->pfamily = pfamily;
903 rai->socktype = socktype;
904 rai->protocol = protocol;
905 rai->canonname = canonname;
906 rai->inspectname = inspectname;
907}
908
909VALUE
910rsock_addrinfo_new(struct sockaddr *addr, socklen_t len,
911 int family, int socktype, int protocol,
912 VALUE canonname, VALUE inspectname)
913{
914 VALUE a;
915 rb_addrinfo_t *rai;
916
917 a = addrinfo_s_allocate(rb_cAddrinfo);
918 DATA_PTR(a) = rai = alloc_addrinfo();
919 init_addrinfo(rai, addr, len, family, socktype, protocol, canonname, inspectname);
920 return a;
921}
922
923static struct rb_addrinfo *
924call_getaddrinfo(VALUE node, VALUE service,
925 VALUE family, VALUE socktype, VALUE protocol, VALUE flags,
926 int socktype_hack, VALUE timeout)
927{
928 struct addrinfo hints;
929 struct rb_addrinfo *res;
930
931 MEMZERO(&hints, struct addrinfo, 1);
932 hints.ai_family = NIL_P(family) ? PF_UNSPEC : rsock_family_arg(family);
933
934 if (!NIL_P(socktype)) {
935 hints.ai_socktype = rsock_socktype_arg(socktype);
936 }
937 if (!NIL_P(protocol)) {
938 hints.ai_protocol = NUM2INT(protocol);
939 }
940 if (!NIL_P(flags)) {
941 hints.ai_flags = NUM2INT(flags);
942 }
943
944#ifdef HAVE_GETADDRINFO_A
945 if (NIL_P(timeout)) {
946 res = rsock_getaddrinfo(node, service, &hints, socktype_hack);
947 } else {
948 res = rsock_getaddrinfo_a(node, service, &hints, socktype_hack, timeout);
949 }
950#else
951 res = rsock_getaddrinfo(node, service, &hints, socktype_hack);
952#endif
953
954 if (res == NULL)
955 rb_raise(rb_eSocket, "host not found");
956 return res;
957}
958
959static VALUE make_inspectname(VALUE node, VALUE service, struct addrinfo *res);
960
961static void
962init_addrinfo_getaddrinfo(rb_addrinfo_t *rai, VALUE node, VALUE service,
963 VALUE family, VALUE socktype, VALUE protocol, VALUE flags,
964 VALUE inspectnode, VALUE inspectservice)
965{
966 struct rb_addrinfo *res = call_getaddrinfo(node, service, family, socktype, protocol, flags, 1, Qnil);
967 VALUE canonname;
968 VALUE inspectname = rb_str_equal(node, inspectnode) ? Qnil : make_inspectname(inspectnode, inspectservice, res->ai);
969
970 canonname = Qnil;
971 if (res->ai->ai_canonname) {
972 canonname = rb_str_new_cstr(res->ai->ai_canonname);
973 OBJ_FREEZE(canonname);
974 }
975
976 init_addrinfo(rai, res->ai->ai_addr, res->ai->ai_addrlen,
977 NUM2INT(family), NUM2INT(socktype), NUM2INT(protocol),
978 canonname, inspectname);
979
980 rb_freeaddrinfo(res);
981}
982
983static VALUE
984make_inspectname(VALUE node, VALUE service, struct addrinfo *res)
985{
986 VALUE inspectname = Qnil;
987
988 if (res) {
989 /* drop redundant information which also shown in address:port part. */
990 char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
991 int ret;
992 ret = rb_getnameinfo(res->ai_addr, res->ai_addrlen, hbuf,
993 sizeof(hbuf), pbuf, sizeof(pbuf),
995 if (ret == 0) {
996 if (RB_TYPE_P(node, T_STRING) && strcmp(hbuf, RSTRING_PTR(node)) == 0)
997 node = Qnil;
998 if (RB_TYPE_P(service, T_STRING) && strcmp(pbuf, RSTRING_PTR(service)) == 0)
999 service = Qnil;
1000 else if (RB_TYPE_P(service, T_FIXNUM) && atoi(pbuf) == FIX2INT(service))
1001 service = Qnil;
1002 }
1003 }
1004
1005 if (RB_TYPE_P(node, T_STRING)) {
1006 inspectname = rb_str_dup(node);
1007 }
1008 if (RB_TYPE_P(service, T_STRING)) {
1009 if (NIL_P(inspectname))
1010 inspectname = rb_sprintf(":%s", StringValueCStr(service));
1011 else
1012 rb_str_catf(inspectname, ":%s", StringValueCStr(service));
1013 }
1014 else if (RB_TYPE_P(service, T_FIXNUM) && FIX2INT(service) != 0)
1015 {
1016 if (NIL_P(inspectname))
1017 inspectname = rb_sprintf(":%d", FIX2INT(service));
1018 else
1019 rb_str_catf(inspectname, ":%d", FIX2INT(service));
1020 }
1021 if (!NIL_P(inspectname)) {
1022 OBJ_FREEZE(inspectname);
1023 }
1024 return inspectname;
1025}
1026
1027static VALUE
1028addrinfo_firstonly_new(VALUE node, VALUE service, VALUE family, VALUE socktype, VALUE protocol, VALUE flags)
1029{
1030 VALUE ret;
1031 VALUE canonname;
1032 VALUE inspectname;
1033
1034 struct rb_addrinfo *res = call_getaddrinfo(node, service, family, socktype, protocol, flags, 0, Qnil);
1035
1036 inspectname = make_inspectname(node, service, res->ai);
1037
1038 canonname = Qnil;
1039 if (res->ai->ai_canonname) {
1040 canonname = rb_str_new_cstr(res->ai->ai_canonname);
1041 OBJ_FREEZE(canonname);
1042 }
1043
1044 ret = rsock_addrinfo_new(res->ai->ai_addr, res->ai->ai_addrlen,
1045 res->ai->ai_family, res->ai->ai_socktype,
1046 res->ai->ai_protocol,
1047 canonname, inspectname);
1048
1049 rb_freeaddrinfo(res);
1050 return ret;
1051}
1052
1053static VALUE
1054addrinfo_list_new(VALUE node, VALUE service, VALUE family, VALUE socktype, VALUE protocol, VALUE flags, VALUE timeout)
1055{
1056 VALUE ret;
1057 struct addrinfo *r;
1058 VALUE inspectname;
1059
1060 struct rb_addrinfo *res = call_getaddrinfo(node, service, family, socktype, protocol, flags, 0, timeout);
1061
1062 inspectname = make_inspectname(node, service, res->ai);
1063
1064 ret = rb_ary_new();
1065 for (r = res->ai; r; r = r->ai_next) {
1066 VALUE addr;
1067 VALUE canonname = Qnil;
1068
1069 if (r->ai_canonname) {
1070 canonname = rb_str_new_cstr(r->ai_canonname);
1071 OBJ_FREEZE(canonname);
1072 }
1073
1076 canonname, inspectname);
1077
1078 rb_ary_push(ret, addr);
1079 }
1080
1081 rb_freeaddrinfo(res);
1082 return ret;
1083}
1084
1085
1086#ifdef HAVE_SYS_UN_H
1087static void
1088init_unix_addrinfo(rb_addrinfo_t *rai, VALUE path, int socktype)
1089{
1090 struct sockaddr_un un;
1091 socklen_t len;
1092
1094
1095 if (sizeof(un.sun_path) < (size_t)RSTRING_LEN(path))
1097 "too long unix socket path (%"PRIuSIZE" bytes given but %"PRIuSIZE" bytes max)",
1098 (size_t)RSTRING_LEN(path), sizeof(un.sun_path));
1099
1100 INIT_SOCKADDR_UN(&un, sizeof(struct sockaddr_un));
1101 memcpy((void*)&un.sun_path, RSTRING_PTR(path), RSTRING_LEN(path));
1102
1103 len = rsock_unix_sockaddr_len(path);
1104 init_addrinfo(rai, (struct sockaddr *)&un, len,
1105 PF_UNIX, socktype, 0, Qnil, Qnil);
1106}
1107
1108static long
1109rai_unixsocket_len(const rb_addrinfo_t *rai)
1110{
1111 return unixsocket_len(&rai->addr.un, rai->sockaddr_len);
1112}
1113#endif
1114
1115/*
1116 * call-seq:
1117 * Addrinfo.new(sockaddr) => addrinfo
1118 * Addrinfo.new(sockaddr, family) => addrinfo
1119 * Addrinfo.new(sockaddr, family, socktype) => addrinfo
1120 * Addrinfo.new(sockaddr, family, socktype, protocol) => addrinfo
1121 *
1122 * returns a new instance of Addrinfo.
1123 * The instance contains sockaddr, family, socktype, protocol.
1124 * sockaddr means struct sockaddr which can be used for connect(2), etc.
1125 * family, socktype and protocol are integers which is used for arguments of socket(2).
1126 *
1127 * sockaddr is specified as an array or a string.
1128 * The array should be compatible to the value of IPSocket#addr or UNIXSocket#addr.
1129 * The string should be struct sockaddr as generated by
1130 * Socket.sockaddr_in or Socket.unpack_sockaddr_un.
1131 *
1132 * sockaddr examples:
1133 * - ["AF_INET", 46102, "localhost.localdomain", "127.0.0.1"]
1134 * - ["AF_INET6", 42304, "ip6-localhost", "::1"]
1135 * - ["AF_UNIX", "/tmp/sock"]
1136 * - Socket.sockaddr_in("smtp", "2001:DB8::1")
1137 * - Socket.sockaddr_in(80, "172.18.22.42")
1138 * - Socket.sockaddr_in(80, "www.ruby-lang.org")
1139 * - Socket.sockaddr_un("/tmp/sock")
1140 *
1141 * In an AF_INET/AF_INET6 sockaddr array, the 4th element,
1142 * numeric IP address, is used to construct socket address in the Addrinfo instance.
1143 * If the 3rd element, textual host name, is non-nil, it is also recorded but used only for Addrinfo#inspect.
1144 *
1145 * family is specified as an integer to specify the protocol family such as Socket::PF_INET.
1146 * It can be a symbol or a string which is the constant name
1147 * with or without PF_ prefix such as :INET, :INET6, :UNIX, "PF_INET", etc.
1148 * If omitted, PF_UNSPEC is assumed.
1149 *
1150 * socktype is specified as an integer to specify the socket type such as Socket::SOCK_STREAM.
1151 * It can be a symbol or a string which is the constant name
1152 * with or without SOCK_ prefix such as :STREAM, :DGRAM, :RAW, "SOCK_STREAM", etc.
1153 * If omitted, 0 is assumed.
1154 *
1155 * protocol is specified as an integer to specify the protocol such as Socket::IPPROTO_TCP.
1156 * It must be an integer, unlike family and socktype.
1157 * If omitted, 0 is assumed.
1158 * Note that 0 is reasonable value for most protocols, except raw socket.
1159 *
1160 */
1161static VALUE
1162addrinfo_initialize(int argc, VALUE *argv, VALUE self)
1163{
1164 rb_addrinfo_t *rai;
1165 VALUE sockaddr_arg, sockaddr_ary, pfamily, socktype, protocol;
1166 int i_pfamily, i_socktype, i_protocol;
1167 struct sockaddr *sockaddr_ptr;
1168 socklen_t sockaddr_len;
1169 VALUE canonname = Qnil, inspectname = Qnil;
1170
1171 if (check_addrinfo(self))
1172 rb_raise(rb_eTypeError, "already initialized socket address");
1173 DATA_PTR(self) = rai = alloc_addrinfo();
1174
1175 rb_scan_args(argc, argv, "13", &sockaddr_arg, &pfamily, &socktype, &protocol);
1176
1177 i_pfamily = NIL_P(pfamily) ? PF_UNSPEC : rsock_family_arg(pfamily);
1178 i_socktype = NIL_P(socktype) ? 0 : rsock_socktype_arg(socktype);
1179 i_protocol = NIL_P(protocol) ? 0 : NUM2INT(protocol);
1180
1181 sockaddr_ary = rb_check_array_type(sockaddr_arg);
1182 if (!NIL_P(sockaddr_ary)) {
1183 VALUE afamily = rb_ary_entry(sockaddr_ary, 0);
1184 int af;
1185 StringValue(afamily);
1186 if (rsock_family_to_int(RSTRING_PTR(afamily), RSTRING_LEN(afamily), &af) == -1)
1187 rb_raise(rb_eSocket, "unknown address family: %s", StringValueCStr(afamily));
1188 switch (af) {
1189 case AF_INET: /* ["AF_INET", 46102, "localhost.localdomain", "127.0.0.1"] */
1190#ifdef INET6
1191 case AF_INET6: /* ["AF_INET6", 42304, "ip6-localhost", "::1"] */
1192#endif
1193 {
1194 VALUE service = rb_ary_entry(sockaddr_ary, 1);
1195 VALUE nodename = rb_ary_entry(sockaddr_ary, 2);
1196 VALUE numericnode = rb_ary_entry(sockaddr_ary, 3);
1197 int flags;
1198
1199 service = INT2NUM(NUM2INT(service));
1200 if (!NIL_P(nodename))
1201 StringValue(nodename);
1202 StringValue(numericnode);
1203 flags = AI_NUMERICHOST;
1204#ifdef AI_NUMERICSERV
1205 flags |= AI_NUMERICSERV;
1206#endif
1207
1208 init_addrinfo_getaddrinfo(rai, numericnode, service,
1209 INT2NUM(i_pfamily ? i_pfamily : af), INT2NUM(i_socktype), INT2NUM(i_protocol),
1210 INT2NUM(flags),
1211 nodename, service);
1212 break;
1213 }
1214
1215#ifdef HAVE_SYS_UN_H
1216 case AF_UNIX: /* ["AF_UNIX", "/tmp/sock"] */
1217 {
1218 VALUE path = rb_ary_entry(sockaddr_ary, 1);
1220 init_unix_addrinfo(rai, path, SOCK_STREAM);
1221 break;
1222 }
1223#endif
1224
1225 default:
1226 rb_raise(rb_eSocket, "unexpected address family");
1227 }
1228 }
1229 else {
1230 StringValue(sockaddr_arg);
1231 sockaddr_ptr = (struct sockaddr *)RSTRING_PTR(sockaddr_arg);
1232 sockaddr_len = RSTRING_SOCKLEN(sockaddr_arg);
1233 init_addrinfo(rai, sockaddr_ptr, sockaddr_len,
1234 i_pfamily, i_socktype, i_protocol,
1235 canonname, inspectname);
1236 }
1237
1238 return self;
1239}
1240
1241static int
1242get_afamily(const struct sockaddr *addr, socklen_t len)
1243{
1244 if ((socklen_t)((const char*)&addr->sa_family + sizeof(addr->sa_family) - (char*)addr) <= len)
1245 return addr->sa_family;
1246 else
1247 return AF_UNSPEC;
1248}
1249
1250static int
1251ai_get_afamily(const rb_addrinfo_t *rai)
1252{
1253 return get_afamily(&rai->addr.addr, rai->sockaddr_len);
1254}
1255
1256static VALUE
1257inspect_sockaddr(VALUE addrinfo, VALUE ret)
1258{
1259 rb_addrinfo_t *rai = get_addrinfo(addrinfo);
1260 union_sockaddr *sockaddr = &rai->addr;
1261 socklen_t socklen = rai->sockaddr_len;
1262 return rsock_inspect_sockaddr((struct sockaddr *)sockaddr, socklen, ret);
1263}
1264
1265VALUE
1266rsock_inspect_sockaddr(struct sockaddr *sockaddr_arg, socklen_t socklen, VALUE ret)
1267{
1268 union_sockaddr *sockaddr = (union_sockaddr *)sockaddr_arg;
1269 if (socklen == 0) {
1270 rb_str_cat2(ret, "empty-sockaddr");
1271 }
1272 else if ((long)socklen < ((char*)&sockaddr->addr.sa_family + sizeof(sockaddr->addr.sa_family)) - (char*)sockaddr)
1273 rb_str_cat2(ret, "too-short-sockaddr");
1274 else {
1275 switch (sockaddr->addr.sa_family) {
1276 case AF_UNSPEC:
1277 {
1278 rb_str_cat2(ret, "UNSPEC");
1279 break;
1280 }
1281
1282 case AF_INET:
1283 {
1284 struct sockaddr_in *addr;
1285 int port;
1286 addr = &sockaddr->in;
1287 if ((socklen_t)(((char*)&addr->sin_addr)-(char*)addr+0+1) <= socklen)
1288 rb_str_catf(ret, "%d", ((unsigned char*)&addr->sin_addr)[0]);
1289 else
1290 rb_str_cat2(ret, "?");
1291 if ((socklen_t)(((char*)&addr->sin_addr)-(char*)addr+1+1) <= socklen)
1292 rb_str_catf(ret, ".%d", ((unsigned char*)&addr->sin_addr)[1]);
1293 else
1294 rb_str_cat2(ret, ".?");
1295 if ((socklen_t)(((char*)&addr->sin_addr)-(char*)addr+2+1) <= socklen)
1296 rb_str_catf(ret, ".%d", ((unsigned char*)&addr->sin_addr)[2]);
1297 else
1298 rb_str_cat2(ret, ".?");
1299 if ((socklen_t)(((char*)&addr->sin_addr)-(char*)addr+3+1) <= socklen)
1300 rb_str_catf(ret, ".%d", ((unsigned char*)&addr->sin_addr)[3]);
1301 else
1302 rb_str_cat2(ret, ".?");
1303
1304 if ((socklen_t)(((char*)&addr->sin_port)-(char*)addr+(int)sizeof(addr->sin_port)) < socklen) {
1305 port = ntohs(addr->sin_port);
1306 if (port)
1307 rb_str_catf(ret, ":%d", port);
1308 }
1309 else {
1310 rb_str_cat2(ret, ":?");
1311 }
1312 if ((socklen_t)sizeof(struct sockaddr_in) != socklen)
1313 rb_str_catf(ret, " (%d bytes for %d bytes sockaddr_in)",
1314 (int)socklen,
1315 (int)sizeof(struct sockaddr_in));
1316 break;
1317 }
1318
1319#ifdef AF_INET6
1320 case AF_INET6:
1321 {
1322 struct sockaddr_in6 *addr;
1323 char hbuf[1024];
1324 int port;
1325 int error;
1326 if (socklen < (socklen_t)sizeof(struct sockaddr_in6)) {
1327 rb_str_catf(ret, "too-short-AF_INET6-sockaddr %d bytes", (int)socklen);
1328 }
1329 else {
1330 addr = &sockaddr->in6;
1331 /* use getnameinfo for scope_id.
1332 * RFC 4007: IPv6 Scoped Address Architecture
1333 * draft-ietf-ipv6-scope-api-00.txt: Scoped Address Extensions to the IPv6 Basic Socket API
1334 */
1335 error = getnameinfo(&sockaddr->addr, socklen,
1336 hbuf, (socklen_t)sizeof(hbuf), NULL, 0,
1338 if (error) {
1339 rsock_raise_socket_error("getnameinfo", error);
1340 }
1341 if (addr->sin6_port == 0) {
1342 rb_str_cat2(ret, hbuf);
1343 }
1344 else {
1345 port = ntohs(addr->sin6_port);
1346 rb_str_catf(ret, "[%s]:%d", hbuf, port);
1347 }
1348 if ((socklen_t)sizeof(struct sockaddr_in6) < socklen)
1349 rb_str_catf(ret, "(sockaddr %d bytes too long)", (int)(socklen - sizeof(struct sockaddr_in6)));
1350 }
1351 break;
1352 }
1353#endif
1354
1355#ifdef HAVE_SYS_UN_H
1356 case AF_UNIX:
1357 {
1358 struct sockaddr_un *addr = &sockaddr->un;
1359 char *p, *s, *e;
1360 long len = unixsocket_len(addr, socklen);
1361 s = addr->sun_path;
1362 if (len < 0)
1363 rb_str_cat2(ret, "too-short-AF_UNIX-sockaddr");
1364 else if (len == 0)
1365 rb_str_cat2(ret, "empty-path-AF_UNIX-sockaddr");
1366 else {
1367 int printable_only = 1;
1368 e = s + len;
1369 p = s;
1370 while (p < e) {
1371 printable_only = printable_only && ISPRINT(*p) && !ISSPACE(*p);
1372 p++;
1373 }
1374 if (printable_only) { /* only printable, no space */
1375 if (s[0] != '/') /* relative path */
1376 rb_str_cat2(ret, "UNIX ");
1377 rb_str_cat(ret, s, p - s);
1378 }
1379 else {
1380 rb_str_cat2(ret, "UNIX");
1381 while (s < e)
1382 rb_str_catf(ret, ":%02x", (unsigned char)*s++);
1383 }
1384 }
1385 break;
1386 }
1387#endif
1388
1389#if defined(AF_PACKET) && defined(__linux__)
1390 /* GNU/Linux */
1391 case AF_PACKET:
1392 {
1393 struct sockaddr_ll *addr;
1394 const char *sep = "[";
1395#define CATSEP do { rb_str_cat2(ret, sep); sep = " "; } while (0);
1396
1397 addr = (struct sockaddr_ll *)sockaddr;
1398
1399 rb_str_cat2(ret, "PACKET");
1400
1401 if (offsetof(struct sockaddr_ll, sll_protocol) + sizeof(addr->sll_protocol) <= (size_t)socklen) {
1402 CATSEP;
1403 rb_str_catf(ret, "protocol=%d", ntohs(addr->sll_protocol));
1404 }
1405 if (offsetof(struct sockaddr_ll, sll_ifindex) + sizeof(addr->sll_ifindex) <= (size_t)socklen) {
1406 char buf[IFNAMSIZ];
1407 CATSEP;
1408 if (if_indextoname(addr->sll_ifindex, buf) == NULL)
1409 rb_str_catf(ret, "ifindex=%d", addr->sll_ifindex);
1410 else
1411 rb_str_catf(ret, "%s", buf);
1412 }
1413 if (offsetof(struct sockaddr_ll, sll_hatype) + sizeof(addr->sll_hatype) <= (size_t)socklen) {
1414 CATSEP;
1415 rb_str_catf(ret, "hatype=%d", addr->sll_hatype);
1416 }
1417 if (offsetof(struct sockaddr_ll, sll_pkttype) + sizeof(addr->sll_pkttype) <= (size_t)socklen) {
1418 CATSEP;
1419 if (addr->sll_pkttype == PACKET_HOST)
1420 rb_str_cat2(ret, "HOST");
1421 else if (addr->sll_pkttype == PACKET_BROADCAST)
1422 rb_str_cat2(ret, "BROADCAST");
1423 else if (addr->sll_pkttype == PACKET_MULTICAST)
1424 rb_str_cat2(ret, "MULTICAST");
1425 else if (addr->sll_pkttype == PACKET_OTHERHOST)
1426 rb_str_cat2(ret, "OTHERHOST");
1427 else if (addr->sll_pkttype == PACKET_OUTGOING)
1428 rb_str_cat2(ret, "OUTGOING");
1429 else
1430 rb_str_catf(ret, "pkttype=%d", addr->sll_pkttype);
1431 }
1432 if (socklen != (socklen_t)(offsetof(struct sockaddr_ll, sll_addr) + addr->sll_halen)) {
1433 CATSEP;
1434 if (offsetof(struct sockaddr_ll, sll_halen) + sizeof(addr->sll_halen) <= (size_t)socklen) {
1435 rb_str_catf(ret, "halen=%d", addr->sll_halen);
1436 }
1437 }
1438 if (offsetof(struct sockaddr_ll, sll_addr) < (size_t)socklen) {
1439 socklen_t len, i;
1440 CATSEP;
1441 rb_str_cat2(ret, "hwaddr");
1442 len = addr->sll_halen;
1443 if ((size_t)socklen < offsetof(struct sockaddr_ll, sll_addr) + len)
1444 len = socklen - offsetof(struct sockaddr_ll, sll_addr);
1445 for (i = 0; i < len; i++) {
1446 rb_str_cat2(ret, i == 0 ? "=" : ":");
1447 rb_str_catf(ret, "%02x", addr->sll_addr[i]);
1448 }
1449 }
1450
1451 if (socklen < (socklen_t)(offsetof(struct sockaddr_ll, sll_halen) + sizeof(addr->sll_halen)) ||
1452 (socklen_t)(offsetof(struct sockaddr_ll, sll_addr) + addr->sll_halen) != socklen) {
1453 CATSEP;
1454 rb_str_catf(ret, "(%d bytes for %d bytes sockaddr_ll)",
1455 (int)socklen, (int)sizeof(struct sockaddr_ll));
1456 }
1457
1458 rb_str_cat2(ret, "]");
1459#undef CATSEP
1460
1461 break;
1462 }
1463#endif
1464
1465#if defined(AF_LINK) && defined(HAVE_TYPE_STRUCT_SOCKADDR_DL)
1466 /* AF_LINK is defined in 4.4BSD derivations since Net2.
1467 link_ntoa is also defined at Net2.
1468 However Debian GNU/kFreeBSD defines AF_LINK but
1469 don't have link_ntoa. */
1470 case AF_LINK:
1471 {
1472 /*
1473 * Simple implementation using link_ntoa():
1474 * This doesn't work on Debian GNU/kFreeBSD 6.0.7 (squeeze).
1475 * Also, the format is bit different.
1476 *
1477 * rb_str_catf(ret, "LINK %s", link_ntoa(&sockaddr->dl));
1478 * break;
1479 */
1480 struct sockaddr_dl *addr = &sockaddr->dl;
1481 char *np = NULL, *ap = NULL, *endp;
1482 int nlen = 0, alen = 0;
1483 int i, off;
1484 const char *sep = "[";
1485#define CATSEP do { rb_str_cat2(ret, sep); sep = " "; } while (0);
1486
1487 rb_str_cat2(ret, "LINK");
1488
1489 endp = ((char *)addr) + socklen;
1490
1491 if (offsetof(struct sockaddr_dl, sdl_data) < socklen) {
1492 np = addr->sdl_data;
1493 nlen = addr->sdl_nlen;
1494 if (endp - np < nlen)
1495 nlen = (int)(endp - np);
1496 }
1497 off = addr->sdl_nlen;
1498
1499 if (offsetof(struct sockaddr_dl, sdl_data) + off < socklen) {
1500 ap = addr->sdl_data + off;
1501 alen = addr->sdl_alen;
1502 if (endp - ap < alen)
1503 alen = (int)(endp - ap);
1504 }
1505
1506 CATSEP;
1507 if (np)
1508 rb_str_catf(ret, "%.*s", nlen, np);
1509 else
1510 rb_str_cat2(ret, "?");
1511
1512 if (ap && 0 < alen) {
1513 CATSEP;
1514 for (i = 0; i < alen; i++)
1515 rb_str_catf(ret, "%s%02x", i == 0 ? "" : ":", (unsigned char)ap[i]);
1516 }
1517
1518 if (socklen < (socklen_t)(offsetof(struct sockaddr_dl, sdl_nlen) + sizeof(addr->sdl_nlen)) ||
1519 socklen < (socklen_t)(offsetof(struct sockaddr_dl, sdl_alen) + sizeof(addr->sdl_alen)) ||
1520 socklen < (socklen_t)(offsetof(struct sockaddr_dl, sdl_slen) + sizeof(addr->sdl_slen)) ||
1521 /* longer length is possible behavior because struct sockaddr_dl has "minimum work area, can be larger" as the last field.
1522 * cf. Net2:/usr/src/sys/net/if_dl.h. */
1523 socklen < (socklen_t)(offsetof(struct sockaddr_dl, sdl_data) + addr->sdl_nlen + addr->sdl_alen + addr->sdl_slen)) {
1524 CATSEP;
1525 rb_str_catf(ret, "(%d bytes for %d bytes sockaddr_dl)",
1526 (int)socklen, (int)sizeof(struct sockaddr_dl));
1527 }
1528
1529 rb_str_cat2(ret, "]");
1530#undef CATSEP
1531 break;
1532 }
1533#endif
1534
1535 default:
1536 {
1537 ID id = rsock_intern_family(sockaddr->addr.sa_family);
1538 if (id == 0)
1539 rb_str_catf(ret, "unknown address family %d", sockaddr->addr.sa_family);
1540 else
1541 rb_str_catf(ret, "%s address format unknown", rb_id2name(id));
1542 break;
1543 }
1544 }
1545 }
1546
1547 return ret;
1548}
1549
1550/*
1551 * call-seq:
1552 * addrinfo.inspect => string
1553 *
1554 * returns a string which shows addrinfo in human-readable form.
1555 *
1556 * Addrinfo.tcp("localhost", 80).inspect #=> "#<Addrinfo: 127.0.0.1:80 TCP (localhost)>"
1557 * Addrinfo.unix("/tmp/sock").inspect #=> "#<Addrinfo: /tmp/sock SOCK_STREAM>"
1558 *
1559 */
1560static VALUE
1561addrinfo_inspect(VALUE self)
1562{
1563 rb_addrinfo_t *rai = get_addrinfo(self);
1564 int internet_p;
1565 VALUE ret;
1566
1567 ret = rb_sprintf("#<%s: ", rb_obj_classname(self));
1568
1569 inspect_sockaddr(self, ret);
1570
1571 if (rai->pfamily && ai_get_afamily(rai) != rai->pfamily) {
1573 if (id)
1574 rb_str_catf(ret, " %s", rb_id2name(id));
1575 else
1576 rb_str_catf(ret, " PF_\?\?\?(%d)", rai->pfamily);
1577 }
1578
1579 internet_p = rai->pfamily == PF_INET;
1580#ifdef INET6
1581 internet_p = internet_p || rai->pfamily == PF_INET6;
1582#endif
1583 if (internet_p && rai->socktype == SOCK_STREAM &&
1584 (rai->protocol == 0 || rai->protocol == IPPROTO_TCP)) {
1585 rb_str_cat2(ret, " TCP");
1586 }
1587 else if (internet_p && rai->socktype == SOCK_DGRAM &&
1588 (rai->protocol == 0 || rai->protocol == IPPROTO_UDP)) {
1589 rb_str_cat2(ret, " UDP");
1590 }
1591 else {
1592 if (rai->socktype) {
1594 if (id)
1595 rb_str_catf(ret, " %s", rb_id2name(id));
1596 else
1597 rb_str_catf(ret, " SOCK_\?\?\?(%d)", rai->socktype);
1598 }
1599
1600 if (rai->protocol) {
1601 if (internet_p) {
1602 ID id = rsock_intern_ipproto(rai->protocol);
1603 if (id)
1604 rb_str_catf(ret, " %s", rb_id2name(id));
1605 else
1606 goto unknown_protocol;
1607 }
1608 else {
1609 unknown_protocol:
1610 rb_str_catf(ret, " UNKNOWN_PROTOCOL(%d)", rai->protocol);
1611 }
1612 }
1613 }
1614
1615 if (!NIL_P(rai->canonname)) {
1616 VALUE name = rai->canonname;
1617 rb_str_catf(ret, " %s", StringValueCStr(name));
1618 }
1619
1620 if (!NIL_P(rai->inspectname)) {
1621 VALUE name = rai->inspectname;
1622 rb_str_catf(ret, " (%s)", StringValueCStr(name));
1623 }
1624
1625 rb_str_buf_cat2(ret, ">");
1626 return ret;
1627}
1628
1629/*
1630 * call-seq:
1631 * addrinfo.inspect_sockaddr => string
1632 *
1633 * returns a string which shows the sockaddr in _addrinfo_ with human-readable form.
1634 *
1635 * Addrinfo.tcp("localhost", 80).inspect_sockaddr #=> "127.0.0.1:80"
1636 * Addrinfo.tcp("ip6-localhost", 80).inspect_sockaddr #=> "[::1]:80"
1637 * Addrinfo.unix("/tmp/sock").inspect_sockaddr #=> "/tmp/sock"
1638 *
1639 */
1640VALUE
1642{
1643 return inspect_sockaddr(self, rb_str_new("", 0));
1644}
1645
1646/* :nodoc: */
1647static VALUE
1648addrinfo_mdump(VALUE self)
1649{
1650 rb_addrinfo_t *rai = get_addrinfo(self);
1651 VALUE sockaddr, afamily, pfamily, socktype, protocol, canonname, inspectname;
1652 int afamily_int = ai_get_afamily(rai);
1653 ID id;
1654
1656 if (id == 0)
1657 rb_raise(rb_eSocket, "unknown protocol family: %d", rai->pfamily);
1658 pfamily = rb_id2str(id);
1659
1660 if (rai->socktype == 0)
1661 socktype = INT2FIX(0);
1662 else {
1664 if (id == 0)
1665 rb_raise(rb_eSocket, "unknown socktype: %d", rai->socktype);
1666 socktype = rb_id2str(id);
1667 }
1668
1669 if (rai->protocol == 0)
1670 protocol = INT2FIX(0);
1671 else if (IS_IP_FAMILY(afamily_int)) {
1672 id = rsock_intern_ipproto(rai->protocol);
1673 if (id == 0)
1674 rb_raise(rb_eSocket, "unknown IP protocol: %d", rai->protocol);
1675 protocol = rb_id2str(id);
1676 }
1677 else {
1678 rb_raise(rb_eSocket, "unknown protocol: %d", rai->protocol);
1679 }
1680
1681 canonname = rai->canonname;
1682
1683 inspectname = rai->inspectname;
1684
1685 id = rsock_intern_family(afamily_int);
1686 if (id == 0)
1687 rb_raise(rb_eSocket, "unknown address family: %d", afamily_int);
1688 afamily = rb_id2str(id);
1689
1690 switch(afamily_int) {
1691#ifdef HAVE_SYS_UN_H
1692 case AF_UNIX:
1693 {
1694 sockaddr = rb_str_new(rai->addr.un.sun_path, rai_unixsocket_len(rai));
1695 break;
1696 }
1697#endif
1698
1699 default:
1700 {
1701 char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
1702 int error;
1703 error = getnameinfo(&rai->addr.addr, rai->sockaddr_len,
1704 hbuf, (socklen_t)sizeof(hbuf), pbuf, (socklen_t)sizeof(pbuf),
1706 if (error) {
1707 rsock_raise_socket_error("getnameinfo", error);
1708 }
1709 sockaddr = rb_assoc_new(rb_str_new_cstr(hbuf), rb_str_new_cstr(pbuf));
1710 break;
1711 }
1712 }
1713
1714 return rb_ary_new3(7, afamily, sockaddr, pfamily, socktype, protocol, canonname, inspectname);
1715}
1716
1717/* :nodoc: */
1718static VALUE
1719addrinfo_mload(VALUE self, VALUE ary)
1720{
1721 VALUE v;
1722 VALUE canonname, inspectname;
1723 int afamily, pfamily, socktype, protocol;
1724 union_sockaddr ss;
1725 socklen_t len;
1726 rb_addrinfo_t *rai;
1727
1728 if (check_addrinfo(self))
1729 rb_raise(rb_eTypeError, "already initialized socket address");
1730
1731 ary = rb_convert_type(ary, T_ARRAY, "Array", "to_ary");
1732
1733 v = rb_ary_entry(ary, 0);
1734 StringValue(v);
1735 if (rsock_family_to_int(RSTRING_PTR(v), RSTRING_LEN(v), &afamily) == -1)
1736 rb_raise(rb_eTypeError, "unexpected address family");
1737
1738 v = rb_ary_entry(ary, 2);
1739 StringValue(v);
1740 if (rsock_family_to_int(RSTRING_PTR(v), RSTRING_LEN(v), &pfamily) == -1)
1741 rb_raise(rb_eTypeError, "unexpected protocol family");
1742
1743 v = rb_ary_entry(ary, 3);
1744 if (v == INT2FIX(0))
1745 socktype = 0;
1746 else {
1747 StringValue(v);
1748 if (rsock_socktype_to_int(RSTRING_PTR(v), RSTRING_LEN(v), &socktype) == -1)
1749 rb_raise(rb_eTypeError, "unexpected socktype");
1750 }
1751
1752 v = rb_ary_entry(ary, 4);
1753 if (v == INT2FIX(0))
1754 protocol = 0;
1755 else {
1756 StringValue(v);
1757 if (IS_IP_FAMILY(afamily)) {
1758 if (rsock_ipproto_to_int(RSTRING_PTR(v), RSTRING_LEN(v), &protocol) == -1)
1759 rb_raise(rb_eTypeError, "unexpected protocol");
1760 }
1761 else {
1762 rb_raise(rb_eTypeError, "unexpected protocol");
1763 }
1764 }
1765
1766 v = rb_ary_entry(ary, 5);
1767 if (NIL_P(v))
1768 canonname = Qnil;
1769 else {
1770 StringValue(v);
1771 canonname = v;
1772 }
1773
1774 v = rb_ary_entry(ary, 6);
1775 if (NIL_P(v))
1776 inspectname = Qnil;
1777 else {
1778 StringValue(v);
1779 inspectname = v;
1780 }
1781
1782 v = rb_ary_entry(ary, 1);
1783 switch(afamily) {
1784#ifdef HAVE_SYS_UN_H
1785 case AF_UNIX:
1786 {
1787 struct sockaddr_un uaddr;
1788 INIT_SOCKADDR_UN(&uaddr, sizeof(struct sockaddr_un));
1789
1790 StringValue(v);
1791 if (sizeof(uaddr.sun_path) < (size_t)RSTRING_LEN(v))
1793 "too long AF_UNIX path (%"PRIuSIZE" bytes given but %"PRIuSIZE" bytes max)",
1794 (size_t)RSTRING_LEN(v), sizeof(uaddr.sun_path));
1795 memcpy(uaddr.sun_path, RSTRING_PTR(v), RSTRING_LEN(v));
1796 len = (socklen_t)sizeof(uaddr);
1797 memcpy(&ss, &uaddr, len);
1798 break;
1799 }
1800#endif
1801
1802 default:
1803 {
1804 VALUE pair = rb_convert_type(v, T_ARRAY, "Array", "to_ary");
1805 struct rb_addrinfo *res;
1806 int flags = AI_NUMERICHOST;
1807#ifdef AI_NUMERICSERV
1808 flags |= AI_NUMERICSERV;
1809#endif
1810 res = call_getaddrinfo(rb_ary_entry(pair, 0), rb_ary_entry(pair, 1),
1811 INT2NUM(pfamily), INT2NUM(socktype), INT2NUM(protocol),
1812 INT2NUM(flags), 1, Qnil);
1813
1814 len = res->ai->ai_addrlen;
1815 memcpy(&ss, res->ai->ai_addr, res->ai->ai_addrlen);
1816 rb_freeaddrinfo(res);
1817 break;
1818 }
1819 }
1820
1821 DATA_PTR(self) = rai = alloc_addrinfo();
1822 init_addrinfo(rai, &ss.addr, len,
1823 pfamily, socktype, protocol,
1824 canonname, inspectname);
1825 return self;
1826}
1827
1828/*
1829 * call-seq:
1830 * addrinfo.afamily => integer
1831 *
1832 * returns the address family as an integer.
1833 *
1834 * Addrinfo.tcp("localhost", 80).afamily == Socket::AF_INET #=> true
1835 *
1836 */
1837static VALUE
1838addrinfo_afamily(VALUE self)
1839{
1840 rb_addrinfo_t *rai = get_addrinfo(self);
1841 return INT2NUM(ai_get_afamily(rai));
1842}
1843
1844/*
1845 * call-seq:
1846 * addrinfo.pfamily => integer
1847 *
1848 * returns the protocol family as an integer.
1849 *
1850 * Addrinfo.tcp("localhost", 80).pfamily == Socket::PF_INET #=> true
1851 *
1852 */
1853static VALUE
1854addrinfo_pfamily(VALUE self)
1855{
1856 rb_addrinfo_t *rai = get_addrinfo(self);
1857 return INT2NUM(rai->pfamily);
1858}
1859
1860/*
1861 * call-seq:
1862 * addrinfo.socktype => integer
1863 *
1864 * returns the socket type as an integer.
1865 *
1866 * Addrinfo.tcp("localhost", 80).socktype == Socket::SOCK_STREAM #=> true
1867 *
1868 */
1869static VALUE
1870addrinfo_socktype(VALUE self)
1871{
1872 rb_addrinfo_t *rai = get_addrinfo(self);
1873 return INT2NUM(rai->socktype);
1874}
1875
1876/*
1877 * call-seq:
1878 * addrinfo.protocol => integer
1879 *
1880 * returns the socket type as an integer.
1881 *
1882 * Addrinfo.tcp("localhost", 80).protocol == Socket::IPPROTO_TCP #=> true
1883 *
1884 */
1885static VALUE
1886addrinfo_protocol(VALUE self)
1887{
1888 rb_addrinfo_t *rai = get_addrinfo(self);
1889 return INT2NUM(rai->protocol);
1890}
1891
1892/*
1893 * call-seq:
1894 * addrinfo.to_sockaddr => string
1895 * addrinfo.to_s => string
1896 *
1897 * returns the socket address as packed struct sockaddr string.
1898 *
1899 * Addrinfo.tcp("localhost", 80).to_sockaddr
1900 * #=> "\x02\x00\x00P\x7F\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00"
1901 *
1902 */
1903static VALUE
1904addrinfo_to_sockaddr(VALUE self)
1905{
1906 rb_addrinfo_t *rai = get_addrinfo(self);
1907 VALUE ret;
1908 ret = rb_str_new((char*)&rai->addr, rai->sockaddr_len);
1909 return ret;
1910}
1911
1912/*
1913 * call-seq:
1914 * addrinfo.canonname => string or nil
1915 *
1916 * returns the canonical name as an string.
1917 *
1918 * nil is returned if no canonical name.
1919 *
1920 * The canonical name is set by Addrinfo.getaddrinfo when AI_CANONNAME is specified.
1921 *
1922 * list = Addrinfo.getaddrinfo("www.ruby-lang.org", 80, :INET, :STREAM, nil, Socket::AI_CANONNAME)
1923 * p list[0] #=> #<Addrinfo: 221.186.184.68:80 TCP carbon.ruby-lang.org (www.ruby-lang.org)>
1924 * p list[0].canonname #=> "carbon.ruby-lang.org"
1925 *
1926 */
1927static VALUE
1928addrinfo_canonname(VALUE self)
1929{
1930 rb_addrinfo_t *rai = get_addrinfo(self);
1931 return rai->canonname;
1932}
1933
1934/*
1935 * call-seq:
1936 * addrinfo.ip? => true or false
1937 *
1938 * returns true if addrinfo is internet (IPv4/IPv6) address.
1939 * returns false otherwise.
1940 *
1941 * Addrinfo.tcp("127.0.0.1", 80).ip? #=> true
1942 * Addrinfo.tcp("::1", 80).ip? #=> true
1943 * Addrinfo.unix("/tmp/sock").ip? #=> false
1944 *
1945 */
1946static VALUE
1947addrinfo_ip_p(VALUE self)
1948{
1949 rb_addrinfo_t *rai = get_addrinfo(self);
1950 int family = ai_get_afamily(rai);
1951 return IS_IP_FAMILY(family) ? Qtrue : Qfalse;
1952}
1953
1954/*
1955 * call-seq:
1956 * addrinfo.ipv4? => true or false
1957 *
1958 * returns true if addrinfo is IPv4 address.
1959 * returns false otherwise.
1960 *
1961 * Addrinfo.tcp("127.0.0.1", 80).ipv4? #=> true
1962 * Addrinfo.tcp("::1", 80).ipv4? #=> false
1963 * Addrinfo.unix("/tmp/sock").ipv4? #=> false
1964 *
1965 */
1966static VALUE
1967addrinfo_ipv4_p(VALUE self)
1968{
1969 rb_addrinfo_t *rai = get_addrinfo(self);
1970 return ai_get_afamily(rai) == AF_INET ? Qtrue : Qfalse;
1971}
1972
1973/*
1974 * call-seq:
1975 * addrinfo.ipv6? => true or false
1976 *
1977 * returns true if addrinfo is IPv6 address.
1978 * returns false otherwise.
1979 *
1980 * Addrinfo.tcp("127.0.0.1", 80).ipv6? #=> false
1981 * Addrinfo.tcp("::1", 80).ipv6? #=> true
1982 * Addrinfo.unix("/tmp/sock").ipv6? #=> false
1983 *
1984 */
1985static VALUE
1986addrinfo_ipv6_p(VALUE self)
1987{
1988#ifdef AF_INET6
1989 rb_addrinfo_t *rai = get_addrinfo(self);
1990 return ai_get_afamily(rai) == AF_INET6 ? Qtrue : Qfalse;
1991#else
1992 return Qfalse;
1993#endif
1994}
1995
1996/*
1997 * call-seq:
1998 * addrinfo.unix? => true or false
1999 *
2000 * returns true if addrinfo is UNIX address.
2001 * returns false otherwise.
2002 *
2003 * Addrinfo.tcp("127.0.0.1", 80).unix? #=> false
2004 * Addrinfo.tcp("::1", 80).unix? #=> false
2005 * Addrinfo.unix("/tmp/sock").unix? #=> true
2006 *
2007 */
2008static VALUE
2009addrinfo_unix_p(VALUE self)
2010{
2011 rb_addrinfo_t *rai = get_addrinfo(self);
2012#ifdef AF_UNIX
2013 return ai_get_afamily(rai) == AF_UNIX ? Qtrue : Qfalse;
2014#else
2015 return Qfalse;
2016#endif
2017}
2018
2019/*
2020 * call-seq:
2021 * addrinfo.getnameinfo => [nodename, service]
2022 * addrinfo.getnameinfo(flags) => [nodename, service]
2023 *
2024 * returns nodename and service as a pair of strings.
2025 * This converts struct sockaddr in addrinfo to textual representation.
2026 *
2027 * flags should be bitwise OR of Socket::NI_??? constants.
2028 *
2029 * Addrinfo.tcp("127.0.0.1", 80).getnameinfo #=> ["localhost", "www"]
2030 *
2031 * Addrinfo.tcp("127.0.0.1", 80).getnameinfo(Socket::NI_NUMERICSERV)
2032 * #=> ["localhost", "80"]
2033 */
2034static VALUE
2035addrinfo_getnameinfo(int argc, VALUE *argv, VALUE self)
2036{
2037 rb_addrinfo_t *rai = get_addrinfo(self);
2038 VALUE vflags;
2039 char hbuf[1024], pbuf[1024];
2040 int flags, error;
2041
2042 rb_scan_args(argc, argv, "01", &vflags);
2043
2044 flags = NIL_P(vflags) ? 0 : NUM2INT(vflags);
2045
2046 if (rai->socktype == SOCK_DGRAM)
2047 flags |= NI_DGRAM;
2048
2049 error = getnameinfo(&rai->addr.addr, rai->sockaddr_len,
2050 hbuf, (socklen_t)sizeof(hbuf), pbuf, (socklen_t)sizeof(pbuf),
2051 flags);
2052 if (error) {
2053 rsock_raise_socket_error("getnameinfo", error);
2054 }
2055
2056 return rb_assoc_new(rb_str_new2(hbuf), rb_str_new2(pbuf));
2057}
2058
2059/*
2060 * call-seq:
2061 * addrinfo.ip_unpack => [addr, port]
2062 *
2063 * Returns the IP address and port number as 2-element array.
2064 *
2065 * Addrinfo.tcp("127.0.0.1", 80).ip_unpack #=> ["127.0.0.1", 80]
2066 * Addrinfo.tcp("::1", 80).ip_unpack #=> ["::1", 80]
2067 */
2068static VALUE
2069addrinfo_ip_unpack(VALUE self)
2070{
2071 rb_addrinfo_t *rai = get_addrinfo(self);
2072 int family = ai_get_afamily(rai);
2073 VALUE vflags;
2074 VALUE ret, portstr;
2075
2076 if (!IS_IP_FAMILY(family))
2077 rb_raise(rb_eSocket, "need IPv4 or IPv6 address");
2078
2080 ret = addrinfo_getnameinfo(1, &vflags, self);
2081 portstr = rb_ary_entry(ret, 1);
2082 rb_ary_store(ret, 1, INT2NUM(atoi(StringValueCStr(portstr))));
2083 return ret;
2084}
2085
2086/*
2087 * call-seq:
2088 * addrinfo.ip_address => string
2089 *
2090 * Returns the IP address as a string.
2091 *
2092 * Addrinfo.tcp("127.0.0.1", 80).ip_address #=> "127.0.0.1"
2093 * Addrinfo.tcp("::1", 80).ip_address #=> "::1"
2094 */
2095static VALUE
2096addrinfo_ip_address(VALUE self)
2097{
2098 rb_addrinfo_t *rai = get_addrinfo(self);
2099 int family = ai_get_afamily(rai);
2100 VALUE vflags;
2101 VALUE ret;
2102
2103 if (!IS_IP_FAMILY(family))
2104 rb_raise(rb_eSocket, "need IPv4 or IPv6 address");
2105
2107 ret = addrinfo_getnameinfo(1, &vflags, self);
2108 return rb_ary_entry(ret, 0);
2109}
2110
2111/*
2112 * call-seq:
2113 * addrinfo.ip_port => port
2114 *
2115 * Returns the port number as an integer.
2116 *
2117 * Addrinfo.tcp("127.0.0.1", 80).ip_port #=> 80
2118 * Addrinfo.tcp("::1", 80).ip_port #=> 80
2119 */
2120static VALUE
2121addrinfo_ip_port(VALUE self)
2122{
2123 rb_addrinfo_t *rai = get_addrinfo(self);
2124 int family = ai_get_afamily(rai);
2125 int port;
2126
2127 if (!IS_IP_FAMILY(family)) {
2128 bad_family:
2129#ifdef AF_INET6
2130 rb_raise(rb_eSocket, "need IPv4 or IPv6 address");
2131#else
2132 rb_raise(rb_eSocket, "need IPv4 address");
2133#endif
2134 }
2135
2136 switch (family) {
2137 case AF_INET:
2138 if (rai->sockaddr_len != sizeof(struct sockaddr_in))
2139 rb_raise(rb_eSocket, "unexpected sockaddr size for IPv4");
2140 port = ntohs(rai->addr.in.sin_port);
2141 break;
2142
2143#ifdef AF_INET6
2144 case AF_INET6:
2145 if (rai->sockaddr_len != sizeof(struct sockaddr_in6))
2146 rb_raise(rb_eSocket, "unexpected sockaddr size for IPv6");
2147 port = ntohs(rai->addr.in6.sin6_port);
2148 break;
2149#endif
2150
2151 default:
2152 goto bad_family;
2153 }
2154
2155 return INT2NUM(port);
2156}
2157
2158static int
2159extract_in_addr(VALUE self, uint32_t *addrp)
2160{
2161 rb_addrinfo_t *rai = get_addrinfo(self);
2162 int family = ai_get_afamily(rai);
2163 if (family != AF_INET) return 0;
2164 *addrp = ntohl(rai->addr.in.sin_addr.s_addr);
2165 return 1;
2166}
2167
2168/*
2169 * Returns true for IPv4 private address (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16).
2170 * It returns false otherwise.
2171 */
2172static VALUE
2173addrinfo_ipv4_private_p(VALUE self)
2174{
2175 uint32_t a;
2176 if (!extract_in_addr(self, &a)) return Qfalse;
2177 if ((a & 0xff000000) == 0x0a000000 || /* 10.0.0.0/8 */
2178 (a & 0xfff00000) == 0xac100000 || /* 172.16.0.0/12 */
2179 (a & 0xffff0000) == 0xc0a80000) /* 192.168.0.0/16 */
2180 return Qtrue;
2181 return Qfalse;
2182}
2183
2184/*
2185 * Returns true for IPv4 loopback address (127.0.0.0/8).
2186 * It returns false otherwise.
2187 */
2188static VALUE
2189addrinfo_ipv4_loopback_p(VALUE self)
2190{
2191 uint32_t a;
2192 if (!extract_in_addr(self, &a)) return Qfalse;
2193 if ((a & 0xff000000) == 0x7f000000) /* 127.0.0.0/8 */
2194 return Qtrue;
2195 return Qfalse;
2196}
2197
2198/*
2199 * Returns true for IPv4 multicast address (224.0.0.0/4).
2200 * It returns false otherwise.
2201 */
2202static VALUE
2203addrinfo_ipv4_multicast_p(VALUE self)
2204{
2205 uint32_t a;
2206 if (!extract_in_addr(self, &a)) return Qfalse;
2207 if ((a & 0xf0000000) == 0xe0000000) /* 224.0.0.0/4 */
2208 return Qtrue;
2209 return Qfalse;
2210}
2211
2212#ifdef INET6
2213
2214static struct in6_addr *
2215extract_in6_addr(VALUE self)
2216{
2217 rb_addrinfo_t *rai = get_addrinfo(self);
2218 int family = ai_get_afamily(rai);
2219 if (family != AF_INET6) return NULL;
2220 return &rai->addr.in6.sin6_addr;
2221}
2222
2223/*
2224 * Returns true for IPv6 unspecified address (::).
2225 * It returns false otherwise.
2226 */
2227static VALUE
2228addrinfo_ipv6_unspecified_p(VALUE self)
2229{
2230 struct in6_addr *addr = extract_in6_addr(self);
2231 if (addr && IN6_IS_ADDR_UNSPECIFIED(addr)) return Qtrue;
2232 return Qfalse;
2233}
2234
2235/*
2236 * Returns true for IPv6 loopback address (::1).
2237 * It returns false otherwise.
2238 */
2239static VALUE
2240addrinfo_ipv6_loopback_p(VALUE self)
2241{
2242 struct in6_addr *addr = extract_in6_addr(self);
2243 if (addr && IN6_IS_ADDR_LOOPBACK(addr)) return Qtrue;
2244 return Qfalse;
2245}
2246
2247/*
2248 * Returns true for IPv6 multicast address (ff00::/8).
2249 * It returns false otherwise.
2250 */
2251static VALUE
2252addrinfo_ipv6_multicast_p(VALUE self)
2253{
2254 struct in6_addr *addr = extract_in6_addr(self);
2255 if (addr && IN6_IS_ADDR_MULTICAST(addr)) return Qtrue;
2256 return Qfalse;
2257}
2258
2259/*
2260 * Returns true for IPv6 link local address (ff80::/10).
2261 * It returns false otherwise.
2262 */
2263static VALUE
2264addrinfo_ipv6_linklocal_p(VALUE self)
2265{
2266 struct in6_addr *addr = extract_in6_addr(self);
2267 if (addr && IN6_IS_ADDR_LINKLOCAL(addr)) return Qtrue;
2268 return Qfalse;
2269}
2270
2271/*
2272 * Returns true for IPv6 site local address (ffc0::/10).
2273 * It returns false otherwise.
2274 */
2275static VALUE
2276addrinfo_ipv6_sitelocal_p(VALUE self)
2277{
2278 struct in6_addr *addr = extract_in6_addr(self);
2279 if (addr && IN6_IS_ADDR_SITELOCAL(addr)) return Qtrue;
2280 return Qfalse;
2281}
2282
2283/*
2284 * Returns true for IPv6 unique local address (fc00::/7, RFC4193).
2285 * It returns false otherwise.
2286 */
2287static VALUE
2288addrinfo_ipv6_unique_local_p(VALUE self)
2289{
2290 struct in6_addr *addr = extract_in6_addr(self);
2291 if (addr && IN6_IS_ADDR_UNIQUE_LOCAL(addr)) return Qtrue;
2292 return Qfalse;
2293}
2294
2295/*
2296 * Returns true for IPv4-mapped IPv6 address (::ffff:0:0/80).
2297 * It returns false otherwise.
2298 */
2299static VALUE
2300addrinfo_ipv6_v4mapped_p(VALUE self)
2301{
2302 struct in6_addr *addr = extract_in6_addr(self);
2303 if (addr && IN6_IS_ADDR_V4MAPPED(addr)) return Qtrue;
2304 return Qfalse;
2305}
2306
2307/*
2308 * Returns true for IPv4-compatible IPv6 address (::/80).
2309 * It returns false otherwise.
2310 */
2311static VALUE
2312addrinfo_ipv6_v4compat_p(VALUE self)
2313{
2314 struct in6_addr *addr = extract_in6_addr(self);
2315 if (addr && IN6_IS_ADDR_V4COMPAT(addr)) return Qtrue;
2316 return Qfalse;
2317}
2318
2319/*
2320 * Returns true for IPv6 multicast node-local scope address.
2321 * It returns false otherwise.
2322 */
2323static VALUE
2324addrinfo_ipv6_mc_nodelocal_p(VALUE self)
2325{
2326 struct in6_addr *addr = extract_in6_addr(self);
2327 if (addr && IN6_IS_ADDR_MC_NODELOCAL(addr)) return Qtrue;
2328 return Qfalse;
2329}
2330
2331/*
2332 * Returns true for IPv6 multicast link-local scope address.
2333 * It returns false otherwise.
2334 */
2335static VALUE
2336addrinfo_ipv6_mc_linklocal_p(VALUE self)
2337{
2338 struct in6_addr *addr = extract_in6_addr(self);
2339 if (addr && IN6_IS_ADDR_MC_LINKLOCAL(addr)) return Qtrue;
2340 return Qfalse;
2341}
2342
2343/*
2344 * Returns true for IPv6 multicast site-local scope address.
2345 * It returns false otherwise.
2346 */
2347static VALUE
2348addrinfo_ipv6_mc_sitelocal_p(VALUE self)
2349{
2350 struct in6_addr *addr = extract_in6_addr(self);
2351 if (addr && IN6_IS_ADDR_MC_SITELOCAL(addr)) return Qtrue;
2352 return Qfalse;
2353}
2354
2355/*
2356 * Returns true for IPv6 multicast organization-local scope address.
2357 * It returns false otherwise.
2358 */
2359static VALUE
2360addrinfo_ipv6_mc_orglocal_p(VALUE self)
2361{
2362 struct in6_addr *addr = extract_in6_addr(self);
2363 if (addr && IN6_IS_ADDR_MC_ORGLOCAL(addr)) return Qtrue;
2364 return Qfalse;
2365}
2366
2367/*
2368 * Returns true for IPv6 multicast global scope address.
2369 * It returns false otherwise.
2370 */
2371static VALUE
2372addrinfo_ipv6_mc_global_p(VALUE self)
2373{
2374 struct in6_addr *addr = extract_in6_addr(self);
2375 if (addr && IN6_IS_ADDR_MC_GLOBAL(addr)) return Qtrue;
2376 return Qfalse;
2377}
2378
2379/*
2380 * Returns IPv4 address of IPv4 mapped/compatible IPv6 address.
2381 * It returns nil if +self+ is not IPv4 mapped/compatible IPv6 address.
2382 *
2383 * Addrinfo.ip("::192.0.2.3").ipv6_to_ipv4 #=> #<Addrinfo: 192.0.2.3>
2384 * Addrinfo.ip("::ffff:192.0.2.3").ipv6_to_ipv4 #=> #<Addrinfo: 192.0.2.3>
2385 * Addrinfo.ip("::1").ipv6_to_ipv4 #=> nil
2386 * Addrinfo.ip("192.0.2.3").ipv6_to_ipv4 #=> nil
2387 * Addrinfo.unix("/tmp/sock").ipv6_to_ipv4 #=> nil
2388 */
2389static VALUE
2390addrinfo_ipv6_to_ipv4(VALUE self)
2391{
2392 rb_addrinfo_t *rai = get_addrinfo(self);
2393 struct in6_addr *addr;
2394 int family = ai_get_afamily(rai);
2395 if (family != AF_INET6) return Qnil;
2396 addr = &rai->addr.in6.sin6_addr;
2397 if (IN6_IS_ADDR_V4MAPPED(addr) || IN6_IS_ADDR_V4COMPAT(addr)) {
2398 struct sockaddr_in sin4;
2399 INIT_SOCKADDR_IN(&sin4, sizeof(sin4));
2400 memcpy(&sin4.sin_addr, (char*)addr + sizeof(*addr) - sizeof(sin4.sin_addr), sizeof(sin4.sin_addr));
2401 return rsock_addrinfo_new((struct sockaddr *)&sin4, (socklen_t)sizeof(sin4),
2402 PF_INET, rai->socktype, rai->protocol,
2403 rai->canonname, rai->inspectname);
2404 }
2405 else {
2406 return Qnil;
2407 }
2408}
2409
2410#endif
2411
2412#ifdef HAVE_SYS_UN_H
2413/*
2414 * call-seq:
2415 * addrinfo.unix_path => path
2416 *
2417 * Returns the socket path as a string.
2418 *
2419 * Addrinfo.unix("/tmp/sock").unix_path #=> "/tmp/sock"
2420 */
2421static VALUE
2422addrinfo_unix_path(VALUE self)
2423{
2424 rb_addrinfo_t *rai = get_addrinfo(self);
2425 int family = ai_get_afamily(rai);
2426 struct sockaddr_un *addr;
2427 long n;
2428
2429 if (family != AF_UNIX)
2430 rb_raise(rb_eSocket, "need AF_UNIX address");
2431
2432 addr = &rai->addr.un;
2433
2434 n = rai_unixsocket_len(rai);
2435 if (n < 0)
2436 rb_raise(rb_eSocket, "too short AF_UNIX address: %"PRIuSIZE" bytes given for minimum %"PRIuSIZE" bytes.",
2437 (size_t)rai->sockaddr_len, offsetof(struct sockaddr_un, sun_path));
2438 if ((long)sizeof(addr->sun_path) < n)
2440 "too long AF_UNIX path (%"PRIuSIZE" bytes given but %"PRIuSIZE" bytes max)",
2441 (size_t)n, sizeof(addr->sun_path));
2442 return rb_str_new(addr->sun_path, n);
2443}
2444#endif
2445
2446static ID id_timeout;
2447
2448/*
2449 * call-seq:
2450 * Addrinfo.getaddrinfo(nodename, service, family, socktype, protocol, flags) => [addrinfo, ...]
2451 * Addrinfo.getaddrinfo(nodename, service, family, socktype, protocol) => [addrinfo, ...]
2452 * Addrinfo.getaddrinfo(nodename, service, family, socktype) => [addrinfo, ...]
2453 * Addrinfo.getaddrinfo(nodename, service, family) => [addrinfo, ...]
2454 * Addrinfo.getaddrinfo(nodename, service) => [addrinfo, ...]
2455 *
2456 * returns a list of addrinfo objects as an array.
2457 *
2458 * This method converts nodename (hostname) and service (port) to addrinfo.
2459 * Since the conversion is not unique, the result is a list of addrinfo objects.
2460 *
2461 * nodename or service can be nil if no conversion intended.
2462 *
2463 * family, socktype and protocol are hint for preferred protocol.
2464 * If the result will be used for a socket with SOCK_STREAM,
2465 * SOCK_STREAM should be specified as socktype.
2466 * If so, Addrinfo.getaddrinfo returns addrinfo list appropriate for SOCK_STREAM.
2467 * If they are omitted or nil is given, the result is not restricted.
2468 *
2469 * Similarly, PF_INET6 as family restricts for IPv6.
2470 *
2471 * flags should be bitwise OR of Socket::AI_??? constants such as follows.
2472 * Note that the exact list of the constants depends on OS.
2473 *
2474 * AI_PASSIVE Get address to use with bind()
2475 * AI_CANONNAME Fill in the canonical name
2476 * AI_NUMERICHOST Prevent host name resolution
2477 * AI_NUMERICSERV Prevent service name resolution
2478 * AI_V4MAPPED Accept IPv4-mapped IPv6 addresses
2479 * AI_ALL Allow all addresses
2480 * AI_ADDRCONFIG Accept only if any address is assigned
2481 *
2482 * Note that socktype should be specified whenever application knows the usage of the address.
2483 * Some platform causes an error when socktype is omitted and servname is specified as an integer
2484 * because some port numbers, 512 for example, are ambiguous without socktype.
2485 *
2486 * Addrinfo.getaddrinfo("www.kame.net", 80, nil, :STREAM)
2487 * #=> [#<Addrinfo: 203.178.141.194:80 TCP (www.kame.net)>,
2488 * # #<Addrinfo: [2001:200:dff:fff1:216:3eff:feb1:44d7]:80 TCP (www.kame.net)>]
2489 *
2490 */
2491static VALUE
2492addrinfo_s_getaddrinfo(int argc, VALUE *argv, VALUE self)
2493{
2494 VALUE node, service, family, socktype, protocol, flags, opts, timeout;
2495
2496 rb_scan_args(argc, argv, "24:", &node, &service, &family, &socktype,
2497 &protocol, &flags, &opts);
2498 rb_get_kwargs(opts, &id_timeout, 0, 1, &timeout);
2499 timeout = Qnil;
2500
2501 return addrinfo_list_new(node, service, family, socktype, protocol, flags, timeout);
2502}
2503
2504/*
2505 * call-seq:
2506 * Addrinfo.ip(host) => addrinfo
2507 *
2508 * returns an addrinfo object for IP address.
2509 *
2510 * The port, socktype, protocol of the result is filled by zero.
2511 * So, it is not appropriate to create a socket.
2512 *
2513 * Addrinfo.ip("localhost") #=> #<Addrinfo: 127.0.0.1 (localhost)>
2514 */
2515static VALUE
2516addrinfo_s_ip(VALUE self, VALUE host)
2517{
2518 VALUE ret;
2519 rb_addrinfo_t *rai;
2520 ret = addrinfo_firstonly_new(host, Qnil,
2521 INT2NUM(PF_UNSPEC), INT2FIX(0), INT2FIX(0), INT2FIX(0));
2522 rai = get_addrinfo(ret);
2523 rai->socktype = 0;
2524 rai->protocol = 0;
2525 return ret;
2526}
2527
2528/*
2529 * call-seq:
2530 * Addrinfo.tcp(host, port) => addrinfo
2531 *
2532 * returns an addrinfo object for TCP address.
2533 *
2534 * Addrinfo.tcp("localhost", "smtp") #=> #<Addrinfo: 127.0.0.1:25 TCP (localhost:smtp)>
2535 */
2536static VALUE
2537addrinfo_s_tcp(VALUE self, VALUE host, VALUE port)
2538{
2539 return addrinfo_firstonly_new(host, port,
2540 INT2NUM(PF_UNSPEC), INT2NUM(SOCK_STREAM), INT2NUM(IPPROTO_TCP), INT2FIX(0));
2541}
2542
2543/*
2544 * call-seq:
2545 * Addrinfo.udp(host, port) => addrinfo
2546 *
2547 * returns an addrinfo object for UDP address.
2548 *
2549 * Addrinfo.udp("localhost", "daytime") #=> #<Addrinfo: 127.0.0.1:13 UDP (localhost:daytime)>
2550 */
2551static VALUE
2552addrinfo_s_udp(VALUE self, VALUE host, VALUE port)
2553{
2554 return addrinfo_firstonly_new(host, port,
2555 INT2NUM(PF_UNSPEC), INT2NUM(SOCK_DGRAM), INT2NUM(IPPROTO_UDP), INT2FIX(0));
2556}
2557
2558#ifdef HAVE_SYS_UN_H
2559
2560/*
2561 * call-seq:
2562 * Addrinfo.unix(path [, socktype]) => addrinfo
2563 *
2564 * returns an addrinfo object for UNIX socket address.
2565 *
2566 * _socktype_ specifies the socket type.
2567 * If it is omitted, :STREAM is used.
2568 *
2569 * Addrinfo.unix("/tmp/sock") #=> #<Addrinfo: /tmp/sock SOCK_STREAM>
2570 * Addrinfo.unix("/tmp/sock", :DGRAM) #=> #<Addrinfo: /tmp/sock SOCK_DGRAM>
2571 */
2572static VALUE
2573addrinfo_s_unix(int argc, VALUE *argv, VALUE self)
2574{
2575 VALUE path, vsocktype, addr;
2576 int socktype;
2577 rb_addrinfo_t *rai;
2578
2579 rb_scan_args(argc, argv, "11", &path, &vsocktype);
2580
2581 if (NIL_P(vsocktype))
2582 socktype = SOCK_STREAM;
2583 else
2584 socktype = rsock_socktype_arg(vsocktype);
2585
2586 addr = addrinfo_s_allocate(rb_cAddrinfo);
2587 DATA_PTR(addr) = rai = alloc_addrinfo();
2588 init_unix_addrinfo(rai, path, socktype);
2589 return addr;
2590}
2591
2592#endif
2593
2594VALUE
2596{
2597 VALUE val = *v;
2598 if (IS_ADDRINFO(val)) {
2599 *v = addrinfo_to_sockaddr(val);
2600 }
2601 StringValue(*v);
2602 return *v;
2603}
2604
2605VALUE
2607{
2608 VALUE val = *v;
2609 *rai_ret = Qnil;
2610 if (IS_ADDRINFO(val)) {
2611 *v = addrinfo_to_sockaddr(val);
2612 *rai_ret = val;
2613 }
2614 StringValue(*v);
2615 return *v;
2616}
2617
2618char *
2620{
2622 return RSTRING_PTR(*v);
2623}
2624
2625VALUE
2627{
2628 if (IS_ADDRINFO(val))
2629 return addrinfo_to_sockaddr(val);
2630 return rb_check_string_type(val);
2631}
2632
2633VALUE
2634rsock_fd_socket_addrinfo(int fd, struct sockaddr *addr, socklen_t len)
2635{
2636 int family;
2637 int socktype;
2638 int ret;
2639 socklen_t optlen = (socklen_t)sizeof(socktype);
2640
2641 /* assumes protocol family and address family are identical */
2642 family = get_afamily(addr, len);
2643
2644 ret = getsockopt(fd, SOL_SOCKET, SO_TYPE, (void*)&socktype, &optlen);
2645 if (ret == -1) {
2646 rb_sys_fail("getsockopt(SO_TYPE)");
2647 }
2648
2649 return rsock_addrinfo_new(addr, len, family, socktype, 0, Qnil, Qnil);
2650}
2651
2652VALUE
2653rsock_io_socket_addrinfo(VALUE io, struct sockaddr *addr, socklen_t len)
2654{
2655 rb_io_t *fptr;
2656
2657 switch (TYPE(io)) {
2658 case T_FIXNUM:
2659 return rsock_fd_socket_addrinfo(FIX2INT(io), addr, len);
2660
2661 case T_BIGNUM:
2662 return rsock_fd_socket_addrinfo(NUM2INT(io), addr, len);
2663
2664 case T_FILE:
2665 GetOpenFile(io, fptr);
2666 return rsock_fd_socket_addrinfo(fptr->fd, addr, len);
2667
2668 default:
2669 rb_raise(rb_eTypeError, "neither IO nor file descriptor");
2670 }
2671
2673}
2674
2675/*
2676 * Addrinfo class
2677 */
2678void
2680{
2681 /*
2682 * The Addrinfo class maps <tt>struct addrinfo</tt> to ruby. This
2683 * structure identifies an Internet host and a service.
2684 */
2685 id_timeout = rb_intern("timeout");
2686
2687 rb_cAddrinfo = rb_define_class("Addrinfo", rb_cData);
2688 rb_define_alloc_func(rb_cAddrinfo, addrinfo_s_allocate);
2689 rb_define_method(rb_cAddrinfo, "initialize", addrinfo_initialize, -1);
2690 rb_define_method(rb_cAddrinfo, "inspect", addrinfo_inspect, 0);
2692 rb_define_singleton_method(rb_cAddrinfo, "getaddrinfo", addrinfo_s_getaddrinfo, -1);
2693 rb_define_singleton_method(rb_cAddrinfo, "ip", addrinfo_s_ip, 1);
2694 rb_define_singleton_method(rb_cAddrinfo, "tcp", addrinfo_s_tcp, 2);
2695 rb_define_singleton_method(rb_cAddrinfo, "udp", addrinfo_s_udp, 2);
2696#ifdef HAVE_SYS_UN_H
2697 rb_define_singleton_method(rb_cAddrinfo, "unix", addrinfo_s_unix, -1);
2698#endif
2699
2700 rb_define_method(rb_cAddrinfo, "afamily", addrinfo_afamily, 0);
2701 rb_define_method(rb_cAddrinfo, "pfamily", addrinfo_pfamily, 0);
2702 rb_define_method(rb_cAddrinfo, "socktype", addrinfo_socktype, 0);
2703 rb_define_method(rb_cAddrinfo, "protocol", addrinfo_protocol, 0);
2704 rb_define_method(rb_cAddrinfo, "canonname", addrinfo_canonname, 0);
2705
2706 rb_define_method(rb_cAddrinfo, "ipv4?", addrinfo_ipv4_p, 0);
2707 rb_define_method(rb_cAddrinfo, "ipv6?", addrinfo_ipv6_p, 0);
2708 rb_define_method(rb_cAddrinfo, "unix?", addrinfo_unix_p, 0);
2709
2710 rb_define_method(rb_cAddrinfo, "ip?", addrinfo_ip_p, 0);
2711 rb_define_method(rb_cAddrinfo, "ip_unpack", addrinfo_ip_unpack, 0);
2712 rb_define_method(rb_cAddrinfo, "ip_address", addrinfo_ip_address, 0);
2713 rb_define_method(rb_cAddrinfo, "ip_port", addrinfo_ip_port, 0);
2714
2715 rb_define_method(rb_cAddrinfo, "ipv4_private?", addrinfo_ipv4_private_p, 0);
2716 rb_define_method(rb_cAddrinfo, "ipv4_loopback?", addrinfo_ipv4_loopback_p, 0);
2717 rb_define_method(rb_cAddrinfo, "ipv4_multicast?", addrinfo_ipv4_multicast_p, 0);
2718
2719#ifdef INET6
2720 rb_define_method(rb_cAddrinfo, "ipv6_unspecified?", addrinfo_ipv6_unspecified_p, 0);
2721 rb_define_method(rb_cAddrinfo, "ipv6_loopback?", addrinfo_ipv6_loopback_p, 0);
2722 rb_define_method(rb_cAddrinfo, "ipv6_multicast?", addrinfo_ipv6_multicast_p, 0);
2723 rb_define_method(rb_cAddrinfo, "ipv6_linklocal?", addrinfo_ipv6_linklocal_p, 0);
2724 rb_define_method(rb_cAddrinfo, "ipv6_sitelocal?", addrinfo_ipv6_sitelocal_p, 0);
2725 rb_define_method(rb_cAddrinfo, "ipv6_unique_local?", addrinfo_ipv6_unique_local_p, 0);
2726 rb_define_method(rb_cAddrinfo, "ipv6_v4mapped?", addrinfo_ipv6_v4mapped_p, 0);
2727 rb_define_method(rb_cAddrinfo, "ipv6_v4compat?", addrinfo_ipv6_v4compat_p, 0);
2728 rb_define_method(rb_cAddrinfo, "ipv6_mc_nodelocal?", addrinfo_ipv6_mc_nodelocal_p, 0);
2729 rb_define_method(rb_cAddrinfo, "ipv6_mc_linklocal?", addrinfo_ipv6_mc_linklocal_p, 0);
2730 rb_define_method(rb_cAddrinfo, "ipv6_mc_sitelocal?", addrinfo_ipv6_mc_sitelocal_p, 0);
2731 rb_define_method(rb_cAddrinfo, "ipv6_mc_orglocal?", addrinfo_ipv6_mc_orglocal_p, 0);
2732 rb_define_method(rb_cAddrinfo, "ipv6_mc_global?", addrinfo_ipv6_mc_global_p, 0);
2733
2734 rb_define_method(rb_cAddrinfo, "ipv6_to_ipv4", addrinfo_ipv6_to_ipv4, 0);
2735#endif
2736
2737#ifdef HAVE_SYS_UN_H
2738 rb_define_method(rb_cAddrinfo, "unix_path", addrinfo_unix_path, 0);
2739#endif
2740
2741 rb_define_method(rb_cAddrinfo, "to_sockaddr", addrinfo_to_sockaddr, 0);
2742 rb_define_method(rb_cAddrinfo, "to_s", addrinfo_to_sockaddr, 0); /* compatibility for ruby before 1.9.2 */
2743
2744 rb_define_method(rb_cAddrinfo, "getnameinfo", addrinfo_getnameinfo, -1);
2745
2746 rb_define_method(rb_cAddrinfo, "marshal_dump", addrinfo_mdump, 0);
2747 rb_define_method(rb_cAddrinfo, "marshal_load", addrinfo_mload, 1);
2748}
int errno
#define EAI_NONAME
Definition: addrinfo.h:85
#define AI_NUMERICHOST
Definition: addrinfo.h:98
#define NI_NUMERICHOST
Definition: addrinfo.h:125
#define EAI_AGAIN
Definition: addrinfo.h:79
#define AI_NUMERICSERV
Definition: addrinfo.h:99
#define EAI_SYSTEM
Definition: addrinfo.h:88
#define NI_DGRAM
Definition: addrinfo.h:128
#define EAI_FAIL
Definition: addrinfo.h:81
#define NI_MAXHOST
Definition: addrinfo.h:117
#define NI_MAXSERV
Definition: addrinfo.h:118
#define NI_NUMERICSERV
Definition: addrinfo.h:127
int rsock_family_arg(VALUE domain)
Definition: constants.c:42
int rsock_socktype_arg(VALUE type)
Definition: constants.c:49
int rsock_family_to_int(const char *str, long len, int *valp)
Definition: constdefs.c:4468
int rsock_socktype_to_int(const char *str, long len, int *valp)
Definition: constdefs.c:4863
ID rsock_intern_family(int val)
Definition: constdefs.c:6748
ID rsock_intern_socktype(int val)
Definition: constdefs.c:6775
int rsock_ipproto_to_int(const char *str, long len, int *valp)
Definition: constdefs.c:4934
ID rsock_intern_ipproto(int val)
Definition: constdefs.c:6784
ID rsock_intern_protocol_family(int val)
Definition: constdefs.c:6766
struct RIMemo * ptr
Definition: debug.c:65
st_table * names
Definition: encoding.c:59
struct rb_encoding_entry * list
Definition: encoding.c:56
void freeaddrinfo(struct addrinfo *ai)
Definition: getaddrinfo.c:216
int socklen_t
Definition: getaddrinfo.c:83
int getaddrinfo(const char *hostname, const char *servname, const struct addrinfo *hints, struct addrinfo **res)
Definition: getaddrinfo.c:272
int getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, socklen_t hostlen, char *serv, socklen_t servlen, int flags)
Definition: getnameinfo.c:122
VALUE rb_define_class(const char *, VALUE)
Defines a top-level class.
Definition: class.c:662
int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *)
Definition: class.c:1904
VALUE rb_cData
Data class.
Definition: ruby.h:2020
VALUE rb_cInteger
Definition: ruby.h:2033
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:2671
VALUE rb_eTypeError
Definition: error.c:924
void * rb_check_typeddata(VALUE obj, const rb_data_type_t *data_type)
Definition: error.c:891
VALUE rb_eArgError
Definition: error.c:925
VALUE rb_ensure(VALUE(*)(VALUE), VALUE, VALUE(*)(VALUE), VALUE)
An equivalent to ensure clause.
Definition: eval.c:1115
void rb_sys_fail(const char *mesg)
Definition: error.c:2795
VALUE rb_convert_type(VALUE, int, const char *, const char *)
Converts an object into another type.
Definition: object.c:2900
VALUE rb_obj_is_kind_of(VALUE, VALUE)
Determines if obj is a kind of c.
Definition: object.c:692
#define GetOpenFile(obj, fp)
Definition: io.h:127
const char * name
Definition: nkf.c:208
#define IFNAMSIZ
void rb_freeaddrinfo(struct rb_addrinfo *ai)
Definition: raddrinfo.c:396
VALUE rsock_addrinfo_new(struct sockaddr *addr, socklen_t len, int family, int socktype, int protocol, VALUE canonname, VALUE inspectname)
Definition: raddrinfo.c:910
#define addrinfo_free
Definition: raddrinfo.c:845
VALUE rsock_sockaddr_string_value(volatile VALUE *v)
Definition: raddrinfo.c:2595
VALUE rsock_freeaddrinfo(VALUE arg)
Definition: raddrinfo.c:808
void rsock_init_addrinfo(void)
Definition: raddrinfo.c:2679
char * rsock_sockaddr_string_value_ptr(volatile VALUE *v)
Definition: raddrinfo.c:2619
struct rb_addrinfo * rsock_getaddrinfo(VALUE host, VALUE port, struct addrinfo *hints, int socktype_hack)
Definition: raddrinfo.c:576
VALUE rsock_make_hostent(VALUE host, struct rb_addrinfo *addr, VALUE(*ipaddr)(struct sockaddr *, socklen_t))
Definition: raddrinfo.c:816
VALUE rsock_make_ipaddr(struct sockaddr *addr, socklen_t addrlen)
Definition: raddrinfo.c:470
VALUE rsock_addrinfo_inspect_sockaddr(VALUE self)
Definition: raddrinfo.c:1641
#define str_equal(ptr, len, name)
Definition: raddrinfo.c:503
VALUE rsock_inspect_sockaddr(struct sockaddr *sockaddr_arg, socklen_t socklen, VALUE ret)
Definition: raddrinfo.c:1266
VALUE rb_check_sockaddr_string_type(VALUE val)
Definition: raddrinfo.c:2626
VALUE rsock_sockaddr_string_value_with_addrinfo(volatile VALUE *v, VALUE *rai_ret)
Definition: raddrinfo.c:2606
int rb_getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct rb_addrinfo **res)
Definition: raddrinfo.c:309
struct rb_addrinfo * rsock_addrinfo(VALUE host, VALUE port, int family, int socktype, int flags)
Definition: raddrinfo.c:653
VALUE rsock_ipaddr(struct sockaddr *sockaddr, socklen_t sockaddrlen, int norevlookup)
Definition: raddrinfo.c:665
int rsock_fd_family(int fd)
Definition: raddrinfo.c:640
int rb_getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags)
Definition: raddrinfo.c:437
VALUE rsock_fd_socket_addrinfo(int fd, struct sockaddr *addr, socklen_t len)
Definition: raddrinfo.c:2634
VALUE rsock_io_socket_addrinfo(VALUE io, struct sockaddr *addr, socklen_t len)
Definition: raddrinfo.c:2653
#define IS_ADDRINFO(obj)
Definition: raddrinfo.c:864
__uint32_t uint32_t
#define rb_str_new2
#define ENOENT
#define MEMCPY(p1, p2, type, n)
#define NULL
#define T_FILE
use StringValue() instead")))
#define RSTRING_LEN(str)
#define rb_str_buf_cat2
int sprintf(char *__restrict__, const char *__restrict__,...) __attribute__((__format__(__printf__
#define STRTOUL(str, endptr, base)
size_t strlen(const char *)
int strcmp(const char *, const char *)
#define T_STRING
VALUE rb_assoc_new(VALUE, VALUE)
Definition: array.c:896
#define offsetof(TYPE, MEMBER)
#define PRIuSIZE
#define xfree
int atoi(const char *__nptr)
#define rb_str_cat2
#define TYPE(x)
#define RSTRING_PTR(str)
const rb_iseq_t const char * error
size_t strspn(const char *, const char *)
#define T_BIGNUM
#define RUBY_UBF_IO
char * strncpy(char *__restrict__, const char *__restrict__, size_t)
int snprintf(char *__restrict__, size_t, const char *__restrict__,...) __attribute__((__format__(__printf__
#define rb_str_new(str, len)
#define NIL_P(v)
#define numberof(array)
VALUE rb_str_cat(VALUE, const char *, long)
Definition: string.c:2812
const char * rb_id2name(ID)
Definition: symbol.c:801
#define T_FIXNUM
const char size_t n
#define MEMZERO(p, type, n)
unsigned long VALUE
VALUE rb_ary_push(VALUE, VALUE)
Definition: array.c:1195
VALUE rb_check_string_type(VALUE)
Definition: string.c:2314
#define xmalloc
void rb_define_alloc_func(VALUE, rb_alloc_func_t)
uint32_t i
#define NUM2UINT(x)
#define RSTRING_GETMEM(str, ptrvar, lenvar)
__inline__ const void *__restrict__ size_t len
const char * rb_obj_classname(VALUE)
Definition: variable.c:289
#define OBJ_FREEZE(x)
#define INT2NUM(x)
#define ZALLOC(type)
#define NUM2INT(x)
void rb_define_singleton_method(VALUE, const char *, VALUE(*)(), int)
VALUE rb_str_equal(VALUE str1, VALUE str2)
Definition: string.c:3267
#define rb_ary_new3
#define FIX2INT(x)
int VALUE v
VALUE rb_ary_new(void)
Definition: array.c:723
#define rb_scan_args(argc, argvp, fmt,...)
void rb_gc_mark(VALUE)
Definition: gc.c:5228
#define rb_intern(str)
#define UNREACHABLE_RETURN(val)
#define TypedData_Wrap_Struct(klass, data_type, sval)
VALUE rb_str_catf(VALUE, const char *,...) __attribute__((format(printf
#define Qtrue
long unsigned int size_t
struct rb_call_cache buf
#define Qnil
#define Qfalse
__uint32_t u_int32_t
#define DATA_PTR(dta)
#define T_ARRAY
void * memcpy(void *__restrict__, const void *__restrict__, size_t)
#define RB_TYPE_P(obj, type)
#define INT2FIX(i)
VALUE rb_check_array_type(VALUE)
Definition: array.c:909
const VALUE * argv
__inline__ int
#define FIXNUM_P(f)
struct timespec rb_time_timespec_interval(VALUE num)
Definition: time.c:2720
double sin(double)
#define xcalloc
VALUE rb_str_dup(VALUE)
Definition: string.c:1516
VALUE rb_sprintf(const char *,...) __attribute__((format(printf
unsigned long ID
size_t st_index_t h
#define ISSPACE(c)
VALUE ID id
#define FIX2LONG(x)
void rb_define_method(VALUE, const char *, VALUE(*)(), int)
#define rb_ary_new2
#define rb_str_new_cstr(str)
void rb_ary_store(VALUE, long, VALUE)
Definition: array.c:1079
#define ISPRINT(c)
VALUE rb_ary_entry(VALUE, long)
Definition: array.c:1512
#define StringValueCStr(v)
#define IS_IP_FAMILY(af)
Definition: rubysocket.h:162
#define SOCKLEN_MAX
Definition: rubysocket.h:124
#define IN6_IS_ADDR_UNIQUE_LOCAL(a)
Definition: rubysocket.h:166
#define RSTRING_SOCKLEN
Definition: rubysocket.h:130
#define INADDR_BROADCAST
Definition: constdefs.h:747
#define INADDR_ANY
Definition: constdefs.h:740
#define IPPROTO_TCP
Definition: constdefs.h:610
#define IPPROTO_UDP
Definition: constdefs.h:627
void rsock_raise_socket_error(const char *reason, int error)
Definition: init.c:39
VALUE rb_eSocket
Definition: init.c:29
VALUE rb_cAddrinfo
Definition: init.c:27
#define PF_INET
Definition: sockport.h:109
#define PF_UNSPEC
Definition: sockport.h:105
#define INIT_SOCKADDR_IN(addr, len)
Definition: sockport.h:47
#define INIT_SOCKADDR_IN6(addr, len)
Definition: sockport.h:56
#define AF_UNSPEC
Definition: sockport.h:101
#define const
Definition: strftime.c:103
size_t ai_addrlen
Definition: addrinfo.h:136
struct sockaddr * ai_addr
Definition: addrinfo.h:138
char * ai_canonname
Definition: addrinfo.h:137
int ai_socktype
Definition: addrinfo.h:134
int ai_protocol
Definition: addrinfo.h:135
struct addrinfo * ai_next
Definition: addrinfo.h:139
int ai_flags
Definition: addrinfo.h:132
int ai_family
Definition: addrinfo.h:133
const struct addrinfo * hints
Definition: raddrinfo.c:181
const char * service
Definition: raddrinfo.c:180
struct addrinfo ** res
Definition: raddrinfo.c:182
const char * node
Definition: raddrinfo.c:179
size_t servlen
Definition: raddrinfo.c:422
socklen_t salen
Definition: raddrinfo.c:417
size_t hostlen
Definition: raddrinfo.c:420
const struct sockaddr * sa
Definition: raddrinfo.c:416
VALUE(* ipaddr)(struct sockaddr *, socklen_t)
Definition: raddrinfo.c:759
struct rb_addrinfo * addr
Definition: raddrinfo.c:758
VALUE host
Definition: raddrinfo.c:757
union_sockaddr addr
Definition: raddrinfo.c:834
socklen_t sockaddr_len
Definition: raddrinfo.c:833
VALUE canonname
Definition: raddrinfo.c:829
VALUE inspectname
Definition: raddrinfo.c:828
struct addrinfo * ai
Definition: rubysocket.h:291
int allocated_by_malloc
Definition: rubysocket.h:292
Definition: io.h:66
int fd
Definition: io.h:68
void * rb_thread_call_without_gvl(void *(*func)(void *), void *data1, rb_unblock_function_t *ubf, void *data2)
struct sockaddr_in in
Definition: rubysocket.h:194
struct sockaddr addr
Definition: rubysocket.h:193
#define rb_id2str(id)
Definition: vm_backtrace.c:30