#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>
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 {
GMainContext *server_context;
gboolean loop_finished;
GSocket *server_socket;
+ GDatagramBased *server_transport;
GSource *server_source;
GTlsDatabase *database;
GDatagramBased *server_connection;
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;
}
/* 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
{
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);
/* 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);
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;
}
&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));
&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));
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);
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)
{
&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));
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);
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));
{
GError *error = NULL;
GSocket *socket;
+ GDatagramBased *transport;
start_server_service (test, threaded);
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
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));
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
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 */
FALSE, /* server_should_disappear */
TRUE, /* server_should_close */
G_TLS_AUTHENTICATION_NONE, /* auth_mode */
+ NULL, NULL, /* loss inducers */
};
const TestData nonblocking = {
0, /* server_timeout */
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 */
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;
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 ();