diff options
author | akr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2009-02-04 15:10:03 +0000 |
---|---|---|
committer | akr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2009-02-04 15:10:03 +0000 |
commit | 9dfc90dc70faf1a9be1f3051a7ac831b0cf2ba51 (patch) | |
tree | f42529c3c3fa7964ba0a23c3b32ca4eb64432b5e | |
parent | ac5b6813341f00b69b4ff286f94dbde91e8c0d59 (diff) | |
download | ruby-9dfc90dc70faf1a9be1f3051a7ac831b0cf2ba51.tar.gz |
* ext/socket/raddrinfo.c (addrinfo_ipv6_to_ipv4): new method.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@22042 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r-- | ChangeLog | 4 | ||||
-rw-r--r-- | ext/socket/raddrinfo.c | 35 |
2 files changed, 39 insertions, 0 deletions
@@ -1,3 +1,7 @@ +Thu Feb 5 00:09:39 2009 Tanaka Akira <akr@fsij.org> + + * ext/socket/raddrinfo.c (addrinfo_ipv6_to_ipv4): new method. + Wed Feb 4 21:59:31 2009 Tanaka Akira <akr@fsij.org> * transcode.c (make_econv_exception): show U+XXXX form for undefined diff --git a/ext/socket/raddrinfo.c b/ext/socket/raddrinfo.c index b2da37c8e2..1c1201ab4b 100644 --- a/ext/socket/raddrinfo.c +++ b/ext/socket/raddrinfo.c @@ -1832,6 +1832,39 @@ addrinfo_ipv6_mc_global_p(VALUE self) return Qfalse; } +/* + * Returns IPv4 address of IPv4 mapped/compatible IPv6 address. + * It returns nil if +self+ is not IPv4 mapped/compatible IPv6 address. + * + * AddrInfo.ip("::192.0.2.3").ipv6_to_ipv4 #=> #<AddrInfo: 192.0.2.3> + * AddrInfo.ip("::ffff:192.0.2.3").ipv6_to_ipv4 #=> #<AddrInfo: 192.0.2.3> + * AddrInfo.ip("::1").ipv6_to_ipv4 #=> nil + * AddrInfo.ip("192.0.2.3").ipv6_to_ipv4 #=> nil + * AddrInfo.unix("/tmp/sock").ipv6_to_ipv4 #=> nil + */ +static VALUE +addrinfo_ipv6_to_ipv4(VALUE self) +{ + rb_addrinfo_t *rai = get_addrinfo(self); + struct in6_addr *addr; + int family = ai_get_afamily(rai); + if (family != AF_INET6) return Qnil; + addr = &((struct sockaddr_in6 *)&rai->addr)->sin6_addr; + if (IN6_IS_ADDR_V4MAPPED(addr) || IN6_IS_ADDR_V4COMPAT(addr)) { + struct sockaddr_in sin4; + MEMZERO(&sin4, struct sockaddr_in, 1); + sin4.sin_family = AF_INET; + SET_SIN_LEN(&sin4, sizeof(sin4)); + memcpy(&sin4.sin_addr, (char*)addr + sizeof(*addr) - sizeof(sin4.sin_addr), sizeof(sin4.sin_addr)); + return addrinfo_new((struct sockaddr *)&sin4, sizeof(sin4), + PF_INET, rai->socktype, rai->protocol, + rai->canonname, rai->inspectname); + } + else { + return Qnil; + } +} + #endif #ifdef HAVE_SYS_UN_H @@ -2107,6 +2140,8 @@ Init_addrinfo(void) rb_define_method(rb_cAddrInfo, "ipv6_mc_sitelocal?", addrinfo_ipv6_mc_sitelocal_p, 0); rb_define_method(rb_cAddrInfo, "ipv6_mc_orglocal?", addrinfo_ipv6_mc_orglocal_p, 0); rb_define_method(rb_cAddrInfo, "ipv6_mc_global?", addrinfo_ipv6_mc_global_p, 0); + + rb_define_method(rb_cAddrInfo, "ipv6_to_ipv4", addrinfo_ipv6_to_ipv4, 0); #endif #ifdef HAVE_SYS_UN_H |