[glib] GSocketAddress: create IPv4 addresses for IPv6 mapped-IPv4 addresses



commit fb74f6e303ee89ab8b37708556a24b5e219c1db1
Author: Dan Winship <danw gnome org>
Date:   Sat Aug 27 19:46:51 2011 -0400

    GSocketAddress: create IPv4 addresses for IPv6 mapped-IPv4 addresses
    
    IPv6-mapped-IPv4 addresses are annoying. Just translate them to real
    IPv4 addresses.
    
    based on a patch from Jonny Lamb
    https://bugzilla.gnome.org/show_bug.cgi?id=646082

 gio/gsocketaddress.c |   15 +++++++-
 gio/tests/socket.c   |  107 +++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 116 insertions(+), 6 deletions(-)
---
diff --git a/gio/gsocketaddress.c b/gio/gsocketaddress.c
index 1c110a0..591a64e 100644
--- a/gio/gsocketaddress.c
+++ b/gio/gsocketaddress.c
@@ -241,7 +241,20 @@ g_socket_address_new_from_native (gpointer native,
       if (len < sizeof (*addr))
 	return NULL;
 
-      iaddr = g_inet_address_new_from_bytes ((guint8 *) &(addr->sin6_addr), AF_INET6);
+      if (IN6_IS_ADDR_V4MAPPED (&(addr->sin6_addr)))
+	{
+	  struct sockaddr_in sin_addr;
+
+	  sin_addr.sin_family = AF_INET;
+	  sin_addr.sin_port = addr->sin6_port;
+	  memcpy (&(sin_addr.sin_addr.s_addr), addr->sin6_addr.s6_addr + 12, 4);
+	  iaddr = g_inet_address_new_from_bytes ((guint8 *) &(sin_addr.sin_addr), AF_INET);
+	}
+      else
+	{
+	  iaddr = g_inet_address_new_from_bytes ((guint8 *) &(addr->sin6_addr), AF_INET6);
+	}
+
       sockaddr = g_inet_socket_address_new (iaddr, g_ntohs (addr->sin6_port));
       g_object_unref (iaddr);
       return sockaddr;
diff --git a/gio/tests/socket.c b/gio/tests/socket.c
index 2b8ea62..3ed030d 100644
--- a/gio/tests/socket.c
+++ b/gio/tests/socket.c
@@ -30,6 +30,8 @@
 #include <gio/gunixconnection.h>
 #endif
 
+#include "gnetworkingprivate.h"
+
 typedef struct {
   GSocket *server;
   GSocket *client;
@@ -70,7 +72,9 @@ echo_server_thread (gpointer user_data)
 }
 
 static IPTestData *
-create_server (GSocketFamily family)
+create_server (GSocketFamily family,
+	       GThreadFunc   server_thread,
+	       gboolean      v4mapped)
 {
   IPTestData *data;
   GSocket *server;
@@ -93,7 +97,21 @@ create_server (GSocketFamily family)
 
   g_socket_set_blocking (server, TRUE);
 
-  iaddr = g_inet_address_new_loopback (family);
+#if defined (IPPROTO_IPV6) && defined (IPV6_V6ONLY)
+  if (v4mapped)
+    {
+      int fd, v6_only;
+
+      fd = g_socket_get_fd (server);
+      v6_only = 0;
+      setsockopt (fd, IPPROTO_IPV6, IPV6_V6ONLY, &v6_only, sizeof (v6_only));
+    }
+#endif
+
+  if (v4mapped)
+    iaddr = g_inet_address_new_any (family);
+  else
+    iaddr = g_inet_address_new_loopback (family);
   addr = g_inet_socket_address_new (iaddr, 0);
   g_object_unref (iaddr);
 
@@ -105,11 +123,12 @@ create_server (GSocketFamily family)
   addr = g_socket_get_local_address (server, &error);
   g_assert_no_error (error);
   g_assert_cmpint (g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr)), !=, 0);
+  g_object_unref (addr);
 
   g_socket_listen (server, &error);
   g_assert_no_error (error);
 
-  data->thread = g_thread_create (echo_server_thread, data, TRUE, &error);
+  data->thread = g_thread_create (server_thread, data, TRUE, &error);
   g_assert_no_error (error);
 
   return data;
@@ -253,7 +272,7 @@ test_ip_async (GSocketFamily family)
   gssize len;
   gchar buf[128];
 
-  data = create_server (family);
+  data = create_server (family, echo_server_thread, FALSE);
   addr = g_socket_get_local_address (data->server, &error);
 
   client = g_socket_new (family,
@@ -285,6 +304,7 @@ test_ip_async (GSocketFamily family)
       g_source_attach (source, NULL);
       g_source_unref (source);
     }
+  g_object_unref (addr);
 
   data->loop = g_main_loop_new (NULL, TRUE);
   g_main_loop_run (data->loop);
@@ -332,7 +352,7 @@ test_ip_sync (GSocketFamily family)
   gssize len;
   gchar buf[128];
 
-  data = create_server (family);
+  data = create_server (family, echo_server_thread, FALSE);
   addr = g_socket_get_local_address (data->server, &error);
 
   client = g_socket_new (family,
@@ -351,6 +371,7 @@ test_ip_sync (GSocketFamily family)
   g_socket_connect (client, addr, NULL, &error);
   g_assert_no_error (error);
   g_assert (g_socket_is_connected (client));
+  g_object_unref (addr);
 
   /* This adds 1 second to "make check", so let's just only do it once. */
   if (family == G_SOCKET_FAMILY_IPV4)
@@ -403,6 +424,79 @@ test_ipv6_sync (void)
   test_ip_sync (G_SOCKET_FAMILY_IPV6);
 }
 
+#if defined (IPPROTO_IPV6) && defined (IPV6_V6ONLY)
+static gpointer
+v4mapped_server_thread (gpointer user_data)
+{
+  IPTestData *data = user_data;
+  GSocket *sock;
+  GError *error = NULL;
+  GSocketAddress *addr;
+
+  sock = g_socket_accept (data->server, NULL, &error);
+  g_assert_no_error (error);
+
+  g_assert_cmpint (g_socket_get_family (sock), ==, G_SOCKET_FAMILY_IPV6);
+
+  addr = g_socket_get_local_address (sock, &error);
+  g_assert_no_error (error);
+  g_assert_cmpint (g_socket_address_get_family (addr), ==, G_SOCKET_FAMILY_IPV4);
+  g_object_unref (addr);
+
+  addr = g_socket_get_remote_address (sock, &error);
+  g_assert_no_error (error);
+  g_assert_cmpint (g_socket_address_get_family (addr), ==, G_SOCKET_FAMILY_IPV4);
+  g_object_unref (addr);
+
+  g_socket_close (sock, &error);
+  g_assert_no_error (error);
+  return NULL;
+}
+
+static void
+test_ipv6_v4mapped (void)
+{
+  IPTestData *data;
+  GError *error = NULL;
+  GSocket *client;
+  GSocketAddress *addr, *v4addr;
+  GInetAddress *iaddr;
+
+  data = create_server (G_SOCKET_FAMILY_IPV6, v4mapped_server_thread, TRUE);
+
+  client = g_socket_new (G_SOCKET_FAMILY_IPV4,
+			 G_SOCKET_TYPE_STREAM,
+			 G_SOCKET_PROTOCOL_DEFAULT,
+			 &error);
+  g_assert_no_error (error);
+
+  g_socket_set_blocking (client, TRUE);
+  g_socket_set_timeout (client, 1);
+
+  addr = g_socket_get_local_address (data->server, &error);
+  iaddr = g_inet_address_new_loopback (G_SOCKET_FAMILY_IPV4);
+  v4addr = g_inet_socket_address_new (iaddr, g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr)));
+  g_object_unref (iaddr);
+  g_object_unref (addr);
+
+  g_socket_connect (client, v4addr, NULL, &error);
+  g_assert_no_error (error);
+  g_assert (g_socket_is_connected (client));
+
+  g_thread_join (data->thread);
+
+  g_socket_close (client, &error);
+  g_assert_no_error (error);
+  g_socket_close (data->server, &error);
+  g_assert_no_error (error);
+
+  g_object_unref (data->server);
+  g_object_unref (client);
+
+  g_slice_free (IPTestData, data);
+}
+#endif
+
 #ifdef G_OS_UNIX
 static void
 test_unix_from_fd (void)
@@ -555,6 +649,9 @@ main (int   argc,
   g_test_add_func ("/socket/ipv4_async", test_ipv4_async);
   g_test_add_func ("/socket/ipv6_sync", test_ipv6_sync);
   g_test_add_func ("/socket/ipv6_async", test_ipv6_async);
+#if defined (IPPROTO_IPV6) && defined (IPV6_V6ONLY)
+  g_test_add_func ("/socket/ipv6_v4mapped", test_ipv6_v4mapped);
+#endif
 #ifdef G_OS_UNIX
   g_test_add_func ("/socket/unix-from-fd", test_unix_from_fd);
   g_test_add_func ("/socket/unix-connection", test_unix_connection);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]