]> git.proxmox.com Git - mirror_qemu.git/blobdiff - tests/test-io-channel-socket.c
qemu-io: Put flag changes in the options QDict in reopen_f()
[mirror_qemu.git] / tests / test-io-channel-socket.c
index 4c16da1add23b28b5ba73d84358fc6b20d2ddb0d..0597213f934a0bc72d07eb9e1c10b35e8b74021a 100644 (file)
 #include "io/channel-socket.h"
 #include "io/channel-util.h"
 #include "io-channel-helpers.h"
-
-static int check_bind(struct sockaddr *sa, socklen_t salen, bool *has_proto)
-{
-    int fd;
-
-    fd = socket(sa->sa_family, SOCK_STREAM, 0);
-    if (fd < 0) {
-        return -1;
-    }
-
-    if (bind(fd, sa, salen) < 0) {
-        close(fd);
-        if (errno == EADDRNOTAVAIL) {
-            *has_proto = false;
-            return 0;
-        }
-        return -1;
-    }
-
-    close(fd);
-    *has_proto = true;
-    return 0;
-}
-
-static int check_protocol_support(bool *has_ipv4, bool *has_ipv6)
-{
-    struct sockaddr_in sin = {
-        .sin_family = AF_INET,
-        .sin_addr = { .s_addr = htonl(INADDR_LOOPBACK) },
-    };
-    struct sockaddr_in6 sin6 = {
-        .sin6_family = AF_INET6,
-        .sin6_addr = IN6ADDR_LOOPBACK_INIT,
-    };
-
-    if (check_bind((struct sockaddr *)&sin, sizeof(sin), has_ipv4) < 0) {
-        return -1;
-    }
-    if (check_bind((struct sockaddr *)&sin6, sizeof(sin6), has_ipv6) < 0) {
-        return -1;
-    }
-
-    return 0;
-}
+#include "socket-helpers.h"
+#include "qapi/error.h"
 
 
 static void test_io_channel_set_socket_bufs(QIOChannel *src,
@@ -99,12 +57,12 @@ static void test_io_channel_setup_sync(SocketAddress *listen_addr,
     lioc = qio_channel_socket_new();
     qio_channel_socket_listen_sync(lioc, listen_addr, &error_abort);
 
-    if (listen_addr->type == SOCKET_ADDRESS_KIND_INET) {
+    if (listen_addr->type == SOCKET_ADDRESS_TYPE_INET) {
         SocketAddress *laddr = qio_channel_socket_get_local_address(
             lioc, &error_abort);
 
-        g_free(connect_addr->u.inet->port);
-        connect_addr->u.inet->port = g_strdup(laddr->u.inet->port);
+        g_free(connect_addr->u.inet.port);
+        connect_addr->u.inet.port = g_strdup(laddr->u.inet.port);
 
         qapi_free_SocketAddress(laddr);
     }
@@ -114,6 +72,7 @@ static void test_io_channel_setup_sync(SocketAddress *listen_addr,
         QIO_CHANNEL_SOCKET(*src), connect_addr, &error_abort);
     qio_channel_set_delay(*src, false);
 
+    qio_channel_wait(QIO_CHANNEL(lioc), G_IO_IN);
     *dst = QIO_CHANNEL(qio_channel_socket_accept(lioc, &error_abort));
     g_assert(*dst);
 
@@ -129,12 +88,11 @@ struct TestIOChannelData {
 };
 
 
-static void test_io_channel_complete(Object *src,
-                                     Error *err,
+static void test_io_channel_complete(QIOTask *task,
                                      gpointer opaque)
 {
     struct TestIOChannelData *data = opaque;
-    data->err = err != NULL;
+    data->err = qio_task_propagate_error(task, NULL);
     g_main_loop_quit(data->loop);
 }
 
@@ -153,19 +111,19 @@ static void test_io_channel_setup_async(SocketAddress *listen_addr,
     lioc = qio_channel_socket_new();
     qio_channel_socket_listen_async(
         lioc, listen_addr,
-        test_io_channel_complete, &data, NULL);
+        test_io_channel_complete, &data, NULL, NULL);
 
     g_main_loop_run(data.loop);
     g_main_context_iteration(g_main_context_default(), FALSE);
 
     g_assert(!data.err);
 
-    if (listen_addr->type == SOCKET_ADDRESS_KIND_INET) {
+    if (listen_addr->type == SOCKET_ADDRESS_TYPE_INET) {
         SocketAddress *laddr = qio_channel_socket_get_local_address(
             lioc, &error_abort);
 
-        g_free(connect_addr->u.inet->port);
-        connect_addr->u.inet->port = g_strdup(laddr->u.inet->port);
+        g_free(connect_addr->u.inet.port);
+        connect_addr->u.inet.port = g_strdup(laddr->u.inet.port);
 
         qapi_free_SocketAddress(laddr);
     }
@@ -174,13 +132,14 @@ static void test_io_channel_setup_async(SocketAddress *listen_addr,
 
     qio_channel_socket_connect_async(
         QIO_CHANNEL_SOCKET(*src), connect_addr,
-        test_io_channel_complete, &data, NULL);
+        test_io_channel_complete, &data, NULL, NULL);
 
     g_main_loop_run(data.loop);
     g_main_context_iteration(g_main_context_default(), FALSE);
 
     g_assert(!data.err);
 
+    qio_channel_wait(QIO_CHANNEL(lioc), G_IO_IN);
     *dst = QIO_CHANNEL(qio_channel_socket_accept(lioc, &error_abort));
     g_assert(*dst);
 
@@ -207,6 +166,8 @@ static void test_io_channel(bool async,
                  qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS));
         g_assert(!passFD ||
                  qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_FD_PASS));
+        g_assert(qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_SHUTDOWN));
+        g_assert(qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_SHUTDOWN));
 
         test = qio_channel_test_new();
         qio_channel_test_run_threads(test, true, src, dst);
@@ -221,6 +182,8 @@ static void test_io_channel(bool async,
                  qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS));
         g_assert(!passFD ||
                  qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_FD_PASS));
+        g_assert(qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_SHUTDOWN));
+        g_assert(qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_SHUTDOWN));
 
         test = qio_channel_test_new();
         qio_channel_test_run_threads(test, false, src, dst);
@@ -235,6 +198,8 @@ static void test_io_channel(bool async,
                  qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS));
         g_assert(!passFD ||
                  qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_FD_PASS));
+        g_assert(qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_SHUTDOWN));
+        g_assert(qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_SHUTDOWN));
 
         test = qio_channel_test_new();
         qio_channel_test_run_threads(test, true, src, dst);
@@ -249,6 +214,8 @@ static void test_io_channel(bool async,
                  qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS));
         g_assert(!passFD ||
                  qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_FD_PASS));
+        g_assert(qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_SHUTDOWN));
+        g_assert(qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_SHUTDOWN));
 
         test = qio_channel_test_new();
         qio_channel_test_run_threads(test, false, src, dst);
@@ -265,16 +232,14 @@ static void test_io_channel_ipv4(bool async)
     SocketAddress *listen_addr = g_new0(SocketAddress, 1);
     SocketAddress *connect_addr = g_new0(SocketAddress, 1);
 
-    listen_addr->type = SOCKET_ADDRESS_KIND_INET;
-    listen_addr->u.inet = g_new(InetSocketAddress, 1);
-    *listen_addr->u.inet = (InetSocketAddress) {
+    listen_addr->type = SOCKET_ADDRESS_TYPE_INET;
+    listen_addr->u.inet = (InetSocketAddress) {
         .host = g_strdup("127.0.0.1"),
         .port = NULL, /* Auto-select */
     };
 
-    connect_addr->type = SOCKET_ADDRESS_KIND_INET;
-    connect_addr->u.inet = g_new(InetSocketAddress, 1);
-    *connect_addr->u.inet = (InetSocketAddress) {
+    connect_addr->type = SOCKET_ADDRESS_TYPE_INET;
+    connect_addr->u.inet = (InetSocketAddress) {
         .host = g_strdup("127.0.0.1"),
         .port = NULL, /* Filled in later */
     };
@@ -303,16 +268,14 @@ static void test_io_channel_ipv6(bool async)
     SocketAddress *listen_addr = g_new0(SocketAddress, 1);
     SocketAddress *connect_addr = g_new0(SocketAddress, 1);
 
-    listen_addr->type = SOCKET_ADDRESS_KIND_INET;
-    listen_addr->u.inet = g_new(InetSocketAddress, 1);
-    *listen_addr->u.inet = (InetSocketAddress) {
+    listen_addr->type = SOCKET_ADDRESS_TYPE_INET;
+    listen_addr->u.inet = (InetSocketAddress) {
         .host = g_strdup("::1"),
         .port = NULL, /* Auto-select */
     };
 
-    connect_addr->type = SOCKET_ADDRESS_KIND_INET;
-    connect_addr->u.inet = g_new(InetSocketAddress, 1);
-    *connect_addr->u.inet = (InetSocketAddress) {
+    connect_addr->type = SOCKET_ADDRESS_TYPE_INET;
+    connect_addr->u.inet = (InetSocketAddress) {
         .host = g_strdup("::1"),
         .port = NULL, /* Filled in later */
     };
@@ -343,19 +306,17 @@ static void test_io_channel_unix(bool async)
     SocketAddress *connect_addr = g_new0(SocketAddress, 1);
 
 #define TEST_SOCKET "test-io-channel-socket.sock"
-    listen_addr->type = SOCKET_ADDRESS_KIND_UNIX;
-    listen_addr->u.q_unix = g_new0(UnixSocketAddress, 1);
-    listen_addr->u.q_unix->path = g_strdup(TEST_SOCKET);
+    listen_addr->type = SOCKET_ADDRESS_TYPE_UNIX;
+    listen_addr->u.q_unix.path = g_strdup(TEST_SOCKET);
 
-    connect_addr->type = SOCKET_ADDRESS_KIND_UNIX;
-    connect_addr->u.q_unix = g_new0(UnixSocketAddress, 1);
-    connect_addr->u.q_unix->path = g_strdup(TEST_SOCKET);
+    connect_addr->type = SOCKET_ADDRESS_TYPE_UNIX;
+    connect_addr->u.q_unix.path = g_strdup(TEST_SOCKET);
 
     test_io_channel(async, listen_addr, connect_addr, true);
 
     qapi_free_SocketAddress(listen_addr);
     qapi_free_SocketAddress(connect_addr);
-    unlink(TEST_SOCKET);
+    g_assert(g_file_test(TEST_SOCKET, G_FILE_TEST_EXISTS) == FALSE);
 }
 
 
@@ -392,13 +353,11 @@ static void test_io_channel_unix_fd_pass(void)
     fdsend[1] = testfd;
     fdsend[2] = testfd;
 
-    listen_addr->type = SOCKET_ADDRESS_KIND_UNIX;
-    listen_addr->u.q_unix = g_new0(UnixSocketAddress, 1);
-    listen_addr->u.q_unix->path = g_strdup(TEST_SOCKET);
+    listen_addr->type = SOCKET_ADDRESS_TYPE_UNIX;
+    listen_addr->u.q_unix.path = g_strdup(TEST_SOCKET);
 
-    connect_addr->type = SOCKET_ADDRESS_KIND_UNIX;
-    connect_addr->u.q_unix = g_new0(UnixSocketAddress, 1);
-    connect_addr->u.q_unix->path = g_strdup(TEST_SOCKET);
+    connect_addr->type = SOCKET_ADDRESS_TYPE_UNIX;
+    connect_addr->u.q_unix.path = g_strdup(TEST_SOCKET);
 
     test_io_channel_setup_sync(listen_addr, connect_addr, &src, &dst);
 
@@ -463,6 +422,37 @@ static void test_io_channel_unix_fd_pass(void)
     }
     g_free(fdrecv);
 }
+
+static void test_io_channel_unix_listen_cleanup(void)
+{
+    QIOChannelSocket *ioc;
+    struct sockaddr_un un;
+    int sock;
+
+#define TEST_SOCKET "test-io-channel-socket.sock"
+
+    ioc = qio_channel_socket_new();
+
+    /* Manually bind ioc without calling the qio api to avoid setting
+     * the LISTEN feature */
+    sock = qemu_socket(PF_UNIX, SOCK_STREAM, 0);
+    memset(&un, 0, sizeof(un));
+    un.sun_family = AF_UNIX;
+    snprintf(un.sun_path, sizeof(un.sun_path), "%s", TEST_SOCKET);
+    unlink(TEST_SOCKET);
+    bind(sock, (struct sockaddr *)&un, sizeof(un));
+    ioc->fd = sock;
+    ioc->localAddrLen = sizeof(ioc->localAddr);
+    getsockname(sock, (struct sockaddr *)&ioc->localAddr,
+                &ioc->localAddrLen);
+
+    g_assert(g_file_test(TEST_SOCKET, G_FILE_TEST_EXISTS));
+    object_unref(OBJECT(ioc));
+    g_assert(g_file_test(TEST_SOCKET, G_FILE_TEST_EXISTS));
+
+    unlink(TEST_SOCKET);
+}
+
 #endif /* _WIN32 */
 
 
@@ -508,7 +498,7 @@ int main(int argc, char **argv)
      * each protocol to avoid breaking tests on machines
      * with either IPv4 or IPv6 disabled.
      */
-    if (check_protocol_support(&has_ipv4, &has_ipv6) < 0) {
+    if (socket_check_protocol_support(&has_ipv4, &has_ipv6) < 0) {
         return 1;
     }
 
@@ -534,6 +524,8 @@ int main(int argc, char **argv)
                     test_io_channel_unix_async);
     g_test_add_func("/io/channel/socket/unix-fd-pass",
                     test_io_channel_unix_fd_pass);
+    g_test_add_func("/io/channel/socket/unix-listen-cleanup",
+                    test_io_channel_unix_listen_cleanup);
 #endif /* _WIN32 */
 
     return g_test_run();