[Spice-commits] 7 commits - configure.ac server/reds.c server/tests

Christophe Fergau teuf at kemper.freedesktop.org
Tue Mar 13 10:45:30 UTC 2018


 configure.ac                    |    7 
 server/reds.c                   |   34 ++-
 server/tests/Makefile.am        |    5 
 server/tests/basic-event-loop.c |    2 
 server/tests/test-listen.c      |  370 ++++++++++++++++++++++++++++++++++++++++
 5 files changed, 401 insertions(+), 17 deletions(-)

New commits:
commit f4dd0f1aa75597dc1442e05d98b1bc2a532671eb
Author: Christophe Fergeau <cfergeau at redhat.com>
Date:   Wed Feb 28 17:24:11 2018 +0100

    test-listen: Add Unix socket test
    
    Signed-off-by: Christophe Fergeau <cfergeau at redhat.com>

diff --git a/configure.ac b/configure.ac
index bcd4bb4d..86383434 100644
--- a/configure.ac
+++ b/configure.ac
@@ -171,6 +171,9 @@ AS_VAR_APPEND([SPICE_REQUIRES], [" glib-2.0 >= $GLIB2_REQUIRED gio-2.0 >= $GLIB2
 PKG_CHECK_MODULES([GOBJECT2], [gobject-2.0 >= $GLIB2_REQUIRED])
 AS_VAR_APPEND([SPICE_REQUIRES], [" gobject-2.0 >= $GLIB2_REQUIRED"])
 
+#used only by tests
+PKG_CHECK_MODULES([GIO_UNIX], [gio-unix-2.0 >= $GLIB2_REQUIRED])
+
 PIXMAN_REQUIRED=0.17.7
 PKG_CHECK_MODULES(PIXMAN, pixman-1 >= $PIXMAN_REQUIRED)
 AC_SUBST(PIXMAN_CFLAGS)
diff --git a/server/tests/Makefile.am b/server/tests/Makefile.am
index 0aae1fd6..ffeb8fc0 100644
--- a/server/tests/Makefile.am
+++ b/server/tests/Makefile.am
@@ -16,8 +16,9 @@ AM_CPPFLAGS =					\
 	-I$(top_builddir)/server		\
 	-I$(top_srcdir)/server/tests		\
 	$(COMMON_CFLAGS)			\
+	$(GIO_UNIX_CFLAGS)			\
 	$(GLIB2_CFLAGS)				\
-	$(GOBJECT2_CFLAGS)				\
+	$(GOBJECT2_CFLAGS)			\
 	$(SMARTCARD_CFLAGS)			\
 	$(SPICE_NONPKGCONFIG_CFLAGS)		\
 	$(SPICE_PROTOCOL_CFLAGS)		\
@@ -39,6 +40,7 @@ LDADD =								\
 	libtest.a						\
 	$(top_builddir)/spice-common/common/libspice-common.la	\
 	$(top_builddir)/server/libserver.la			\
+	$(GIO_UNIX_LIBS)					\
 	$(GLIB2_LIBS)						\
 	$(GOBJECT2_LIBS)					\
 	$(SPICE_NONPKGCONFIG_LIBS)		                \
diff --git a/server/tests/test-listen.c b/server/tests/test-listen.c
index 3d09bb6e..531bd1bd 100644
--- a/server/tests/test-listen.c
+++ b/server/tests/test-listen.c
@@ -27,6 +27,7 @@
 #include <stdint.h>
 #include <string.h>
 #include <gio/gio.h>
+#include <gio/gunixsocketaddress.h>
 
 /* Arbitrary base port, we want a port which is not in use by the system, and
  * by another of our tests (in case of parallel runs)
@@ -207,9 +208,13 @@ static GThread *fake_client_new(GThreadFunc thread_func,
 {
     ThreadData *thread_data = g_new0(ThreadData, 1);
 
-    g_assert_cmpuint(port, >, 0);
-    g_assert_cmpuint(port, <, 65536);
-    thread_data->connectable = g_network_address_new(hostname, port);
+    if (port == -1) {
+        thread_data->connectable = G_SOCKET_CONNECTABLE(g_unix_socket_address_new(hostname));
+    } else {
+        g_assert_cmpuint(port, >, 0);
+        g_assert_cmpuint(port, <, 65536);
+        thread_data->connectable = g_network_address_new(hostname, port);
+    }
     thread_data->use_tls = use_tls;
     thread_data->event_loop = event_loop;
 
@@ -310,6 +315,32 @@ static void test_connect_plain_and_tls(void)
     spice_server_destroy(server);
 }
 
+static void test_connect_unix(void)
+{
+    GThread *thread;
+    int result;
+
+    TestEventLoop event_loop = { 0, };
+
+    test_event_loop_init(&event_loop);
+
+    /* server */
+    SpiceServer *server = spice_server_new();
+    spice_server_set_name(server, "SPICE listen test");
+    spice_server_set_noauth(server);
+    spice_server_set_addr(server, "test-listen.unix", SPICE_ADDR_FLAG_UNIX_ONLY);
+    result = spice_server_init(server, event_loop.core);
+    g_assert_cmpint(result, ==, 0);
+
+    /* fake client */
+    thread = fake_client_new(check_magic_thread, "test-listen.unix", -1, false, &event_loop);
+    test_event_loop_run(&event_loop);
+    g_assert_null(g_thread_join(thread));
+
+    test_event_loop_destroy(&event_loop);
+    spice_server_destroy(server);
+}
+
 static void test_connect_ko(void)
 {
     GThread *thread;
@@ -332,6 +363,7 @@ int main(int argc, char **argv)
     g_test_add_func("/server/listen/connect_plain", test_connect_plain);
     g_test_add_func("/server/listen/connect_tls", test_connect_tls);
     g_test_add_func("/server/listen/connect_both", test_connect_plain_and_tls);
+    g_test_add_func("/server/listen/connect_unix", test_connect_unix);
     g_test_add_func("/server/listen/connect_ko", test_connect_ko);
 
     return g_test_run();
commit 0308530d5e3b37ed81264c3def33cbbd13af38bd
Author: Christophe Fergeau <cfergeau at redhat.com>
Date:   Wed Feb 28 11:31:29 2018 +0100

    test-listen: Add TLS test
    
    Signed-off-by: Christophe Fergeau <cfergeau at redhat.com>

diff --git a/server/tests/test-listen.c b/server/tests/test-listen.c
index a072c59a..3d09bb6e 100644
--- a/server/tests/test-listen.c
+++ b/server/tests/test-listen.c
@@ -33,6 +33,8 @@
  */
 #define BASE_PORT 5728
 
+#define PKI_DIR SPICE_TOP_SRCDIR "/server/tests/pki/"
+
 static bool error_is_set(GError **error)
 {
     return ((error != NULL) && (*error != NULL));
@@ -99,6 +101,28 @@ static GIOStream *fake_client_connect(GSocketConnectable *connectable, GError **
     return G_IO_STREAM(connection);
 }
 
+static GIOStream *fake_client_connect_tls(GSocketConnectable *connectable, GError **error)
+{
+    GSocketClient *client;
+    GSocketConnection *connection;
+    GIOStream *tls_connection;
+
+    client = g_socket_client_new();
+    connection = g_socket_client_connect(client, connectable, NULL, error);
+    g_assert_no_error(*error);
+    tls_connection = g_tls_client_connection_new(G_IO_STREAM(connection),
+                                                 connectable,
+                                                 error);
+    g_assert_no_error(*error);
+    /* Disable all certificate checks as our test setup is known to be invalid */
+    g_tls_client_connection_set_validation_flags(G_TLS_CLIENT_CONNECTION(tls_connection), 0);
+
+    g_object_unref(connection);
+    g_object_unref(client);
+
+    return tls_connection;
+}
+
 static void check_magic(GIOStream *io_stream, GError **error)
 {
     uint8_t buffer[4];
@@ -127,6 +151,7 @@ static void check_magic(GIOStream *io_stream, GError **error)
 typedef struct
 {
     GSocketConnectable *connectable;
+    bool use_tls;
     TestEventLoop *event_loop;
 } ThreadData;
 
@@ -137,7 +162,11 @@ static gpointer check_magic_thread(gpointer data)
     GSocketConnectable *connectable = G_SOCKET_CONNECTABLE(thread_data->connectable);
     GIOStream *stream;
 
-    stream = fake_client_connect(connectable, &error);
+    if (thread_data->use_tls) {
+        stream = fake_client_connect_tls(connectable, &error);
+    } else {
+        stream = fake_client_connect(connectable, &error);
+    }
     g_assert_no_error(error);
     check_magic(stream, &error);
     g_assert_no_error(error);
@@ -173,6 +202,7 @@ static gpointer check_no_connect_thread(gpointer data)
 
 static GThread *fake_client_new(GThreadFunc thread_func,
                                 const char *hostname, int port,
+                                bool use_tls,
                                 TestEventLoop *event_loop)
 {
     ThreadData *thread_data = g_new0(ThreadData, 1);
@@ -180,6 +210,7 @@ static GThread *fake_client_new(GThreadFunc thread_func,
     g_assert_cmpuint(port, >, 0);
     g_assert_cmpuint(port, <, 65536);
     thread_data->connectable = g_network_address_new(hostname, port);
+    thread_data->use_tls = use_tls;
     thread_data->event_loop = event_loop;
 
     /* check_magic_thread will assume ownership of 'connectable' */
@@ -204,7 +235,74 @@ static void test_connect_plain(void)
     g_assert_cmpint(result, ==, 0);
 
     /* fake client */
-    thread = fake_client_new(check_magic_thread, "localhost", BASE_PORT, &event_loop);
+    thread = fake_client_new(check_magic_thread, "localhost", BASE_PORT, false, &event_loop);
+    test_event_loop_run(&event_loop);
+    g_assert_null(g_thread_join(thread));
+
+    test_event_loop_destroy(&event_loop);
+    spice_server_destroy(server);
+}
+
+static void test_connect_tls(void)
+{
+    GThread *thread;
+    int result;
+
+    TestEventLoop event_loop = { 0, };
+
+    test_event_loop_init(&event_loop);
+
+    /* server */
+    SpiceServer *server = spice_server_new();
+    spice_server_set_name(server, "SPICE listen test");
+    spice_server_set_noauth(server);
+    result = spice_server_set_tls(server, BASE_PORT,
+                                  PKI_DIR "ca-cert.pem",
+                                  PKI_DIR "server-cert.pem",
+                                  PKI_DIR "server-key.pem",
+                                  NULL, NULL, NULL);
+    g_assert_cmpint(result, ==, 0);
+    result = spice_server_init(server, event_loop.core);
+    g_assert_cmpint(result, ==, 0);
+
+    /* fake client */
+    thread = fake_client_new(check_magic_thread, "localhost", BASE_PORT, true, &event_loop);
+    test_event_loop_run(&event_loop);
+    g_assert_null(g_thread_join(thread));
+
+    test_event_loop_destroy(&event_loop);
+    spice_server_destroy(server);
+}
+
+static void test_connect_plain_and_tls(void)
+{
+    GThread *thread;
+    int result;
+
+    TestEventLoop event_loop = { 0, };
+
+    test_event_loop_init(&event_loop);
+
+    /* server */
+    SpiceServer *server = spice_server_new();
+    spice_server_set_name(server, "SPICE listen test");
+    spice_server_set_noauth(server);
+    spice_server_set_port(server, BASE_PORT);
+    result = spice_server_set_tls(server, BASE_PORT+1,
+                                  PKI_DIR "ca-cert.pem",
+                                  PKI_DIR "server-cert.pem",
+                                  PKI_DIR "server-key.pem",
+                                  NULL, NULL, NULL);
+    g_assert_cmpint(result, ==, 0);
+    result = spice_server_init(server, event_loop.core);
+    g_assert_cmpint(result, ==, 0);
+
+    /* fake client */
+    thread = fake_client_new(check_magic_thread, "localhost", BASE_PORT, false, &event_loop);
+    test_event_loop_run(&event_loop);
+    g_assert_null(g_thread_join(thread));
+
+    thread = fake_client_new(check_magic_thread, "localhost", BASE_PORT+1, true, &event_loop);
     test_event_loop_run(&event_loop);
     g_assert_null(g_thread_join(thread));
 
@@ -220,7 +318,7 @@ static void test_connect_ko(void)
     test_event_loop_init(&event_loop);
 
     /* fake client */
-    thread = fake_client_new(check_no_connect_thread, "localhost", BASE_PORT, &event_loop);
+    thread = fake_client_new(check_no_connect_thread, "localhost", BASE_PORT, false, &event_loop);
     test_event_loop_run(&event_loop);
     g_assert_null(g_thread_join(thread));
 
@@ -232,6 +330,8 @@ int main(int argc, char **argv)
     g_test_init(&argc, &argv, NULL);
 
     g_test_add_func("/server/listen/connect_plain", test_connect_plain);
+    g_test_add_func("/server/listen/connect_tls", test_connect_tls);
+    g_test_add_func("/server/listen/connect_both", test_connect_plain_and_tls);
     g_test_add_func("/server/listen/connect_ko", test_connect_ko);
 
     return g_test_run();
commit d1d43223af55efcb25af05479363e316788e2664
Author: Christophe Fergeau <cfergeau at redhat.com>
Date:   Wed Feb 28 11:29:24 2018 +0100

    test-listen: Add event loop helpers
    
    These factor a bit of common code, and more importantly, help with
    freeing all event loop related data at the end of each test.
    
    Signed-off-by: Christophe Fergeau <cfergeau at redhat.com>

diff --git a/server/tests/test-listen.c b/server/tests/test-listen.c
index ab8bceab..a072c59a 100644
--- a/server/tests/test-listen.c
+++ b/server/tests/test-listen.c
@@ -33,13 +33,59 @@
  */
 #define BASE_PORT 5728
 
-static SpiceCoreInterface *core;
-
 static bool error_is_set(GError **error)
 {
     return ((error != NULL) && (*error != NULL));
 }
 
+typedef struct {
+    SpiceCoreInterface *core;
+    SpiceTimer *exit_mainloop_timer;
+    SpiceTimer *timeout_timer;
+} TestEventLoop;
+
+static void timeout_cb(SPICE_GNUC_UNUSED void *opaque)
+{
+    g_assert_not_reached();
+}
+
+static void exit_mainloop_cb(SPICE_GNUC_UNUSED void *opaque)
+{
+    basic_event_loop_quit();
+}
+
+static void test_event_loop_quit(TestEventLoop *event_loop)
+{
+    event_loop->core->timer_start(event_loop->exit_mainloop_timer, 0);
+}
+
+static void test_event_loop_init(TestEventLoop *event_loop)
+{
+    event_loop->core = basic_event_loop_init();
+    event_loop->timeout_timer = event_loop->core->timer_add(timeout_cb, NULL);
+    event_loop->exit_mainloop_timer = event_loop->core->timer_add(exit_mainloop_cb, NULL);
+}
+
+static void test_event_loop_destroy(TestEventLoop *event_loop)
+{
+    if (event_loop->timeout_timer != NULL) {
+        event_loop->core->timer_remove(event_loop->timeout_timer);
+        event_loop->timeout_timer = NULL;
+    }
+    if (event_loop->exit_mainloop_timer != NULL) {
+        event_loop->core->timer_remove(event_loop->exit_mainloop_timer);
+        event_loop->exit_mainloop_timer = NULL;
+    }
+    basic_event_loop_destroy();
+    event_loop->core = NULL;
+}
+
+static void test_event_loop_run(TestEventLoop *event_loop)
+{
+    event_loop->core->timer_start(event_loop->timeout_timer, 5000);
+    basic_event_loop_mainloop();
+}
+
 static GIOStream *fake_client_connect(GSocketConnectable *connectable, GError **error)
 {
     GSocketClient *client;
@@ -78,17 +124,18 @@ static void check_magic(GIOStream *io_stream, GError **error)
     g_assert_cmpint(memcmp(buffer, "REDQ", 4), ==, 0);
 }
 
-static void exit_mainloop_cb(SPICE_GNUC_UNUSED void *opaque)
+typedef struct
 {
-    basic_event_loop_quit();
-}
+    GSocketConnectable *connectable;
+    TestEventLoop *event_loop;
+} ThreadData;
 
 static gpointer check_magic_thread(gpointer data)
 {
     GError *error = NULL;
-    GSocketConnectable *connectable = G_SOCKET_CONNECTABLE(data);
+    ThreadData *thread_data = data;
+    GSocketConnectable *connectable = G_SOCKET_CONNECTABLE(thread_data->connectable);
     GIOStream *stream;
-    SpiceTimer *exit_mainloop_timer;
 
     stream = fake_client_connect(connectable, &error);
     g_assert_no_error(error);
@@ -97,8 +144,9 @@ static gpointer check_magic_thread(gpointer data)
 
     g_object_unref(stream);
     g_object_unref(connectable);
-    exit_mainloop_timer = core->timer_add(exit_mainloop_cb, NULL);
-    core->timer_start(exit_mainloop_timer, 0);
+    g_free(thread_data);
+
+    test_event_loop_quit(thread_data->event_loop);
 
     return NULL;
 }
@@ -106,9 +154,9 @@ static gpointer check_magic_thread(gpointer data)
 static gpointer check_no_connect_thread(gpointer data)
 {
     GError *error = NULL;
-    GSocketConnectable *connectable = G_SOCKET_CONNECTABLE(data);
+    ThreadData *thread_data = data;
+    GSocketConnectable *connectable = G_SOCKET_CONNECTABLE(thread_data->connectable);
     GIOStream *stream;
-    SpiceTimer *exit_mainloop_timer;
 
     stream = fake_client_connect(connectable, &error);
     g_assert(error != NULL);
@@ -116,22 +164,26 @@ static gpointer check_no_connect_thread(gpointer data)
     g_clear_error(&error);
 
     g_object_unref(connectable);
-    exit_mainloop_timer = core->timer_add(exit_mainloop_cb, NULL);
-    core->timer_start(exit_mainloop_timer, 0);
+    g_free(thread_data);
+
+    test_event_loop_quit(thread_data->event_loop);
 
     return NULL;
 }
 
-static GThread *fake_client_new(GThreadFunc thread_func, const char *hostname, int port)
+static GThread *fake_client_new(GThreadFunc thread_func,
+                                const char *hostname, int port,
+                                TestEventLoop *event_loop)
 {
-    GSocketConnectable *connectable;
+    ThreadData *thread_data = g_new0(ThreadData, 1);
 
     g_assert_cmpuint(port, >, 0);
     g_assert_cmpuint(port, <, 65536);
-    connectable = g_network_address_new(hostname, port);
+    thread_data->connectable = g_network_address_new(hostname, port);
+    thread_data->event_loop = event_loop;
 
     /* check_magic_thread will assume ownership of 'connectable' */
-    return g_thread_new("fake-client-thread", thread_func, connectable);
+    return g_thread_new("fake-client-thread", thread_func, thread_data);
 }
 
 static void test_connect_plain(void)
@@ -139,44 +191,40 @@ static void test_connect_plain(void)
     GThread *thread;
     int result;
 
+    TestEventLoop event_loop = { 0, };
+
+    test_event_loop_init(&event_loop);
+
     /* server */
     SpiceServer *server = spice_server_new();
-    core = basic_event_loop_init();
     spice_server_set_name(server, "SPICE listen test");
     spice_server_set_noauth(server);
     spice_server_set_port(server, BASE_PORT);
-    result = spice_server_init(server, core);
+    result = spice_server_init(server, event_loop.core);
     g_assert_cmpint(result, ==, 0);
 
     /* fake client */
-    thread = fake_client_new(check_magic_thread, "localhost", BASE_PORT);
-
-    basic_event_loop_mainloop();
-
+    thread = fake_client_new(check_magic_thread, "localhost", BASE_PORT, &event_loop);
+    test_event_loop_run(&event_loop);
     g_assert_null(g_thread_join(thread));
 
-    g_thread_unref(thread);
-    basic_event_loop_destroy();
-    core = NULL;
+    test_event_loop_destroy(&event_loop);
     spice_server_destroy(server);
 }
 
 static void test_connect_ko(void)
 {
     GThread *thread;
+    TestEventLoop event_loop = { 0, };
 
-    core = basic_event_loop_init();
+    test_event_loop_init(&event_loop);
 
     /* fake client */
-    thread = fake_client_new(check_no_connect_thread, "localhost", BASE_PORT);
-
-    basic_event_loop_mainloop();
-
+    thread = fake_client_new(check_no_connect_thread, "localhost", BASE_PORT, &event_loop);
+    test_event_loop_run(&event_loop);
     g_assert_null(g_thread_join(thread));
 
-    g_thread_unref(thread);
-    basic_event_loop_destroy();
-    core = NULL;
+    test_event_loop_destroy(&event_loop);
 }
 
 int main(int argc, char **argv)
commit a58d44cec38c6efba1753a24fa3b5d343fd708ec
Author: Christophe Fergeau <cfergeau at redhat.com>
Date:   Tue Feb 27 15:38:34 2018 +0100

    test-listen: Add test case for port/address configuration
    
    This test case will be testing the external spice-server API to
    configure the address/port it's listening on. For now it sets up a
    listening server, spawns a thread which is going to connect to that
    port, and check it gets the REDQ magic upon connection. It will be
    extended to test for Unix sockets, TLS sockets, ...
    
    Signed-off-by: Christophe Fergeau <cfergeau at redhat.com>

diff --git a/server/tests/Makefile.am b/server/tests/Makefile.am
index 2ff06d7a..0aae1fd6 100644
--- a/server/tests/Makefile.am
+++ b/server/tests/Makefile.am
@@ -59,6 +59,7 @@ check_PROGRAMS =				\
 	test-empty-success			\
 	test-channel				\
 	test-stream-device			\
+	test-listen				\
 	$(NULL)
 
 noinst_PROGRAMS =				\
diff --git a/server/tests/test-listen.c b/server/tests/test-listen.c
new file mode 100644
index 00000000..ab8bceab
--- /dev/null
+++ b/server/tests/test-listen.c
@@ -0,0 +1,190 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+   Copyright (C) 2018 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
+   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/>.
+*/
+/*
+ * This tests the external API entry points to configure the address/port
+ * spice-server is listening on
+ */
+#include <config.h>
+
+#include "basic-event-loop.h"
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include <gio/gio.h>
+
+/* Arbitrary base port, we want a port which is not in use by the system, and
+ * by another of our tests (in case of parallel runs)
+ */
+#define BASE_PORT 5728
+
+static SpiceCoreInterface *core;
+
+static bool error_is_set(GError **error)
+{
+    return ((error != NULL) && (*error != NULL));
+}
+
+static GIOStream *fake_client_connect(GSocketConnectable *connectable, GError **error)
+{
+    GSocketClient *client;
+    GSocketConnection *connection;
+
+    client = g_socket_client_new();
+    connection = g_socket_client_connect(client, connectable, NULL, error);
+
+    g_object_unref(client);
+
+    return G_IO_STREAM(connection);
+}
+
+static void check_magic(GIOStream *io_stream, GError **error)
+{
+    uint8_t buffer[4];
+    gsize bytes_read;
+    gsize bytes_written;
+    GInputStream *input_stream;
+    GOutputStream *output_stream;
+
+    /* send dummy data to trigger a response from the server */
+    output_stream = g_io_stream_get_output_stream(io_stream);
+    memset(buffer, 0xa5, G_N_ELEMENTS(buffer));
+    g_output_stream_write_all(output_stream, buffer, G_N_ELEMENTS(buffer), &bytes_written, NULL, error);
+    if (error_is_set(error)) {
+        return;
+    }
+
+    input_stream = g_io_stream_get_input_stream(io_stream);
+    g_input_stream_read_all(input_stream, buffer, G_N_ELEMENTS(buffer), &bytes_read, NULL, error);
+    if (error_is_set(error)) {
+        return;
+    }
+    g_assert_cmpuint(bytes_read, ==, G_N_ELEMENTS(buffer));
+    g_assert_cmpint(memcmp(buffer, "REDQ", 4), ==, 0);
+}
+
+static void exit_mainloop_cb(SPICE_GNUC_UNUSED void *opaque)
+{
+    basic_event_loop_quit();
+}
+
+static gpointer check_magic_thread(gpointer data)
+{
+    GError *error = NULL;
+    GSocketConnectable *connectable = G_SOCKET_CONNECTABLE(data);
+    GIOStream *stream;
+    SpiceTimer *exit_mainloop_timer;
+
+    stream = fake_client_connect(connectable, &error);
+    g_assert_no_error(error);
+    check_magic(stream, &error);
+    g_assert_no_error(error);
+
+    g_object_unref(stream);
+    g_object_unref(connectable);
+    exit_mainloop_timer = core->timer_add(exit_mainloop_cb, NULL);
+    core->timer_start(exit_mainloop_timer, 0);
+
+    return NULL;
+}
+
+static gpointer check_no_connect_thread(gpointer data)
+{
+    GError *error = NULL;
+    GSocketConnectable *connectable = G_SOCKET_CONNECTABLE(data);
+    GIOStream *stream;
+    SpiceTimer *exit_mainloop_timer;
+
+    stream = fake_client_connect(connectable, &error);
+    g_assert(error != NULL);
+    g_assert(stream == NULL);
+    g_clear_error(&error);
+
+    g_object_unref(connectable);
+    exit_mainloop_timer = core->timer_add(exit_mainloop_cb, NULL);
+    core->timer_start(exit_mainloop_timer, 0);
+
+    return NULL;
+}
+
+static GThread *fake_client_new(GThreadFunc thread_func, const char *hostname, int port)
+{
+    GSocketConnectable *connectable;
+
+    g_assert_cmpuint(port, >, 0);
+    g_assert_cmpuint(port, <, 65536);
+    connectable = g_network_address_new(hostname, port);
+
+    /* check_magic_thread will assume ownership of 'connectable' */
+    return g_thread_new("fake-client-thread", thread_func, connectable);
+}
+
+static void test_connect_plain(void)
+{
+    GThread *thread;
+    int result;
+
+    /* server */
+    SpiceServer *server = spice_server_new();
+    core = basic_event_loop_init();
+    spice_server_set_name(server, "SPICE listen test");
+    spice_server_set_noauth(server);
+    spice_server_set_port(server, BASE_PORT);
+    result = spice_server_init(server, core);
+    g_assert_cmpint(result, ==, 0);
+
+    /* fake client */
+    thread = fake_client_new(check_magic_thread, "localhost", BASE_PORT);
+
+    basic_event_loop_mainloop();
+
+    g_assert_null(g_thread_join(thread));
+
+    g_thread_unref(thread);
+    basic_event_loop_destroy();
+    core = NULL;
+    spice_server_destroy(server);
+}
+
+static void test_connect_ko(void)
+{
+    GThread *thread;
+
+    core = basic_event_loop_init();
+
+    /* fake client */
+    thread = fake_client_new(check_no_connect_thread, "localhost", BASE_PORT);
+
+    basic_event_loop_mainloop();
+
+    g_assert_null(g_thread_join(thread));
+
+    g_thread_unref(thread);
+    basic_event_loop_destroy();
+    core = NULL;
+}
+
+int main(int argc, char **argv)
+{
+    g_test_init(&argc, &argv, NULL);
+
+    g_test_add_func("/server/listen/connect_plain", test_connect_plain);
+    g_test_add_func("/server/listen/connect_ko", test_connect_ko);
+
+    return g_test_run();
+}
commit 1a230cdac03af4f376fb741f82853293465aae40
Author: Christophe Fergeau <cfergeau at redhat.com>
Date:   Tue Feb 27 17:29:24 2018 +0100

    tests: basic-event-loop: Silence debug message
    
    There is currently a debug printf which is always shown when a mainloop
    event is triggered. This is unlikely to be useful unless one is
    debugging the event loop code.
    
    Signed-off-by: Christophe Fergeau <cfergeau at redhat.com>

diff --git a/server/tests/basic-event-loop.c b/server/tests/basic-event-loop.c
index b10ac946..607a5a5e 100644
--- a/server/tests/basic-event-loop.c
+++ b/server/tests/basic-event-loop.c
@@ -46,7 +46,7 @@ GMainContext *basic_event_loop_get_context(void)
 
 static void event_loop_channel_event(int event, SpiceChannelEventInfo *info)
 {
-    DPRINTF(0, "channel event con, type, id, event: %d, %d, %d, %d",
+    DPRINTF(1, "channel event con, type, id, event: %d, %d, %d, %d",
             info->connection_id, info->type, info->id, event);
 }
 
commit 6bc2b39a01a2318d183749b0b78b0a9af6790362
Author: Christophe Fergeau <cfergeau at redhat.com>
Date:   Fri Mar 2 17:16:47 2018 +0100

    build: Bump glib version
    
    From spice-gtk b312ca08 commit:
    "    At the moment:
        - Fedora 26 has 2.52
        - Fedora 25 has 2.50
        - Fedora 24 has 2.48
        - CentOS 7 has 2.46
        - Debian 9 has 2.50"
    
    RHEL6 only have 2.28, but glib 2.32 is only used in a test case at the
    moment.
    
    Signed-off-by: Christophe Fergeau <cfergeau at redhat.com>

diff --git a/configure.ac b/configure.ac
index 9eb9bb49..bcd4bb4d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -161,8 +161,8 @@ SPICE_PROTOCOL_MIN_VER=0.12.14
 PKG_CHECK_MODULES([SPICE_PROTOCOL], [spice-protocol >= $SPICE_PROTOCOL_MIN_VER])
 AC_SUBST([SPICE_PROTOCOL_MIN_VER])
 
-GLIB2_REQUIRED=2.28
-GLIB2_ENCODED_VERSION="GLIB_VERSION_2_28"
+GLIB2_REQUIRED=2.32
+GLIB2_ENCODED_VERSION="GLIB_VERSION_2_32"
 PKG_CHECK_MODULES([GLIB2], [glib-2.0 >= $GLIB2_REQUIRED gio-2.0 >= $GLIB2_REQUIRED])
 GLIB2_CFLAGS="$GLIB2_CFLAGS -DGLIB_VERSION_MIN_REQUIRED=$GLIB2_ENCODED_VERSION \
   -DGLIB_VERSION_MAX_ALLOWED=$GLIB2_ENCODED_VERSION"
commit 4ec9f3e02f004d1431c5ab087ade5bd8c02c636b
Author: Christophe Fergeau <cfergeau at redhat.com>
Date:   Tue Aug 2 11:40:59 2016 +0200

    reds: Close sockets when failing to watch them
    
    Currently if we fail to set up the watch waiting for accept() to be
    called on the socket, we still keep the network socket(s) open even if we
    are not going to be able to use it. This commit makes sure it's closed a
    set to -1 when such a failure occurs rather than having a half
    initialized spice-server instance.
    
    Signed-off-by: Christophe Fergeau <cfergeau at redhat.com>

diff --git a/server/reds.c b/server/reds.c
index 73c9ec20..415d570f 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -2607,6 +2607,24 @@ void reds_set_client_mm_time_latency(RedsState *reds, RedClient *client, uint32_
     }
 }
 
+static void reds_cleanup_net(SpiceServer *reds)
+{
+    if (reds->listen_socket != -1) {
+       reds_core_watch_remove(reds, reds->listen_watch);
+       if (reds->config->spice_listen_socket_fd != reds->listen_socket) {
+          close(reds->listen_socket);
+       }
+       reds->listen_watch = NULL;
+       reds->listen_socket = -1;
+    }
+    if (reds->secure_listen_socket != -1) {
+       reds_core_watch_remove(reds, reds->secure_listen_watch);
+       close(reds->secure_listen_socket);
+       reds->secure_listen_watch = NULL;
+       reds->secure_listen_socket = -1;
+    }
+}
+
 static int reds_init_net(RedsState *reds)
 {
     if (reds->config->spice_port != -1 || reds->config->spice_family == AF_UNIX) {
@@ -2618,7 +2636,6 @@ static int reds_init_net(RedsState *reds)
                                                  SPICE_WATCH_EVENT_READ,
                                                  reds_accept, reds);
         if (reds->listen_watch == NULL) {
-            spice_warning("set fd handle failed");
             return -1;
         }
     }
@@ -2633,7 +2650,6 @@ static int reds_init_net(RedsState *reds)
                                                         SPICE_WATCH_EVENT_READ,
                                                         reds_accept_ssl_connection, reds);
         if (reds->secure_listen_watch == NULL) {
-            spice_warning("set fd handle failed");
             return -1;
         }
     }
@@ -2644,7 +2660,6 @@ static int reds_init_net(RedsState *reds)
                                                  SPICE_WATCH_EVENT_READ,
                                                  reds_accept, reds);
         if (reds->listen_watch == NULL) {
-            spice_warning("set fd handle failed");
             return -1;
         }
     }
@@ -3362,6 +3377,7 @@ static int do_spice_init(RedsState *reds, SpiceCoreInterface *core_interface)
     }
 
     if (reds_init_net(reds) < 0) {
+        spice_warning("Failed to open SPICE sockets");
         goto err;
     }
     if (reds->secure_listen_socket != -1) {
@@ -3396,6 +3412,7 @@ static int do_spice_init(RedsState *reds, SpiceCoreInterface *core_interface)
     return 0;
 
 err:
+    reds_cleanup_net(reds);
     return -1;
 }
 
@@ -3655,16 +3672,7 @@ SPICE_GNUC_VISIBLE void spice_server_destroy(SpiceServer *reds)
     if (reds->main_dispatcher) {
         g_object_unref(reds->main_dispatcher);
     }
-    if (reds->listen_socket != -1) {
-       reds_core_watch_remove(reds, reds->listen_watch);
-       if (reds->config->spice_listen_socket_fd != reds->listen_socket) {
-          close(reds->listen_socket);
-       }
-    }
-    if (reds->secure_listen_socket != -1) {
-       reds_core_watch_remove(reds, reds->secure_listen_watch);
-       close(reds->secure_listen_socket);
-    }
+    reds_cleanup_net(reds);
     g_clear_object(&reds->agent_dev);
     spice_buffer_free(&reds->client_monitors_config);
     red_record_unref(reds->record);


More information about the Spice-commits mailing list