summaryrefslogtreecommitdiffstats
path: root/ext/socket/raddrinfo.c
diff options
context:
space:
mode:
authorakr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2009-02-04 15:10:03 +0000
committerakr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2009-02-04 15:10:03 +0000
commit3183b7a7df21e2b0eca764ef332162ef3910ba9e (patch)
treef42529c3c3fa7964ba0a23c3b32ca4eb64432b5e /ext/socket/raddrinfo.c
parent45a4c036414b3de683ca4dc0e5f6f0408122f3bf (diff)
downloadruby-3183b7a7df21e2b0eca764ef332162ef3910ba9e.tar.gz
ruby-3183b7a7df21e2b0eca764ef332162ef3910ba9e.tar.xz
ruby-3183b7a7df21e2b0eca764ef332162ef3910ba9e.zip
* ext/socket/raddrinfo.c (addrinfo_ipv6_to_ipv4): new method.
git-svn-id: http://svn.ruby-lang.org/repos/ruby/trunk@22042 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'ext/socket/raddrinfo.c')
-rw-r--r--ext/socket/raddrinfo.c35
1 files changed, 35 insertions, 0 deletions
diff --git a/ext/socket/raddrinfo.c b/ext/socket/raddrinfo.c
index b2da37c8e..1c1201ab4 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