[glib-networking] tests: add test coverage for DTLS packet loss
- From: Michael Catanzaro <mcatanzaro src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib-networking] tests: add test coverage for DTLS packet loss
- Date: Thu, 3 Jun 2021 18:49:25 +0000 (UTC)
commit daffbaac9d5906d471864bc21aa6e2df6ae101a5
Author: Ole André Vadla Ravnås <oleavr gmail com>
Date: Thu May 27 09:56:06 2021 +0200
tests: add test coverage for DTLS packet loss
tls/tests/dtls-connection.c | 70 ++++++++++++++-
tls/tests/lossy-socket.c | 214 ++++++++++++++++++++++++++++++++++++++++++++
tls/tests/lossy-socket.h | 55 ++++++++++++
tls/tests/meson.build | 2 +-
4 files changed, 337 insertions(+), 4 deletions(-)
---
diff --git a/tls/tests/dtls-connection.c b/tls/tests/dtls-connection.c
index 999f3e3..4f3cd3c 100644
--- a/tls/tests/dtls-connection.c
+++ b/tls/tests/dtls-connection.c
@@ -27,6 +27,7 @@
#include "config.h"
+#include "lossy-socket.h"
#include "mock-interaction.h"
#include <gio/gio.h>
@@ -68,6 +69,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 +80,7 @@ typedef struct {
GMainContext *server_context;
gboolean loop_finished;
GSocket *server_socket;
+ GDatagramBased *server_transport;
GSource *server_source;
GTlsDatabase *database;
GDatagramBased *server_connection;
@@ -155,6 +159,8 @@ teardown_connection (TestConnection *test, gconstpointer data)
test->server_connection = NULL;
}
+ g_clear_object (&test->server_transport);
+
if (test->server_socket)
{
g_socket_close (test->server_socket, &error);
@@ -219,6 +225,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;
}
@@ -396,7 +412,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);
@@ -502,7 +518,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);
@@ -603,6 +619,7 @@ start_server_and_connect_to_it (TestConnection *test,
{
GError *error = NULL;
GSocket *socket;
+ GDatagramBased *transport;
start_server_service (test, threaded);
@@ -613,7 +630,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
@@ -745,6 +774,16 @@ test_connection_timeouts_read (TestConnection *test,
g_assert_error (test->read_error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT);
}
+static IODecision
+drop_first_outgoing (const IODetails *io,
+ gpointer user_data)
+{
+ if (io->direction == IO_OUT && io->serial == 1)
+ return IO_DROP;
+
+ return IO_KEEP;
+}
+
int
main (int argc,
char *argv[])
@@ -755,6 +794,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 */
@@ -762,6 +802,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 */
@@ -769,6 +810,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 */
@@ -776,6 +818,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;
@@ -826,6 +885,11 @@ main (int argc,
setup_connection, test_connection_timeouts_read,
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 ();
/* for valgrinding */
diff --git a/tls/tests/lossy-socket.c b/tls/tests/lossy-socket.c
new file mode 100644
index 0000000..7c20708
--- /dev/null
+++ b/tls/tests/lossy-socket.c
@@ -0,0 +1,214 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * Copyright (C) 2021 Ole André Vadla Ravnås <oleavr frida re>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * In addition, when the library is used with OpenSSL, a special
+ * exception applies. Refer to the LICENSE_EXCEPTION file for details.
+ */
+
+#include "config.h"
+
+#include "lossy-socket.h"
+
+struct _LossySocket
+{
+ GObject parent_instance;
+
+ GDatagramBased *base_socket;
+
+ IOPredicateFunc predicate_func;
+ gpointer predicate_data;
+
+ gint next_rx_serial;
+ gint next_tx_serial;
+};
+
+static void lossy_socket_datagram_based_iface_init (GDatagramBasedInterface *iface);
+
+G_DEFINE_TYPE_EXTENDED (LossySocket,
+ lossy_socket,
+ G_TYPE_OBJECT, 0,
+ G_IMPLEMENT_INTERFACE (G_TYPE_DATAGRAM_BASED,
+ lossy_socket_datagram_based_iface_init))
+
+static gint
+lossy_socket_receive_messages (GDatagramBased *datagram_based,
+ GInputMessage *messages,
+ guint num_messages,
+ gint flags,
+ gint64 timeout,
+ GCancellable *cancellable,
+ GError **error)
+{
+ LossySocket *self = LOSSY_SOCKET (datagram_based);
+ gint ret;
+ gboolean skip;
+
+ do
+ {
+ IODetails d;
+
+ skip = FALSE;
+
+ ret = g_datagram_based_receive_messages (self->base_socket, messages,
+ num_messages, flags, timeout,
+ cancellable, error);
+ if (ret <= 0)
+ break;
+
+ d.direction = IO_IN;
+ d.serial = self->next_rx_serial++;
+
+ if (self->predicate_func (&d, self->predicate_data) == IO_DROP)
+ {
+ messages->bytes_received = 0;
+ messages->flags = 0;
+
+ if (timeout == 0)
+ {
+ ret = -1;
+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK,
+ "Operation would block");
+ }
+ else
+ {
+ skip = TRUE;
+ }
+ }
+ }
+ while (skip);
+
+ return ret;
+}
+
+static gint
+lossy_socket_send_messages (GDatagramBased *datagram_based,
+ GOutputMessage *messages,
+ guint num_messages,
+ gint flags,
+ gint64 timeout,
+ GCancellable *cancellable,
+ GError **error)
+{
+ LossySocket *self = LOSSY_SOCKET (datagram_based);
+ IODetails d;
+
+ d.direction = IO_OUT;
+ d.serial = self->next_tx_serial++;
+
+ if (self->predicate_func (&d, self->predicate_data) == IO_DROP)
+ {
+ guint i, j;
+
+ for (i = 0; i < num_messages; i++)
+ {
+ GOutputMessage *m = &messages[i];
+
+ for (j = 0; j < m->num_vectors; j++)
+ m->bytes_sent += m->vectors[j].size;
+ }
+
+ return num_messages;
+ }
+
+ return g_datagram_based_send_messages (self->base_socket, messages,
+ num_messages, flags, timeout,
+ cancellable, error);
+}
+
+static GSource *
+lossy_socket_create_source (GDatagramBased *datagram_based,
+ GIOCondition condition,
+ GCancellable *cancellable)
+{
+ LossySocket *self = LOSSY_SOCKET (datagram_based);
+
+ return g_datagram_based_create_source (self->base_socket, condition,
+ cancellable);
+}
+
+static GIOCondition
+lossy_socket_condition_check (GDatagramBased *datagram_based,
+ GIOCondition condition)
+{
+ LossySocket *self = LOSSY_SOCKET (datagram_based);
+
+ return g_datagram_based_condition_check (self->base_socket, condition);
+}
+
+static gboolean
+lossy_socket_condition_wait (GDatagramBased *datagram_based,
+ GIOCondition condition,
+ gint64 timeout,
+ GCancellable *cancellable,
+ GError **error)
+{
+ LossySocket *self = LOSSY_SOCKET (datagram_based);
+
+ return g_datagram_based_condition_wait (self->base_socket, condition, timeout,
+ cancellable, error);
+}
+
+static void
+lossy_socket_init (LossySocket *self)
+{
+ self->next_rx_serial = 1;
+ self->next_tx_serial = 1;
+}
+
+static void
+lossy_socket_dispose (GObject *object)
+{
+ LossySocket *self = LOSSY_SOCKET (object);
+
+ g_clear_object (&self->base_socket);
+
+ G_OBJECT_CLASS (lossy_socket_parent_class)->dispose (object);
+}
+
+static void
+lossy_socket_class_init (LossySocketClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->dispose = lossy_socket_dispose;
+}
+
+static void
+lossy_socket_datagram_based_iface_init (GDatagramBasedInterface *iface)
+{
+ iface->receive_messages = lossy_socket_receive_messages;
+ iface->send_messages = lossy_socket_send_messages;
+ iface->create_source = lossy_socket_create_source;
+ iface->condition_check = lossy_socket_condition_check;
+ iface->condition_wait = lossy_socket_condition_wait;
+}
+
+GDatagramBased *
+lossy_socket_new (GDatagramBased *base_socket,
+ IOPredicateFunc predicate_func,
+ gpointer predicate_data)
+{
+ LossySocket *s;
+
+ s = g_object_new (LOSSY_TYPE_SOCKET, NULL);
+ s->base_socket = g_object_ref (base_socket);
+ s->predicate_func = predicate_func;
+ s->predicate_data = predicate_data;
+
+ return G_DATAGRAM_BASED (s);
+}
diff --git a/tls/tests/lossy-socket.h b/tls/tests/lossy-socket.h
new file mode 100644
index 0000000..1e74c2d
--- /dev/null
+++ b/tls/tests/lossy-socket.h
@@ -0,0 +1,55 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * Copyright (C) 2021 Ole André Vadla Ravnås <oleavr frida re>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#include <gio/gio.h>
+
+#pragma once
+
+G_BEGIN_DECLS
+
+typedef enum {
+ IO_KEEP,
+ IO_DROP
+} IODecision;
+
+typedef enum {
+ IO_IN,
+ IO_OUT
+} IODirection;
+
+typedef struct _IODetails IODetails;
+
+typedef IODecision (*IOPredicateFunc) (const IODetails *io,
+ gpointer user_data);
+
+struct _IODetails
+{
+ IODirection direction;
+ guint serial;
+};
+
+#define LOSSY_TYPE_SOCKET (lossy_socket_get_type ())
+
+G_DECLARE_FINAL_TYPE (LossySocket, lossy_socket, LOSSY, SOCKET, GObject)
+
+GDatagramBased *lossy_socket_new (GDatagramBased *base_socket,
+ IOPredicateFunc predicate_func,
+ gpointer predicate_data);
+
+G_END_DECLS
diff --git a/tls/tests/meson.build b/tls/tests/meson.build
index 6f2af7e..b7c9cd1 100644
--- a/tls/tests/meson.build
+++ b/tls/tests/meson.build
@@ -46,7 +46,7 @@ test_programs = [
['file-database', [], deps, [], []],
['connection', ['mock-interaction.c'], deps, [], [mock_pkcs11_module]],
# DTLS tests are disabled until we fix https://gitlab.gnome.org/GNOME/glib-networking/issues/49
-# ['dtls-connection', ['mock-interaction.c'], deps, [], [mock_pkcs11_module]],
+# ['dtls-connection', ['mock-interaction.c', 'lossy-socket.c'], deps, [], [mock_pkcs11_module]],
]
foreach backend: backends
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]