gio/tests/socket: add some basic IPv4 and IPv6 tests
authorDan Winship <danw@gnome.org>
Sun, 24 Jul 2011 18:55:05 +0000 (14:55 -0400)
committerDan Winship <danw@gnome.org>
Sun, 24 Jul 2011 18:55:05 +0000 (14:55 -0400)
gio/tests/socket.c

index 00e9598397ce0751ab9731dd72058d0f5179e19e..87b426ef75f65569b1f46f33df5de24804fe914b 100644 (file)
@@ -1,6 +1,6 @@
 /* GLib testing framework examples and tests
  *
- * Copyright (C) 2008-2010 Red Hat, Inc.
+ * Copyright (C) 2008-2011 Red Hat, Inc.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -16,8 +16,6 @@
  * Public License along with this library; if not, write to the
  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  * Boston, MA 02111-1307, USA.
- *
- * Author: David Zeuthen <davidz@redhat.com>
  */
 
 #include <gio/gio.h>
 #include <gio/gunixconnection.h>
 #endif
 
+typedef struct {
+  GSocket *server;
+  GSocket *client;
+  GSocketFamily family;
+  GThread *thread;
+  GMainLoop *loop;
+} IPTestData;
+
+static gpointer
+echo_server_thread (gpointer user_data)
+{
+  IPTestData *data = user_data;
+  GSocket *sock;
+  GError *error = NULL;
+  gssize nread, nwrote;
+  gchar buf[128];
+
+  sock = g_socket_accept (data->server, NULL, &error);
+  g_assert_no_error (error);
+
+  while (TRUE)
+    {
+      nread = g_socket_receive (sock, buf, sizeof (buf), NULL, &error);
+      g_assert_no_error (error);
+      g_assert_cmpint (nread, >=, 0);
+
+      if (nread == 0)
+       break;
+
+      nwrote = g_socket_send (sock, buf, nread, NULL, &error);
+      g_assert_no_error (error);
+      g_assert_cmpint (nwrote, ==, nread);
+    }
+
+  g_socket_close (sock, &error);
+  g_assert_no_error (error);
+  return NULL;
+}
+
+static IPTestData *
+create_server (GSocketFamily family)
+{
+  IPTestData *data;
+  GSocket *server;
+  GError *error = NULL;
+  GSocketAddress *addr;
+  GInetAddress *iaddr;
+
+  data = g_slice_new (IPTestData);
+  data->family = family;
+
+  data->server = server = g_socket_new (family,
+                                       G_SOCKET_TYPE_STREAM,
+                                       G_SOCKET_PROTOCOL_DEFAULT,
+                                       &error);
+  g_assert_no_error (error);
+
+  g_assert_cmpint (g_socket_get_family (server), ==, family);
+  g_assert_cmpint (g_socket_get_socket_type (server), ==, G_SOCKET_TYPE_STREAM);
+  g_assert_cmpint (g_socket_get_protocol (server), ==, G_SOCKET_PROTOCOL_DEFAULT);
+
+  g_socket_set_blocking (server, TRUE);
+
+  iaddr = g_inet_address_new_loopback (family);
+  addr = g_inet_socket_address_new (iaddr, 0);
+  g_object_unref (iaddr);
+
+  g_assert_cmpint (g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr)), ==, 0);
+  g_socket_bind (server, addr, TRUE, &error);
+  g_assert_no_error (error);
+  g_object_unref (addr);
+
+  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_socket_listen (server, &error);
+  g_assert_no_error (error);
+
+  data->thread = g_thread_create (echo_server_thread, data, TRUE, &error);
+  g_assert_no_error (error);
+
+  return data;
+}
+
+static const gchar *testbuf = "0123456789abcdef";
+
+static gboolean
+test_ip_async_read_ready (GSocket      *client,
+                         GIOCondition  cond,
+                         gpointer      user_data)
+{
+  IPTestData *data = user_data;
+  GError *error = NULL;
+  gssize len;
+  gchar buf[128];
+
+  g_assert_cmpint (cond, ==, G_IO_IN);
+
+  len = g_socket_receive (client, buf, sizeof (buf), NULL, &error);
+  g_assert_no_error (error);
+  g_assert_cmpint (len, ==, strlen (testbuf) + 1);
+
+  g_assert_cmpstr (testbuf, ==, buf);
+
+  g_main_loop_quit (data->loop);
+
+  return FALSE;
+}
+
+static gboolean
+test_ip_async_write_ready (GSocket      *client,
+                          GIOCondition  cond,
+                          gpointer      user_data)
+{
+  IPTestData *data = user_data;
+  GError *error = NULL;
+  GSource *source;
+  gssize len;
+
+  g_assert_cmpint (cond, ==, G_IO_OUT);
+
+  len = g_socket_send (client, testbuf, strlen (testbuf) + 1, NULL, &error);
+  g_assert_no_error (error);
+  g_assert_cmpint (len, ==, strlen (testbuf) + 1);
+
+  source = g_socket_create_source (client, G_IO_IN, NULL);
+  g_source_set_callback (source, (GSourceFunc)test_ip_async_read_ready,
+                        data, NULL);
+  g_source_attach (source, NULL);
+  g_source_unref (source);
+
+  return FALSE;
+}
+
+static gboolean
+test_ip_async_timed_out (GSocket      *client,
+                        GIOCondition  cond,
+                        gpointer      user_data)
+{
+  IPTestData *data = user_data;
+  GError *error = NULL;
+  GSource *source;
+  gssize len;
+  gchar buf[128];
+
+  if (data->family == G_SOCKET_FAMILY_IPV4)
+    {
+      g_assert_cmpint (cond, ==, 0);
+      len = g_socket_receive (client, buf, sizeof (buf), NULL, &error);
+      g_assert_cmpint (len, ==, -1);
+      g_assert_error (error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT);
+      g_clear_error (&error);
+    }
+
+  source = g_socket_create_source (client, G_IO_OUT, NULL);
+  g_source_set_callback (source, (GSourceFunc)test_ip_async_write_ready,
+                        data, NULL);
+  g_source_attach (source, NULL);
+  g_source_unref (source);
+
+  return FALSE;
+}
+
+static gboolean
+test_ip_async_connected (GSocket      *client,
+                        GIOCondition  cond,
+                        gpointer      user_data)
+{
+  IPTestData *data = user_data;
+  GError *error = NULL;
+  GSource *source;
+  gssize len;
+  gchar buf[128];
+
+  g_socket_check_connect_result (client, &error);
+  g_assert_no_error (error);
+  /* We do this after the check_connect_result, since that will give a
+   * more useful assertion in case of error.
+   */
+  g_assert_cmpint (cond, ==, G_IO_OUT);
+
+  g_assert (g_socket_is_connected (client));
+
+  /* This adds 1 second to "make check", so let's just only do it once. */
+  if (data->family == G_SOCKET_FAMILY_IPV4)
+    {
+      len = g_socket_receive (client, buf, sizeof (buf), NULL, &error);
+      g_assert_cmpint (len, ==, -1);
+      g_assert_error (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK);
+      g_clear_error (&error);
+
+      source = g_socket_create_source (client, G_IO_IN, NULL);
+      g_source_set_callback (source, (GSourceFunc)test_ip_async_timed_out,
+                            data, NULL);
+      g_source_attach (source, NULL);
+      g_source_unref (source);
+    }
+  else
+    test_ip_async_timed_out (client, 0, data);
+
+  return FALSE;
+}
+
+static gboolean
+idle_test_ip_async_connected (gpointer user_data)
+{
+  IPTestData *data = user_data;
+
+  return test_ip_async_connected (data->client, G_IO_OUT, data);
+}
+
+static void
+test_ip_async (GSocketFamily family)
+{
+  IPTestData *data;
+  GError *error = NULL;
+  GSocket *client;
+  GSocketAddress *addr;
+  GSource *source;
+  gssize len;
+  gchar buf[128];
+
+  data = create_server (family);
+  addr = g_socket_get_local_address (data->server, &error);
+
+  client = g_socket_new (family,
+                        G_SOCKET_TYPE_STREAM,
+                        G_SOCKET_PROTOCOL_DEFAULT,
+                        &error);
+  g_assert_no_error (error);
+  data->client = client;
+
+  g_assert_cmpint (g_socket_get_family (client), ==, family);
+  g_assert_cmpint (g_socket_get_socket_type (client), ==, G_SOCKET_TYPE_STREAM);
+  g_assert_cmpint (g_socket_get_protocol (client), ==, G_SOCKET_PROTOCOL_DEFAULT);
+
+  g_socket_set_blocking (client, FALSE);
+  g_socket_set_timeout (client, 1);
+
+  if (g_socket_connect (client, addr, NULL, &error))
+    {
+      g_assert_no_error (error);
+      g_idle_add (idle_test_ip_async_connected, data);
+    }
+  else
+    {
+      g_assert_error (error, G_IO_ERROR, G_IO_ERROR_PENDING);
+      g_clear_error (&error);
+      source = g_socket_create_source (client, G_IO_OUT, NULL);
+      g_source_set_callback (source, (GSourceFunc)test_ip_async_connected,
+                            data, NULL);
+      g_source_attach (source, NULL);
+      g_source_unref (source);
+    }
+
+  data->loop = g_main_loop_new (NULL, TRUE);
+  g_main_loop_run (data->loop);
+  g_main_loop_unref (data->loop);
+
+  g_socket_shutdown (client, FALSE, TRUE, &error);
+  g_assert_no_error (error);
+
+  g_thread_join (data->thread);
+
+  len = g_socket_receive (client, buf, sizeof (buf), NULL, &error);
+  g_assert_no_error (error);
+  g_assert_cmpint (len, ==, 0);
+
+  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);
+}
+
+static void
+test_ipv4_async (void)
+{
+  test_ip_async (G_SOCKET_FAMILY_IPV4);
+}
+
+static void
+test_ipv6_async (void)
+{
+  test_ip_async (G_SOCKET_FAMILY_IPV6);
+}
+
+static void
+test_ip_sync (GSocketFamily family)
+{
+  IPTestData *data;
+  GError *error = NULL;
+  GSocket *client;
+  GSocketAddress *addr;
+  gssize len;
+  gchar buf[128];
+
+  data = create_server (family);
+  addr = g_socket_get_local_address (data->server, &error);
+
+  client = g_socket_new (family,
+                        G_SOCKET_TYPE_STREAM,
+                        G_SOCKET_PROTOCOL_DEFAULT,
+                        &error);
+  g_assert_no_error (error);
+
+  g_assert_cmpint (g_socket_get_family (client), ==, family);
+  g_assert_cmpint (g_socket_get_socket_type (client), ==, G_SOCKET_TYPE_STREAM);
+  g_assert_cmpint (g_socket_get_protocol (client), ==, G_SOCKET_PROTOCOL_DEFAULT);
+
+  g_socket_set_blocking (client, TRUE);
+  g_socket_set_timeout (client, 1);
+
+  g_socket_connect (client, addr, NULL, &error);
+  g_assert_no_error (error);
+  g_assert (g_socket_is_connected (client));
+
+  /* This adds 1 second to "make check", so let's just only do it once. */
+  if (family == G_SOCKET_FAMILY_IPV4)
+    {
+      len = g_socket_receive (client, buf, sizeof (buf), NULL, &error);
+      g_assert_cmpint (len, ==, -1);
+      g_assert_error (error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT);
+      g_clear_error (&error);
+    }
+
+  len = g_socket_send (client, testbuf, strlen (testbuf) + 1, NULL, &error);
+  g_assert_no_error (error);
+  g_assert_cmpint (len, ==, strlen (testbuf) + 1);
+  
+  len = g_socket_receive (client, buf, sizeof (buf), NULL, &error);
+  g_assert_no_error (error);
+  g_assert_cmpint (len, ==, strlen (testbuf) + 1);
+
+  g_assert_cmpstr (testbuf, ==, buf);
+
+  g_socket_shutdown (client, FALSE, TRUE, &error);
+  g_assert_no_error (error);
+
+  g_thread_join (data->thread);
+
+  len = g_socket_receive (client, buf, sizeof (buf), NULL, &error);
+  g_assert_no_error (error);
+  g_assert_cmpint (len, ==, 0);
+
+  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);
+}
+
+static void
+test_ipv4_sync (void)
+{
+  test_ip_sync (G_SOCKET_FAMILY_IPV4);
+}
+
+static void
+test_ipv6_sync (void)
+{
+  test_ip_sync (G_SOCKET_FAMILY_IPV6);
+}
+
 #ifdef G_OS_UNIX
 static void
 test_unix_from_fd (void)
@@ -180,6 +551,10 @@ main (int   argc,
   g_type_init ();
   g_test_init (&argc, &argv, NULL);
 
+  g_test_add_func ("/socket/ipv4_sync", test_ipv4_sync);
+  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_sync", test_ipv6_async);
 #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);