Bug #743 ยป bug743.patch
| ext/socket/socket.c (working copy) | ||
|---|---|---|
| }; | ||
| static VALUE | ||
| make_hostent_internal(struct hostent_arg *arg) | ||
| make_hostent(struct hostent *h) | ||
| { | ||
|     VALUE host = arg->host; | ||
|     struct addrinfo* addr = arg->addr; | ||
|     VALUE (*ipaddr)(struct sockaddr*, size_t) = arg->ipaddr; | ||
|     VALUE ary, aliases, addresses; | ||
|     char **a; | ||
|     struct addrinfo *ai; | ||
|     struct hostent *h; | ||
|     VALUE ary, names; | ||
|     char **pch; | ||
|     const char* hostp; | ||
|     char hbuf[NI_MAXHOST]; | ||
|     ary = rb_ary_new(); | ||
|     if (addr->ai_canonname) { | ||
| 	hostp = addr->ai_canonname; | ||
|     rb_ary_push(ary, rb_str_new2(h->h_name)); | ||
|     if (h->h_aliases) { | ||
|         aliases = rb_ary_new(); | ||
|         for (a = h->h_aliases; *a; ++a) { | ||
|             rb_ary_push(aliases, rb_str_new2(*a)); | ||
|         } | ||
|     } | ||
|     else { | ||
| 	hostp = host_str(host, hbuf, sizeof(hbuf)); | ||
|         aliases = rb_ary_new2(0); | ||
|     } | ||
|     rb_ary_push(ary, rb_str_new2(hostp)); | ||
|     rb_ary_push(ary, aliases); | ||
|     if (addr->ai_canonname && (h = gethostbyname(addr->ai_canonname))) { | ||
| 	names = rb_ary_new(); | ||
| 	if (h->h_aliases != NULL) { | ||
| 	    for (pch = h->h_aliases; *pch; pch++) { | ||
| 		rb_ary_push(names, rb_str_new2(*pch)); | ||
| 	    } | ||
| 	} | ||
|     rb_ary_push(ary, INT2NUM(h->h_addrtype)); | ||
|     if (h->h_addr_list) { | ||
|         addresses = rb_ary_new(); | ||
|         for (a = h->h_addr_list; *a; ++a) { | ||
|             rb_ary_push(addresses, rb_str_new(*a, h->h_length)); | ||
|         } | ||
|     } | ||
|     else { | ||
| 	names = rb_ary_new2(0); | ||
|         addresses = rb_ary_new2(0); | ||
|     } | ||
|     rb_ary_push(ary, names); | ||
|     rb_ary_push(ary, INT2NUM(addr->ai_family)); | ||
|     for (ai = addr; ai; ai = ai->ai_next) { | ||
| 	rb_ary_push(ary, (*ipaddr)(ai->ai_addr, ai->ai_addrlen)); | ||
|     } | ||
|     rb_ary_push(ary, addresses); | ||
|     return ary; | ||
| } | ||
| static VALUE | ||
| make_hostent(VALUE host, struct addrinfo *addr, VALUE (*ipaddr)(struct sockaddr *, size_t)) | ||
| { | ||
|     struct hostent_arg arg; | ||
|     arg.host = host; | ||
|     arg.addr = addr; | ||
|     arg.ipaddr = ipaddr; | ||
|     return rb_ensure(make_hostent_internal, (VALUE)&arg, | ||
| 		     RUBY_METHOD_FUNC(freeaddrinfo), (VALUE)addr); | ||
| } | ||
| static VALUE | ||
| tcp_sockaddr(struct sockaddr *addr, size_t len) | ||
| { | ||
|     return make_ipaddr(addr); | ||
| } | ||
| static VALUE | ||
| tcp_s_gethostbyname(VALUE obj, VALUE host) | ||
| { | ||
|     rb_secure(3); | ||
|     return make_hostent(host, sock_addrinfo(host, Qnil, SOCK_STREAM, AI_CANONNAME), | ||
| 			tcp_sockaddr); | ||
| } | ||
| static VALUE | ||
| tcp_svr_init(int argc, VALUE *argv, VALUE sock) | ||
| { | ||
|     VALUE arg1, arg2; | ||
| ... | ... | |
|     return base; | ||
| } | ||
| /* | ||
|  * call-seq: Socket.inet_aton(host_addr) => in_addr | ||
|  * | ||
|  * Converts an IP address in dotted-quad notation into a | ||
|  * <code>struct in_addr</code> packed as a Ruby string. | ||
|  * | ||
|  * === Parameters | ||
|  * +host_addr+ - The IP address to convert. | ||
|  * | ||
|  * === Examples | ||
|  *   require 'socket' | ||
|  *   p Socket.gethostbyaddr(Socket.inet_aton("127.0.0.1")) | ||
|  */ | ||
| static VALUE | ||
| sock_sockaddr(struct sockaddr *addr, size_t len) | ||
| sock_s_inet_aton(VALUE obj, VALUE host_addr) | ||
| { | ||
|     char *ptr; | ||
|     const char *cp; | ||
|     struct in_addr addr; | ||
|     switch (addr->sa_family) { | ||
|       case AF_INET: | ||
| 	ptr = (char*)&((struct sockaddr_in*)addr)->sin_addr.s_addr; | ||
| 	len = sizeof(((struct sockaddr_in*)addr)->sin_addr.s_addr); | ||
| 	break; | ||
| #ifdef INET6 | ||
|       case AF_INET6: | ||
| 	ptr = (char*)&((struct sockaddr_in6*)addr)->sin6_addr.s6_addr; | ||
| 	len = sizeof(((struct sockaddr_in6*)addr)->sin6_addr.s6_addr); | ||
| 	break; | ||
| #endif | ||
|       default: | ||
|         rb_raise(rb_eSocket, "unknown socket family:%d", addr->sa_family); | ||
| 	break; | ||
|     cp = StringValueCStr(host_addr); | ||
|     if (!inet_aton(cp, &addr)) { | ||
|         rb_raise(rb_eSocket, "invalid host address"); | ||
|     } | ||
|     return rb_str_new(ptr, len); | ||
|     return rb_str_new((char *)&addr, sizeof(addr)); | ||
| } | ||
| /* | ||
|  * call-seq: Socket.inet_ntoa(in_addr) => host_addr | ||
|  * | ||
|  * Converts a <code>struct in_addr</code> packed as a Ruby string into an IP | ||
|  * address in dotted-quad notation. | ||
|  * | ||
|  * === Parameters | ||
|  * +in_addr+ - The packed <code>struct in_addr</code> to convert. | ||
|  * | ||
|  * === Examples | ||
|  *   require 'socket' | ||
|  *   hostent = Socket.gethostbyname('localhost') | ||
|  *   hostent[3].each { |in_addr| p Socket.inet_ntoa(in_addr) } | ||
|  */ | ||
| static VALUE | ||
| sock_s_inet_ntoa(VALUE obj, VALUE addrstr) | ||
| { | ||
|     struct in_addr *addr; | ||
|     addr = (struct in_addr *)StringValuePtr(addrstr); | ||
|     if (RSTRING_LEN(addrstr) != sizeof(struct in_addr)) { | ||
|         rb_raise(rb_eSocket, "invalid address"); | ||
|     } | ||
|     return rb_str_new2(inet_ntoa(*addr)); | ||
| } | ||
| static VALUE | ||
| sock_s_gethostbyname(VALUE obj, VALUE host) | ||
| { | ||
|     struct hostent *h; | ||
|     char *hostp; | ||
|     rb_secure(3); | ||
|     return make_hostent(host, sock_addrinfo(host, Qnil, SOCK_STREAM, AI_CANONNAME), sock_sockaddr); | ||
|     hostp = StringValueCStr(host); | ||
|     h = gethostbyname(hostp); | ||
|     if (h == NULL) { | ||
| #ifdef HAVE_HSTRERROR | ||
|         extern int h_errno; | ||
|         rb_raise(rb_eSocket, "%s", (char*)hstrerror(h_errno)); | ||
| #else | ||
|         rb_raise(rb_eSocket, "host not found"); | ||
| #endif | ||
|     } | ||
|     return make_hostent(h); | ||
| } | ||
| static VALUE | ||
| ... | ... | |
| { | ||
|     VALUE addr, type; | ||
|     struct hostent *h; | ||
|     struct sockaddr *sa; | ||
|     char **pch; | ||
|     VALUE ary, names; | ||
|     int t = AF_INET; | ||
|     rb_scan_args(argc, argv, "11", &addr, &type); | ||
|     sa = (struct sockaddr*)StringValuePtr(addr); | ||
|     StringValue(addr); | ||
|     if (!NIL_P(type)) { | ||
| 	t = NUM2INT(type); | ||
|     } | ||
| #ifdef INET6 | ||
|     else if (RSTRING_LEN(addr) == 16) { | ||
| 	t = AF_INET6; | ||
|     } | ||
| #endif | ||
|     h = gethostbyaddr(RSTRING_PTR(addr), RSTRING_LEN(addr), t); | ||
|     if (h == NULL) { | ||
| #ifdef HAVE_HSTRERROR | ||
| 	extern int h_errno; | ||
| 	rb_raise(rb_eSocket, "%s", (char*)hstrerror(h_errno)); | ||
|         extern int h_errno; | ||
|         rb_raise(rb_eSocket, "%s", (char*)hstrerror(h_errno)); | ||
| #else | ||
| 	rb_raise(rb_eSocket, "host not found"); | ||
|         rb_raise(rb_eSocket, "host not found"); | ||
| #endif | ||
|     } | ||
|     ary = rb_ary_new(); | ||
|     rb_ary_push(ary, rb_str_new2(h->h_name)); | ||
|     names = rb_ary_new(); | ||
|     rb_ary_push(ary, names); | ||
|     if (h->h_aliases != NULL) { | ||
| 	for (pch = h->h_aliases; *pch; pch++) { | ||
| 	    rb_ary_push(names, rb_str_new2(*pch)); | ||
| 	} | ||
|     } | ||
|     rb_ary_push(ary, INT2NUM(h->h_addrtype)); | ||
| #ifdef h_addr | ||
|     for (pch = h->h_addr_list; *pch; pch++) { | ||
| 	rb_ary_push(ary, rb_str_new(*pch, h->h_length)); | ||
|     } | ||
| #else | ||
|     rb_ary_push(ary, rb_str_new(h->h_addr, h->h_length)); | ||
| #endif | ||
|     return ary; | ||
|     return make_hostent(h); | ||
| } | ||
| static VALUE | ||
| ... | ... | |
|     rb_define_singleton_method(rb_cIPSocket, "getaddress", ip_s_getaddress, 1); | ||
|     rb_cTCPSocket = rb_define_class("TCPSocket", rb_cIPSocket); | ||
|     rb_define_singleton_method(rb_cTCPSocket, "gethostbyname", tcp_s_gethostbyname, 1); | ||
|     rb_define_method(rb_cTCPSocket, "initialize", tcp_init, -1); | ||
| #ifdef SOCKS | ||
| ... | ... | |
|     rb_define_singleton_method(rb_cSocket, "socketpair", sock_s_socketpair, 3); | ||
|     rb_define_singleton_method(rb_cSocket, "pair", sock_s_socketpair, 3); | ||
|     rb_define_singleton_method(rb_cSocket, "gethostname", sock_gethostname, 0); | ||
|     rb_define_singleton_method(rb_cSocket, "inet_aton", sock_s_inet_aton, 1); | ||
|     rb_define_singleton_method(rb_cSocket, "inet_ntoa", sock_s_inet_ntoa, 1); | ||
|     rb_define_singleton_method(rb_cSocket, "gethostbyname", sock_s_gethostbyname, 1); | ||
|     rb_define_singleton_method(rb_cSocket, "gethostbyaddr", sock_s_gethostbyaddr, -1); | ||
|     rb_define_singleton_method(rb_cSocket, "getservbyname", sock_s_getservbyname, -1); | ||