Imported Upstream version 2.72.alpha
[platform/upstream/glib-networking.git] / tls / tests / dtls-connection.c
index 1304d96..78b2cee 100644 (file)
 
 #include "config.h"
 
+#include "lossy-socket.h"
 #include "mock-interaction.h"
 
 #include <gio/gio.h>
+#ifdef BACKEND_IS_GNUTLS
 #include <gnutls/gnutls.h>
+#endif
 
 #include <sys/types.h>
 #include <string.h>
@@ -68,6 +71,8 @@ typedef struct {
   gboolean server_should_disappear;  /* whether the server should stop responding before sending a message */
   gboolean server_should_close;  /* whether the server should close gracefully once it’s sent a message */
   GTlsAuthenticationMode auth_mode;
+  IOPredicateFunc client_loss_inducer;
+  IOPredicateFunc server_loss_inducer;
 } TestData;
 
 typedef struct {
@@ -77,6 +82,7 @@ typedef struct {
   GMainContext *server_context;
   gboolean loop_finished;
   GSocket *server_socket;
+  GDatagramBased *server_transport;
   GSource *server_source;
   GTlsDatabase *database;
   GDatagramBased *server_connection;
@@ -89,9 +95,7 @@ typedef struct {
   gboolean expect_server_error;
   GError *server_error;
   gboolean server_running;
-#if GLIB_CHECK_VERSION(2, 60, 0)
   const gchar * const *server_protocols;
-#endif
 
   char buf[128];
   gssize nread, nwrote;
@@ -107,18 +111,33 @@ setup_connection (TestConnection *test, gconstpointer data)
 }
 
 /* Waits about 10 seconds for @var to be NULL/FALSE */
-#define WAIT_UNTIL_UNSET(var)                             \
-  if (var)                                                \
-    {                                                     \
-      int i;                                              \
-                                                          \
-      for (i = 0; i < 13 && (var); i++)                   \
-        {                                                 \
-          g_usleep (1000 * (1 << i));                     \
-          g_main_context_iteration (NULL, FALSE);         \
-        }                                                 \
-                                                          \
-      g_assert (!(var));                                  \
+#define WAIT_UNTIL_UNSET(var)                                     \
+  if (var)                                                        \
+    {                                                             \
+      int i;                                                      \
+                                                                  \
+      for (i = 0; i < 13 && (var); i++)                           \
+        {                                                         \
+          g_usleep (1000 * (1 << i));                             \
+          g_main_context_iteration (test->client_context, FALSE); \
+        }                                                         \
+                                                                  \
+      g_assert_true (!(var));                                     \
+    }
+
+/* Waits about 10 seconds for @var's ref_count to drop to 1 */
+#define WAIT_UNTIL_UNREFFED(var)                                  \
+  if (var)                                                        \
+    {                                                             \
+      int i;                                                      \
+                                                                  \
+      for (i = 0; i < 13 && G_OBJECT (var)->ref_count > 1; i++)   \
+        {                                                         \
+          g_usleep (1000 * (1 << i));                             \
+          g_main_context_iteration (test->client_context, FALSE); \
+        }                                                         \
+                                                                  \
+      g_assert_cmpuint (G_OBJECT (var)->ref_count, ==, 1);        \
     }
 
 static void
@@ -137,12 +156,13 @@ teardown_connection (TestConnection *test, gconstpointer data)
     {
       WAIT_UNTIL_UNSET (test->server_running);
 
-      g_object_add_weak_pointer (G_OBJECT (test->server_connection),
-                                 (gpointer *)&test->server_connection);
+      WAIT_UNTIL_UNREFFED (test->server_connection);
       g_object_unref (test->server_connection);
-      WAIT_UNTIL_UNSET (test->server_connection);
+      test->server_connection = NULL;
     }
 
+  g_clear_object (&test->server_transport);
+
   if (test->server_socket)
     {
       g_socket_close (test->server_socket, &error);
@@ -151,25 +171,23 @@ teardown_connection (TestConnection *test, gconstpointer data)
       /* The outstanding accept_async will hold a ref on test->server_socket,
        * which we want to wait for it to release if we're valgrinding.
        */
-      g_object_add_weak_pointer (G_OBJECT (test->server_socket), (gpointer *)&test->server_socket);
+      WAIT_UNTIL_UNREFFED (test->server_socket);
       g_object_unref (test->server_socket);
-      WAIT_UNTIL_UNSET (test->server_socket);
+      test->server_socket = NULL;
     }
 
   if (test->client_connection)
     {
-      g_object_add_weak_pointer (G_OBJECT (test->client_connection),
-                                 (gpointer *)&test->client_connection);
+      WAIT_UNTIL_UNREFFED (test->client_connection);
       g_object_unref (test->client_connection);
-      WAIT_UNTIL_UNSET (test->client_connection);
+      test->client_connection = NULL;
     }
 
   if (test->database)
     {
-      g_object_add_weak_pointer (G_OBJECT (test->database),
-                                 (gpointer *)&test->database);
+      WAIT_UNTIL_UNREFFED (test->database);
       g_object_unref (test->database);
-      WAIT_UNTIL_UNSET (test->database);
+      test->database = NULL;
     }
 
   g_clear_object (&test->address);
@@ -209,6 +227,16 @@ start_server (TestConnection *test)
                                           g_inet_socket_address_get_port (iaddr));
 
   test->server_socket = socket;
+  if (test->test_data->server_loss_inducer)
+    {
+      test->server_transport = lossy_socket_new (G_DATAGRAM_BASED (socket),
+                                                 test->test_data->server_loss_inducer,
+                                                 test);
+    }
+  else
+    {
+      test->server_transport = G_DATAGRAM_BASED (g_object_ref (socket));
+    }
   test->server_running = TRUE;
 }
 
@@ -247,7 +275,7 @@ on_rehandshake_finish (GObject        *object,
                                                &message, 1,
                                                G_SOCKET_MSG_NONE, 0, NULL,
                                                &test->server_error);
-      g_main_context_iteration (NULL, FALSE);
+      g_main_context_iteration (test->server_context, FALSE);
     }
   while (g_error_matches (test->server_error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK));
 
@@ -294,7 +322,7 @@ on_rehandshake_finish_threaded (GObject      *object,
                                                &message, 1,
                                                G_SOCKET_MSG_NONE, 0, NULL,
                                                &test->server_error);
-      g_main_context_iteration (NULL, FALSE);
+      g_main_context_iteration (test->server_context, FALSE);
     }
   while (g_error_matches (test->server_error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK));
 
@@ -386,7 +414,7 @@ on_incoming_connection (GSocket       *socket,
   cert = g_tls_certificate_new_from_file (tls_test_file_path ("server-and-key.pem"), &error);
   g_assert_no_error (error);
 
-  test->server_connection = g_dtls_server_connection_new (G_DATAGRAM_BASED (socket),
+  test->server_connection = g_dtls_server_connection_new (test->server_transport,
                                                           cert, &error);
   g_debug ("%s: Server connection %p on socket %p", G_STRFUNC, test->server_connection, socket);
   g_assert_no_error (error);
@@ -400,13 +428,11 @@ on_incoming_connection (GSocket       *socket,
   if (test->database)
     g_dtls_connection_set_database (G_DTLS_CONNECTION (test->server_connection), test->database);
 
-#if GLIB_CHECK_VERSION(2, 60, 0)
   if (test->server_protocols)
     {
       g_dtls_connection_set_advertised_protocols (G_DTLS_CONNECTION (test->server_connection),
                                                   test->server_protocols);
     }
-#endif
 
   if (test->test_data->server_should_disappear)
     {
@@ -421,7 +447,7 @@ on_incoming_connection (GSocket       *socket,
                                                &message, 1,
                                                G_SOCKET_MSG_NONE, 0, NULL,
                                                &test->server_error);
-      g_main_context_iteration (NULL, FALSE);
+      g_main_context_iteration (test->server_context, FALSE);
     }
   while (g_error_matches (test->server_error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK));
 
@@ -494,7 +520,7 @@ on_incoming_connection_threaded (GSocket      *socket,
   cert = g_tls_certificate_new_from_file (tls_test_file_path ("server-and-key.pem"), &error);
   g_assert_no_error (error);
 
-  test->server_connection = g_dtls_server_connection_new (G_DATAGRAM_BASED (socket),
+  test->server_connection = g_dtls_server_connection_new (test->server_transport,
                                                           cert, &error);
   g_debug ("%s: Server connection %p on socket %p", G_STRFUNC, test->server_connection, socket);
   g_assert_no_error (error);
@@ -522,7 +548,7 @@ on_incoming_connection_threaded (GSocket      *socket,
                                                G_SOCKET_MSG_NONE,
                                                test->test_data->server_timeout, NULL,
                                                &test->server_error);
-      g_main_context_iteration (NULL, FALSE);
+      g_main_context_iteration (test->server_context, FALSE);
     }
   while (g_error_matches (test->server_error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK));
 
@@ -595,6 +621,7 @@ start_server_and_connect_to_it (TestConnection         *test,
 {
   GError *error = NULL;
   GSocket *socket;
+  GDatagramBased *transport;
 
   start_server_service (test, threaded);
 
@@ -605,7 +632,19 @@ start_server_and_connect_to_it (TestConnection         *test,
   g_socket_connect (socket, test->address, NULL, &error);
   g_assert_no_error (error);
 
-  return G_DATAGRAM_BASED (socket);
+  if (test->test_data->client_loss_inducer)
+    {
+      transport = lossy_socket_new (G_DATAGRAM_BASED (socket),
+                                    test->test_data->client_loss_inducer,
+                                    test);
+      g_object_unref (socket);
+    }
+  else
+    {
+      transport = G_DATAGRAM_BASED (socket);
+    }
+
+  return transport;
 }
 
 static void
@@ -629,7 +668,7 @@ read_test_data_async (TestConnection *test)
                                                   G_SOCKET_MSG_NONE,
                                                   test->test_data->client_timeout,
                                                   NULL, &test->read_error);
-      g_main_context_iteration (NULL, FALSE);
+      g_main_context_iteration (test->client_context, FALSE);
     }
   while (g_error_matches (test->read_error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK));
 
@@ -737,81 +776,14 @@ test_connection_timeouts_read (TestConnection *test,
   g_assert_error (test->read_error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT);
 }
 
-static void
-test_alpn (TestConnection *test,
-           const char * const *client_protocols,
-           const char * const *server_protocols,
-           const char *negotiated_protocol)
-{
-#if GLIB_CHECK_VERSION(2, 60, 0)
-  GDatagramBased *connection;
-  GError *error = NULL;
-
-  test->server_protocols = server_protocols;
-
-  test->database = g_tls_file_database_new (tls_test_file_path ("ca-roots.pem"), &error);
-  g_assert_no_error (error);
-  g_assert (test->database);
-
-  connection = start_server_and_connect_to_it (test, FALSE);
-  test->client_connection = g_dtls_client_connection_new (connection, test->identity, &error);
-  g_assert_no_error (error);
-  g_object_unref (connection);
-
-  if (client_protocols)
-    {
-      g_dtls_connection_set_advertised_protocols (G_DTLS_CONNECTION (test->client_connection),
-             client_protocols);
-    }
-
-  g_tls_connection_set_database (G_TLS_CONNECTION (test->client_connection), test->database);
-
-  read_test_data_async (test);
-  while (!test->loop_finished)
-    g_main_context_iteration (test->client_context, TRUE);
-
-  g_assert_no_error (test->server_error);
-  g_assert_no_error (test->read_error);
-
-  g_assert_cmpstr (g_dtls_connection_get_negotiated_protocol (G_DTLS_CONNECTION (test->server_connection)), ==, negotiated_protocol);
-  g_assert_cmpstr (g_dtls_connection_get_negotiated_protocol (G_DTLS_CONNECTION (test->client_connection)), ==, negotiated_protocol);
-#else
-  g_test_skip ("no support for ALPN in this GLib version");
-#endif
-}
-
-static void
-test_alpn_match (TestConnection *test, gconstpointer data)
-{
-  const char * const client_protocols[] = { "one", "two", "three", NULL };
-  const char * const server_protocols[] = { "four", "seven", "nine", "two", NULL };
-
-  test_alpn (test, client_protocols, server_protocols, "two");
-}
-
-static void
-test_alpn_no_match (TestConnection *test, gconstpointer data)
-{
-  const char * const client_protocols[] = { "one", "two", "three", NULL };
-  const char * const server_protocols[] = { "four", "seven", "nine", NULL };
-
-  test_alpn (test, client_protocols, server_protocols, NULL);
-}
-
-static void
-test_alpn_client_only (TestConnection *test, gconstpointer data)
-{
-  const char * const client_protocols[] = { "one", "two", "three", NULL };
-
-  test_alpn (test, client_protocols, NULL, NULL);
-}
-
-static void
-test_alpn_server_only (TestConnection *test, gconstpointer data)
+static IODecision
+drop_first_outgoing (const IODetails *io,
+                     gpointer         user_data)
 {
-  const char * const server_protocols[] = { "four", "seven", "nine", "two", NULL };
+  if (io->direction == IO_OUT && io->serial == 1)
+    return IO_DROP;
 
-  test_alpn (test, NULL, server_protocols, NULL);
+  return IO_KEEP;
 }
 
 int
@@ -824,6 +796,7 @@ main (int   argc,
     FALSE,  /* server_should_disappear */
     TRUE, /* server_should_close */
     G_TLS_AUTHENTICATION_NONE,  /* auth_mode */
+    NULL, NULL, /* loss inducers */
   };
   const TestData server_timeout = {
     1000 * G_USEC_PER_SEC,  /* server_timeout */
@@ -831,6 +804,7 @@ main (int   argc,
     FALSE,  /* server_should_disappear */
     TRUE, /* server_should_close */
     G_TLS_AUTHENTICATION_NONE,  /* auth_mode */
+    NULL, NULL, /* loss inducers */
   };
   const TestData nonblocking = {
     0,  /* server_timeout */
@@ -838,6 +812,7 @@ main (int   argc,
     FALSE,  /* server_should_disappear */
     TRUE, /* server_should_close */
     G_TLS_AUTHENTICATION_NONE,  /* auth_mode */
+    NULL, NULL, /* loss inducers */
   };
   const TestData client_timeout = {
     0,  /* server_timeout */
@@ -845,6 +820,23 @@ main (int   argc,
     TRUE,  /* server_should_disappear */
     TRUE, /* server_should_close */
     G_TLS_AUTHENTICATION_NONE,  /* auth_mode */
+    NULL, NULL, /* loss inducers */
+  };
+  const TestData client_loss = {
+    -1,  /* server_timeout */
+    0,  /* client_timeout */
+    FALSE,  /* server_should_disappear */
+    TRUE, /* server_should_close */
+    G_TLS_AUTHENTICATION_NONE,  /* auth_mode */
+    drop_first_outgoing, NULL, /* loss inducers */
+  };
+  const TestData server_loss = {
+    -1,  /* server_timeout */
+    0,  /* client_timeout */
+    FALSE,  /* server_should_disappear */
+    TRUE, /* server_should_close */
+    G_TLS_AUTHENTICATION_NONE,  /* auth_mode */
+    NULL, drop_first_outgoing, /* loss inducers */
   };
   int ret;
   int i;
@@ -872,41 +864,33 @@ main (int   argc,
 
   g_setenv ("GSETTINGS_BACKEND", "memory", TRUE);
   g_setenv ("GIO_USE_TLS", BACKEND, TRUE);
-  g_assert (g_ascii_strcasecmp (G_OBJECT_TYPE_NAME (g_tls_backend_get_default ()), "GTlsBackend" BACKEND) == 0);
+  g_assert_cmpint (g_ascii_strcasecmp (G_OBJECT_TYPE_NAME (g_tls_backend_get_default ()), "GTlsBackend" BACKEND), ==, 0);
 
-  g_test_add ("/dtls/connection/basic/blocking", TestConnection, &blocking,
+  g_test_add ("/dtls/" BACKEND "/connection/basic/blocking", TestConnection, &blocking,
               setup_connection, test_basic_connection, teardown_connection);
-  g_test_add ("/dtls/connection/basic/timeout", TestConnection, &server_timeout,
+  g_test_add ("/dtls/" BACKEND "/connection/basic/timeout", TestConnection, &server_timeout,
               setup_connection, test_basic_connection, teardown_connection);
-  g_test_add ("/dtls/connection/basic/nonblocking",
+  g_test_add ("/dtls/" BACKEND "/connection/basic/nonblocking",
               TestConnection, &nonblocking,
               setup_connection, test_basic_connection, teardown_connection);
 
-  g_test_add ("/dtls/connection/threaded/blocking", TestConnection, &blocking,
+  g_test_add ("/dtls/" BACKEND "/connection/threaded/blocking", TestConnection, &blocking,
               setup_connection, test_threaded_connection, teardown_connection);
-  g_test_add ("/dtls/connection/threaded/timeout",
+  g_test_add ("/dtls/" BACKEND "/connection/threaded/timeout",
               TestConnection, &server_timeout,
               setup_connection, test_threaded_connection, teardown_connection);
-  g_test_add ("/dtls/connection/threaded/nonblocking",
+  g_test_add ("/dtls/" BACKEND "/connection/threaded/nonblocking",
               TestConnection, &nonblocking,
               setup_connection, test_threaded_connection, teardown_connection);
 
-  g_test_add ("/dtls/connection/timeouts/read", TestConnection, &client_timeout,
+  g_test_add ("/dtls/" BACKEND "/connection/timeouts/read", TestConnection, &client_timeout,
               setup_connection, test_connection_timeouts_read,
               teardown_connection);
 
-  g_test_add ("/dtls/connection/alpn/match", TestConnection, &blocking,
-              setup_connection, test_alpn_match,
-              teardown_connection);
-  g_test_add ("/dtls/connection/alpn/no-match", TestConnection, &blocking,
-              setup_connection, test_alpn_no_match,
-              teardown_connection);
-  g_test_add ("/dtls/connection/alpn/client-only", TestConnection, &blocking,
-              setup_connection, test_alpn_client_only,
-              teardown_connection);
-  g_test_add ("/dtls/connection/alpn/server-only", TestConnection, &blocking,
-              setup_connection, test_alpn_server_only,
-              teardown_connection);
+  g_test_add ("/dtls/" BACKEND "/connection/lossy/client", TestConnection, &client_loss,
+              setup_connection, test_basic_connection, teardown_connection);
+  g_test_add ("/dtls/" BACKEND "/connection/lossy/server", TestConnection, &server_loss,
+              setup_connection, test_basic_connection, teardown_connection);
 
   ret = g_test_run ();