1c95031a1SLaurent Vivier /* 2c95031a1SLaurent Vivier * QTest testcase for netdev stream and dgram 3c95031a1SLaurent Vivier * 4c95031a1SLaurent Vivier * Copyright (c) 2022 Red Hat, Inc. 5c95031a1SLaurent Vivier * 6c95031a1SLaurent Vivier * SPDX-License-Identifier: GPL-2.0-or-later 7c95031a1SLaurent Vivier */ 8c95031a1SLaurent Vivier 9c95031a1SLaurent Vivier #include "qemu/osdep.h" 10c95031a1SLaurent Vivier #include "qemu/sockets.h" 11c95031a1SLaurent Vivier #include <glib/gstdio.h> 12c95031a1SLaurent Vivier #include "../unit/socket-helpers.h" 13c95031a1SLaurent Vivier #include "libqtest.h" 14148fbf0dSLaurent Vivier #include "qapi/qmp/qstring.h" 15148fbf0dSLaurent Vivier #include "qemu/sockets.h" 16148fbf0dSLaurent Vivier #include "qapi/qobject-input-visitor.h" 17148fbf0dSLaurent Vivier #include "qapi/qapi-visit-sockets.h" 18c95031a1SLaurent Vivier 19a2982938SDaniel P. Berrangé #define CONNECTION_TIMEOUT 60 20c95031a1SLaurent Vivier 21c95031a1SLaurent Vivier #define EXPECT_STATE(q, e, t) \ 22c95031a1SLaurent Vivier do { \ 23c95031a1SLaurent Vivier char *resp = NULL; \ 24c95031a1SLaurent Vivier g_test_timer_start(); \ 25c95031a1SLaurent Vivier do { \ 26c95031a1SLaurent Vivier g_free(resp); \ 27c95031a1SLaurent Vivier resp = qtest_hmp(q, "info network"); \ 28c95031a1SLaurent Vivier if (t) { \ 29c95031a1SLaurent Vivier strrchr(resp, t)[0] = 0; \ 30c95031a1SLaurent Vivier } \ 31c95031a1SLaurent Vivier if (g_str_equal(resp, e)) { \ 32c95031a1SLaurent Vivier break; \ 33c95031a1SLaurent Vivier } \ 349f7ac8e8SDaniel P. Berrangé } while (g_test_timer_elapsed() < CONNECTION_TIMEOUT); \ 35c95031a1SLaurent Vivier g_assert_cmpstr(resp, ==, e); \ 36c95031a1SLaurent Vivier g_free(resp); \ 37c95031a1SLaurent Vivier } while (0) 38c95031a1SLaurent Vivier 39c95031a1SLaurent Vivier static gchar *tmpdir; 40c95031a1SLaurent Vivier 41c95031a1SLaurent Vivier static int inet_get_free_port_socket_ipv4(int sock) 42c95031a1SLaurent Vivier { 43c95031a1SLaurent Vivier struct sockaddr_in addr; 44c95031a1SLaurent Vivier socklen_t len; 45c95031a1SLaurent Vivier 46c95031a1SLaurent Vivier memset(&addr, 0, sizeof(addr)); 47c95031a1SLaurent Vivier addr.sin_family = AF_INET; 48c95031a1SLaurent Vivier addr.sin_addr.s_addr = INADDR_ANY; 49c95031a1SLaurent Vivier addr.sin_port = 0; 50c95031a1SLaurent Vivier if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) { 51c95031a1SLaurent Vivier return -1; 52c95031a1SLaurent Vivier } 53c95031a1SLaurent Vivier 54c95031a1SLaurent Vivier len = sizeof(addr); 55c95031a1SLaurent Vivier if (getsockname(sock, (struct sockaddr *)&addr, &len) < 0) { 56c95031a1SLaurent Vivier return -1; 57c95031a1SLaurent Vivier } 58c95031a1SLaurent Vivier 59c95031a1SLaurent Vivier return ntohs(addr.sin_port); 60c95031a1SLaurent Vivier } 61c95031a1SLaurent Vivier 62c95031a1SLaurent Vivier static int inet_get_free_port_socket_ipv6(int sock) 63c95031a1SLaurent Vivier { 64c95031a1SLaurent Vivier struct sockaddr_in6 addr; 65c95031a1SLaurent Vivier socklen_t len; 66c95031a1SLaurent Vivier 67c95031a1SLaurent Vivier memset(&addr, 0, sizeof(addr)); 68c95031a1SLaurent Vivier addr.sin6_family = AF_INET6; 69c95031a1SLaurent Vivier addr.sin6_addr = in6addr_any; 70c95031a1SLaurent Vivier addr.sin6_port = 0; 71c95031a1SLaurent Vivier if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) { 72c95031a1SLaurent Vivier return -1; 73c95031a1SLaurent Vivier } 74c95031a1SLaurent Vivier 75c95031a1SLaurent Vivier len = sizeof(addr); 76c95031a1SLaurent Vivier if (getsockname(sock, (struct sockaddr *)&addr, &len) < 0) { 77c95031a1SLaurent Vivier return -1; 78c95031a1SLaurent Vivier } 79c95031a1SLaurent Vivier 80c95031a1SLaurent Vivier return ntohs(addr.sin6_port); 81c95031a1SLaurent Vivier } 82c95031a1SLaurent Vivier 83c95031a1SLaurent Vivier static int inet_get_free_port_multiple(int nb, int *port, bool ipv6) 84c95031a1SLaurent Vivier { 85b2a7d863SPeter Maydell g_autofree int *sock = g_new(int, nb); 86c95031a1SLaurent Vivier int i; 87c95031a1SLaurent Vivier 88c95031a1SLaurent Vivier for (i = 0; i < nb; i++) { 89c95031a1SLaurent Vivier sock[i] = socket(ipv6 ? AF_INET6 : AF_INET, SOCK_STREAM, 0); 90c95031a1SLaurent Vivier if (sock[i] < 0) { 91c95031a1SLaurent Vivier break; 92c95031a1SLaurent Vivier } 93c95031a1SLaurent Vivier port[i] = ipv6 ? inet_get_free_port_socket_ipv6(sock[i]) : 94c95031a1SLaurent Vivier inet_get_free_port_socket_ipv4(sock[i]); 95c95031a1SLaurent Vivier if (port[i] == -1) { 96c95031a1SLaurent Vivier break; 97c95031a1SLaurent Vivier } 98c95031a1SLaurent Vivier } 99c95031a1SLaurent Vivier 100c95031a1SLaurent Vivier nb = i; 101c95031a1SLaurent Vivier for (i = 0; i < nb; i++) { 10225657fc6SMarc-André Lureau close(sock[i]); 103c95031a1SLaurent Vivier } 104c95031a1SLaurent Vivier 105c95031a1SLaurent Vivier return nb; 106c95031a1SLaurent Vivier } 107c95031a1SLaurent Vivier 108c95031a1SLaurent Vivier static int inet_get_free_port(bool ipv6) 109c95031a1SLaurent Vivier { 110c95031a1SLaurent Vivier int nb, port; 111c95031a1SLaurent Vivier 112c95031a1SLaurent Vivier nb = inet_get_free_port_multiple(1, &port, ipv6); 113c95031a1SLaurent Vivier g_assert_cmpint(nb, ==, 1); 114c95031a1SLaurent Vivier 115c95031a1SLaurent Vivier return port; 116c95031a1SLaurent Vivier } 117c95031a1SLaurent Vivier 118c95031a1SLaurent Vivier static void test_stream_inet_ipv4(void) 119c95031a1SLaurent Vivier { 120c95031a1SLaurent Vivier QTestState *qts0, *qts1; 121c95031a1SLaurent Vivier char *expect; 122c95031a1SLaurent Vivier int port; 123c95031a1SLaurent Vivier 124c95031a1SLaurent Vivier port = inet_get_free_port(false); 125c95031a1SLaurent Vivier qts0 = qtest_initf("-nodefaults -M none " 126c95031a1SLaurent Vivier "-netdev stream,id=st0,server=true,addr.type=inet," 127c95031a1SLaurent Vivier "addr.ipv4=on,addr.ipv6=off," 128c95031a1SLaurent Vivier "addr.host=127.0.0.1,addr.port=%d", port); 129c95031a1SLaurent Vivier 130*cc91ca64SDaniel P. Berrangé EXPECT_STATE(qts0, "st0: index=0,type=stream,listening\r\n", 0); 131c95031a1SLaurent Vivier 132c95031a1SLaurent Vivier qts1 = qtest_initf("-nodefaults -M none " 133c95031a1SLaurent Vivier "-netdev stream,server=false,id=st0,addr.type=inet," 134c95031a1SLaurent Vivier "addr.ipv4=on,addr.ipv6=off," 135c95031a1SLaurent Vivier "addr.host=127.0.0.1,addr.port=%d", port); 136c95031a1SLaurent Vivier 137c95031a1SLaurent Vivier expect = g_strdup_printf("st0: index=0,type=stream,tcp:127.0.0.1:%d\r\n", 138c95031a1SLaurent Vivier port); 139c95031a1SLaurent Vivier EXPECT_STATE(qts1, expect, 0); 140c95031a1SLaurent Vivier g_free(expect); 141c95031a1SLaurent Vivier 142c95031a1SLaurent Vivier /* the port is unknown, check only the address */ 143c95031a1SLaurent Vivier EXPECT_STATE(qts0, "st0: index=0,type=stream,tcp:127.0.0.1", ':'); 144c95031a1SLaurent Vivier 145c95031a1SLaurent Vivier qtest_quit(qts1); 146c95031a1SLaurent Vivier qtest_quit(qts0); 147c95031a1SLaurent Vivier } 148c95031a1SLaurent Vivier 149148fbf0dSLaurent Vivier static void wait_stream_connected(QTestState *qts, const char *id, 150148fbf0dSLaurent Vivier SocketAddress **addr) 151148fbf0dSLaurent Vivier { 152148fbf0dSLaurent Vivier QDict *resp, *data; 153148fbf0dSLaurent Vivier QString *qstr; 154148fbf0dSLaurent Vivier QObject *obj; 155148fbf0dSLaurent Vivier Visitor *v = NULL; 156148fbf0dSLaurent Vivier 157148fbf0dSLaurent Vivier resp = qtest_qmp_eventwait_ref(qts, "NETDEV_STREAM_CONNECTED"); 158148fbf0dSLaurent Vivier g_assert_nonnull(resp); 159148fbf0dSLaurent Vivier data = qdict_get_qdict(resp, "data"); 160148fbf0dSLaurent Vivier g_assert_nonnull(data); 161148fbf0dSLaurent Vivier 162148fbf0dSLaurent Vivier qstr = qobject_to(QString, qdict_get(data, "netdev-id")); 163148fbf0dSLaurent Vivier g_assert_nonnull(data); 164148fbf0dSLaurent Vivier 165148fbf0dSLaurent Vivier g_assert(!strcmp(qstring_get_str(qstr), id)); 166148fbf0dSLaurent Vivier 167148fbf0dSLaurent Vivier obj = qdict_get(data, "addr"); 168148fbf0dSLaurent Vivier 169148fbf0dSLaurent Vivier v = qobject_input_visitor_new(obj); 170148fbf0dSLaurent Vivier visit_type_SocketAddress(v, NULL, addr, NULL); 171148fbf0dSLaurent Vivier visit_free(v); 172148fbf0dSLaurent Vivier qobject_unref(resp); 173148fbf0dSLaurent Vivier } 174148fbf0dSLaurent Vivier 175148fbf0dSLaurent Vivier static void wait_stream_disconnected(QTestState *qts, const char *id) 176148fbf0dSLaurent Vivier { 177148fbf0dSLaurent Vivier QDict *resp, *data; 178148fbf0dSLaurent Vivier QString *qstr; 179148fbf0dSLaurent Vivier 180148fbf0dSLaurent Vivier resp = qtest_qmp_eventwait_ref(qts, "NETDEV_STREAM_DISCONNECTED"); 181148fbf0dSLaurent Vivier g_assert_nonnull(resp); 182148fbf0dSLaurent Vivier data = qdict_get_qdict(resp, "data"); 183148fbf0dSLaurent Vivier g_assert_nonnull(data); 184148fbf0dSLaurent Vivier 185148fbf0dSLaurent Vivier qstr = qobject_to(QString, qdict_get(data, "netdev-id")); 186148fbf0dSLaurent Vivier g_assert_nonnull(data); 187148fbf0dSLaurent Vivier 188148fbf0dSLaurent Vivier g_assert(!strcmp(qstring_get_str(qstr), id)); 189148fbf0dSLaurent Vivier qobject_unref(resp); 190148fbf0dSLaurent Vivier } 191148fbf0dSLaurent Vivier 192eb966605SLaurent Vivier static void test_stream_unix_reconnect(void) 193148fbf0dSLaurent Vivier { 194148fbf0dSLaurent Vivier QTestState *qts0, *qts1; 195148fbf0dSLaurent Vivier SocketAddress *addr; 196eb966605SLaurent Vivier gchar *path; 197148fbf0dSLaurent Vivier 198eb966605SLaurent Vivier path = g_strconcat(tmpdir, "/stream_unix_reconnect", NULL); 199148fbf0dSLaurent Vivier qts0 = qtest_initf("-nodefaults -M none " 200eb966605SLaurent Vivier "-netdev stream,id=st0,server=true,addr.type=unix," 201eb966605SLaurent Vivier "addr.path=%s", path); 202148fbf0dSLaurent Vivier 203*cc91ca64SDaniel P. Berrangé EXPECT_STATE(qts0, "st0: index=0,type=stream,listening\r\n", 0); 204148fbf0dSLaurent Vivier 205148fbf0dSLaurent Vivier qts1 = qtest_initf("-nodefaults -M none " 206eb966605SLaurent Vivier "-netdev stream,server=false,id=st0,addr.type=unix," 207eb966605SLaurent Vivier "addr.path=%s,reconnect=1", path); 208148fbf0dSLaurent Vivier 209148fbf0dSLaurent Vivier wait_stream_connected(qts0, "st0", &addr); 210eb966605SLaurent Vivier g_assert_cmpint(addr->type, ==, SOCKET_ADDRESS_TYPE_UNIX); 211eb966605SLaurent Vivier g_assert_cmpstr(addr->u.q_unix.path, ==, path); 212148fbf0dSLaurent Vivier qapi_free_SocketAddress(addr); 213148fbf0dSLaurent Vivier 214148fbf0dSLaurent Vivier /* kill server */ 215148fbf0dSLaurent Vivier qtest_quit(qts0); 216148fbf0dSLaurent Vivier 217148fbf0dSLaurent Vivier /* check client has been disconnected */ 218148fbf0dSLaurent Vivier wait_stream_disconnected(qts1, "st0"); 219148fbf0dSLaurent Vivier 220148fbf0dSLaurent Vivier /* restart server */ 221148fbf0dSLaurent Vivier qts0 = qtest_initf("-nodefaults -M none " 222eb966605SLaurent Vivier "-netdev stream,id=st0,server=true,addr.type=unix," 223eb966605SLaurent Vivier "addr.path=%s", path); 224148fbf0dSLaurent Vivier 225148fbf0dSLaurent Vivier /* wait connection events*/ 226148fbf0dSLaurent Vivier wait_stream_connected(qts0, "st0", &addr); 227eb966605SLaurent Vivier g_assert_cmpint(addr->type, ==, SOCKET_ADDRESS_TYPE_UNIX); 228eb966605SLaurent Vivier g_assert_cmpstr(addr->u.q_unix.path, ==, path); 229148fbf0dSLaurent Vivier qapi_free_SocketAddress(addr); 230148fbf0dSLaurent Vivier 231148fbf0dSLaurent Vivier wait_stream_connected(qts1, "st0", &addr); 232eb966605SLaurent Vivier g_assert_cmpint(addr->type, ==, SOCKET_ADDRESS_TYPE_UNIX); 233eb966605SLaurent Vivier g_assert_cmpstr(addr->u.q_unix.path, ==, path); 234148fbf0dSLaurent Vivier qapi_free_SocketAddress(addr); 235148fbf0dSLaurent Vivier 236148fbf0dSLaurent Vivier qtest_quit(qts1); 237148fbf0dSLaurent Vivier qtest_quit(qts0); 238eb966605SLaurent Vivier g_free(path); 239148fbf0dSLaurent Vivier } 240148fbf0dSLaurent Vivier 241c95031a1SLaurent Vivier static void test_stream_inet_ipv6(void) 242c95031a1SLaurent Vivier { 243c95031a1SLaurent Vivier QTestState *qts0, *qts1; 244c95031a1SLaurent Vivier char *expect; 245c95031a1SLaurent Vivier int port; 246c95031a1SLaurent Vivier 247c95031a1SLaurent Vivier port = inet_get_free_port(true); 248c95031a1SLaurent Vivier qts0 = qtest_initf("-nodefaults -M none " 249c95031a1SLaurent Vivier "-netdev stream,id=st0,server=true,addr.type=inet," 250c95031a1SLaurent Vivier "addr.ipv4=off,addr.ipv6=on," 251c95031a1SLaurent Vivier "addr.host=::1,addr.port=%d", port); 252c95031a1SLaurent Vivier 253*cc91ca64SDaniel P. Berrangé EXPECT_STATE(qts0, "st0: index=0,type=stream,listening\r\n", 0); 254c95031a1SLaurent Vivier 255c95031a1SLaurent Vivier qts1 = qtest_initf("-nodefaults -M none " 256c95031a1SLaurent Vivier "-netdev stream,server=false,id=st0,addr.type=inet," 257c95031a1SLaurent Vivier "addr.ipv4=off,addr.ipv6=on," 258c95031a1SLaurent Vivier "addr.host=::1,addr.port=%d", port); 259c95031a1SLaurent Vivier 260c95031a1SLaurent Vivier expect = g_strdup_printf("st0: index=0,type=stream,tcp:::1:%d\r\n", 261c95031a1SLaurent Vivier port); 262c95031a1SLaurent Vivier EXPECT_STATE(qts1, expect, 0); 263c95031a1SLaurent Vivier g_free(expect); 264c95031a1SLaurent Vivier 265c95031a1SLaurent Vivier /* the port is unknown, check only the address */ 266c95031a1SLaurent Vivier EXPECT_STATE(qts0, "st0: index=0,type=stream,tcp:::1", ':'); 267c95031a1SLaurent Vivier 268c95031a1SLaurent Vivier qtest_quit(qts1); 269c95031a1SLaurent Vivier qtest_quit(qts0); 270c95031a1SLaurent Vivier } 271c95031a1SLaurent Vivier 272c95031a1SLaurent Vivier static void test_stream_unix(void) 273c95031a1SLaurent Vivier { 274c95031a1SLaurent Vivier QTestState *qts0, *qts1; 275c95031a1SLaurent Vivier char *expect; 276c95031a1SLaurent Vivier gchar *path; 277c95031a1SLaurent Vivier 278c95031a1SLaurent Vivier path = g_strconcat(tmpdir, "/stream_unix", NULL); 279c95031a1SLaurent Vivier 280c95031a1SLaurent Vivier qts0 = qtest_initf("-nodefaults -M none " 281c95031a1SLaurent Vivier "-netdev stream,id=st0,server=true," 282c95031a1SLaurent Vivier "addr.type=unix,addr.path=%s,", 283c95031a1SLaurent Vivier path); 284c95031a1SLaurent Vivier 285*cc91ca64SDaniel P. Berrangé EXPECT_STATE(qts0, "st0: index=0,type=stream,listening\r\n", 0); 286c95031a1SLaurent Vivier 287c95031a1SLaurent Vivier qts1 = qtest_initf("-nodefaults -M none " 288c95031a1SLaurent Vivier "-netdev stream,id=st0,server=false," 289c95031a1SLaurent Vivier "addr.type=unix,addr.path=%s", 290c95031a1SLaurent Vivier path); 291c95031a1SLaurent Vivier 292c95031a1SLaurent Vivier expect = g_strdup_printf("st0: index=0,type=stream,unix:%s\r\n", path); 293c95031a1SLaurent Vivier EXPECT_STATE(qts1, expect, 0); 294c95031a1SLaurent Vivier EXPECT_STATE(qts0, expect, 0); 295c95031a1SLaurent Vivier g_free(expect); 296c95031a1SLaurent Vivier g_free(path); 297c95031a1SLaurent Vivier 298c95031a1SLaurent Vivier qtest_quit(qts1); 299c95031a1SLaurent Vivier qtest_quit(qts0); 300c95031a1SLaurent Vivier } 301c95031a1SLaurent Vivier 302c95031a1SLaurent Vivier #ifdef CONFIG_LINUX 303c95031a1SLaurent Vivier static void test_stream_unix_abstract(void) 304c95031a1SLaurent Vivier { 305c95031a1SLaurent Vivier QTestState *qts0, *qts1; 306c95031a1SLaurent Vivier char *expect; 307c95031a1SLaurent Vivier gchar *path; 308c95031a1SLaurent Vivier 309c95031a1SLaurent Vivier path = g_strconcat(tmpdir, "/stream_unix_abstract", NULL); 310c95031a1SLaurent Vivier 311c95031a1SLaurent Vivier qts0 = qtest_initf("-nodefaults -M none " 312c95031a1SLaurent Vivier "-netdev stream,id=st0,server=true," 313c95031a1SLaurent Vivier "addr.type=unix,addr.path=%s," 314c95031a1SLaurent Vivier "addr.abstract=on", 315c95031a1SLaurent Vivier path); 316c95031a1SLaurent Vivier 317*cc91ca64SDaniel P. Berrangé EXPECT_STATE(qts0, "st0: index=0,type=stream,listening\r\n", 0); 318c95031a1SLaurent Vivier 319c95031a1SLaurent Vivier qts1 = qtest_initf("-nodefaults -M none " 320c95031a1SLaurent Vivier "-netdev stream,id=st0,server=false," 321c95031a1SLaurent Vivier "addr.type=unix,addr.path=%s,addr.abstract=on", 322c95031a1SLaurent Vivier path); 323c95031a1SLaurent Vivier 324c95031a1SLaurent Vivier expect = g_strdup_printf("st0: index=0,type=stream,unix:%s\r\n", path); 325c95031a1SLaurent Vivier EXPECT_STATE(qts1, expect, 0); 326c95031a1SLaurent Vivier EXPECT_STATE(qts0, expect, 0); 327c95031a1SLaurent Vivier g_free(expect); 328c95031a1SLaurent Vivier g_free(path); 329c95031a1SLaurent Vivier 330c95031a1SLaurent Vivier qtest_quit(qts1); 331c95031a1SLaurent Vivier qtest_quit(qts0); 332c95031a1SLaurent Vivier } 333c95031a1SLaurent Vivier #endif 334c95031a1SLaurent Vivier 335c95031a1SLaurent Vivier #ifndef _WIN32 336c95031a1SLaurent Vivier static void test_stream_fd(void) 337c95031a1SLaurent Vivier { 338c95031a1SLaurent Vivier QTestState *qts0, *qts1; 339c95031a1SLaurent Vivier int sock[2]; 340c95031a1SLaurent Vivier int ret; 341c95031a1SLaurent Vivier 342c95031a1SLaurent Vivier ret = socketpair(AF_LOCAL, SOCK_STREAM, 0, sock); 343c95031a1SLaurent Vivier g_assert_true(ret == 0); 344c95031a1SLaurent Vivier 345c95031a1SLaurent Vivier qts0 = qtest_initf("-nodefaults -M none " 346c95031a1SLaurent Vivier "-netdev stream,id=st0,addr.type=fd,addr.str=%d", 347c95031a1SLaurent Vivier sock[0]); 348c95031a1SLaurent Vivier 349c95031a1SLaurent Vivier EXPECT_STATE(qts0, "st0: index=0,type=stream,unix:\r\n", 0); 350c95031a1SLaurent Vivier 351c95031a1SLaurent Vivier qts1 = qtest_initf("-nodefaults -M none " 352c95031a1SLaurent Vivier "-netdev stream,id=st0,addr.type=fd,addr.str=%d", 353c95031a1SLaurent Vivier sock[1]); 354c95031a1SLaurent Vivier 355c95031a1SLaurent Vivier EXPECT_STATE(qts1, "st0: index=0,type=stream,unix:\r\n", 0); 356c95031a1SLaurent Vivier EXPECT_STATE(qts0, "st0: index=0,type=stream,unix:\r\n", 0); 357c95031a1SLaurent Vivier 358c95031a1SLaurent Vivier qtest_quit(qts1); 359c95031a1SLaurent Vivier qtest_quit(qts0); 360c95031a1SLaurent Vivier 36125657fc6SMarc-André Lureau close(sock[0]); 36225657fc6SMarc-André Lureau close(sock[1]); 363c95031a1SLaurent Vivier } 364c95031a1SLaurent Vivier #endif 365c95031a1SLaurent Vivier 366c95031a1SLaurent Vivier static void test_dgram_inet(void) 367c95031a1SLaurent Vivier { 368c95031a1SLaurent Vivier QTestState *qts0, *qts1; 369c95031a1SLaurent Vivier char *expect; 370c95031a1SLaurent Vivier int port[2]; 371c95031a1SLaurent Vivier int nb; 372c95031a1SLaurent Vivier 373c95031a1SLaurent Vivier nb = inet_get_free_port_multiple(2, port, false); 374c95031a1SLaurent Vivier g_assert_cmpint(nb, ==, 2); 375c95031a1SLaurent Vivier 376c95031a1SLaurent Vivier qts0 = qtest_initf("-nodefaults -M none " 377c95031a1SLaurent Vivier "-netdev dgram,id=st0," 378c95031a1SLaurent Vivier "local.type=inet,local.host=127.0.0.1,local.port=%d," 379c95031a1SLaurent Vivier "remote.type=inet,remote.host=127.0.0.1,remote.port=%d", 380c95031a1SLaurent Vivier port[0], port[1]); 381c95031a1SLaurent Vivier 382c95031a1SLaurent Vivier expect = g_strdup_printf("st0: index=0,type=dgram," 383c95031a1SLaurent Vivier "udp=127.0.0.1:%d/127.0.0.1:%d\r\n", 384c95031a1SLaurent Vivier port[0], port[1]); 385c95031a1SLaurent Vivier EXPECT_STATE(qts0, expect, 0); 386c95031a1SLaurent Vivier g_free(expect); 387c95031a1SLaurent Vivier 388c95031a1SLaurent Vivier qts1 = qtest_initf("-nodefaults -M none " 389c95031a1SLaurent Vivier "-netdev dgram,id=st0," 390c95031a1SLaurent Vivier "local.type=inet,local.host=127.0.0.1,local.port=%d," 391c95031a1SLaurent Vivier "remote.type=inet,remote.host=127.0.0.1,remote.port=%d", 392c95031a1SLaurent Vivier port[1], port[0]); 393c95031a1SLaurent Vivier 394c95031a1SLaurent Vivier expect = g_strdup_printf("st0: index=0,type=dgram," 395c95031a1SLaurent Vivier "udp=127.0.0.1:%d/127.0.0.1:%d\r\n", 396c95031a1SLaurent Vivier port[1], port[0]); 397c95031a1SLaurent Vivier EXPECT_STATE(qts1, expect, 0); 398c95031a1SLaurent Vivier g_free(expect); 399c95031a1SLaurent Vivier 400c95031a1SLaurent Vivier qtest_quit(qts1); 401c95031a1SLaurent Vivier qtest_quit(qts0); 402c95031a1SLaurent Vivier } 403c95031a1SLaurent Vivier 40402e8828aSPhilippe Mathieu-Daudé #if !defined(_WIN32) && !defined(CONFIG_DARWIN) 405c95031a1SLaurent Vivier static void test_dgram_mcast(void) 406c95031a1SLaurent Vivier { 407c95031a1SLaurent Vivier QTestState *qts; 408c95031a1SLaurent Vivier 409c95031a1SLaurent Vivier qts = qtest_initf("-nodefaults -M none " 410c95031a1SLaurent Vivier "-netdev dgram,id=st0," 411c95031a1SLaurent Vivier "remote.type=inet,remote.host=230.0.0.1,remote.port=1234"); 412c95031a1SLaurent Vivier 413c95031a1SLaurent Vivier EXPECT_STATE(qts, "st0: index=0,type=dgram,mcast=230.0.0.1:1234\r\n", 0); 414c95031a1SLaurent Vivier 415c95031a1SLaurent Vivier qtest_quit(qts); 416c95031a1SLaurent Vivier } 41702e8828aSPhilippe Mathieu-Daudé #endif 418c95031a1SLaurent Vivier 41902e8828aSPhilippe Mathieu-Daudé #ifndef _WIN32 420c95031a1SLaurent Vivier static void test_dgram_unix(void) 421c95031a1SLaurent Vivier { 422c95031a1SLaurent Vivier QTestState *qts0, *qts1; 423c95031a1SLaurent Vivier char *expect; 424c95031a1SLaurent Vivier gchar *path0, *path1; 425c95031a1SLaurent Vivier 426c95031a1SLaurent Vivier path0 = g_strconcat(tmpdir, "/dgram_unix0", NULL); 427c95031a1SLaurent Vivier path1 = g_strconcat(tmpdir, "/dgram_unix1", NULL); 428c95031a1SLaurent Vivier 429c95031a1SLaurent Vivier qts0 = qtest_initf("-nodefaults -M none " 430c95031a1SLaurent Vivier "-netdev dgram,id=st0,local.type=unix,local.path=%s," 431c95031a1SLaurent Vivier "remote.type=unix,remote.path=%s", 432c95031a1SLaurent Vivier path0, path1); 433c95031a1SLaurent Vivier 434c95031a1SLaurent Vivier expect = g_strdup_printf("st0: index=0,type=dgram,udp=%s:%s\r\n", 435c95031a1SLaurent Vivier path0, path1); 436c95031a1SLaurent Vivier EXPECT_STATE(qts0, expect, 0); 437c95031a1SLaurent Vivier g_free(expect); 438c95031a1SLaurent Vivier 439c95031a1SLaurent Vivier qts1 = qtest_initf("-nodefaults -M none " 440c95031a1SLaurent Vivier "-netdev dgram,id=st0,local.type=unix,local.path=%s," 441c95031a1SLaurent Vivier "remote.type=unix,remote.path=%s", 442c95031a1SLaurent Vivier path1, path0); 443c95031a1SLaurent Vivier 444c95031a1SLaurent Vivier 445c95031a1SLaurent Vivier expect = g_strdup_printf("st0: index=0,type=dgram,udp=%s:%s\r\n", 446c95031a1SLaurent Vivier path1, path0); 447c95031a1SLaurent Vivier EXPECT_STATE(qts1, expect, 0); 448c95031a1SLaurent Vivier g_free(expect); 449c95031a1SLaurent Vivier 450c95031a1SLaurent Vivier unlink(path0); 451c95031a1SLaurent Vivier g_free(path0); 452c95031a1SLaurent Vivier unlink(path1); 453c95031a1SLaurent Vivier g_free(path1); 454c95031a1SLaurent Vivier 455c95031a1SLaurent Vivier qtest_quit(qts1); 456c95031a1SLaurent Vivier qtest_quit(qts0); 457c95031a1SLaurent Vivier } 458c95031a1SLaurent Vivier 459c95031a1SLaurent Vivier static void test_dgram_fd(void) 460c95031a1SLaurent Vivier { 461c95031a1SLaurent Vivier QTestState *qts0, *qts1; 462c95031a1SLaurent Vivier char *expect; 463c95031a1SLaurent Vivier int ret; 464c95031a1SLaurent Vivier int sv[2]; 465c95031a1SLaurent Vivier 466c95031a1SLaurent Vivier ret = socketpair(PF_UNIX, SOCK_DGRAM, 0, sv); 467c95031a1SLaurent Vivier g_assert_cmpint(ret, !=, -1); 468c95031a1SLaurent Vivier 469c95031a1SLaurent Vivier qts0 = qtest_initf("-nodefaults -M none " 470c95031a1SLaurent Vivier "-netdev dgram,id=st0,local.type=fd,local.str=%d", 471c95031a1SLaurent Vivier sv[0]); 472c95031a1SLaurent Vivier 473c95031a1SLaurent Vivier expect = g_strdup_printf("st0: index=0,type=dgram,fd=%d unix\r\n", sv[0]); 474c95031a1SLaurent Vivier EXPECT_STATE(qts0, expect, 0); 475c95031a1SLaurent Vivier g_free(expect); 476c95031a1SLaurent Vivier 477c95031a1SLaurent Vivier qts1 = qtest_initf("-nodefaults -M none " 478c95031a1SLaurent Vivier "-netdev dgram,id=st0,local.type=fd,local.str=%d", 479c95031a1SLaurent Vivier sv[1]); 480c95031a1SLaurent Vivier 481c95031a1SLaurent Vivier 482c95031a1SLaurent Vivier expect = g_strdup_printf("st0: index=0,type=dgram,fd=%d unix\r\n", sv[1]); 483c95031a1SLaurent Vivier EXPECT_STATE(qts1, expect, 0); 484c95031a1SLaurent Vivier g_free(expect); 485c95031a1SLaurent Vivier 486c95031a1SLaurent Vivier qtest_quit(qts1); 487c95031a1SLaurent Vivier qtest_quit(qts0); 488c95031a1SLaurent Vivier 48925657fc6SMarc-André Lureau close(sv[0]); 49025657fc6SMarc-André Lureau close(sv[1]); 491c95031a1SLaurent Vivier } 492c95031a1SLaurent Vivier #endif 493c95031a1SLaurent Vivier 494c95031a1SLaurent Vivier int main(int argc, char **argv) 495c95031a1SLaurent Vivier { 496c95031a1SLaurent Vivier int ret; 497c95031a1SLaurent Vivier bool has_ipv4, has_ipv6, has_afunix; 498c95031a1SLaurent Vivier g_autoptr(GError) err = NULL; 499c95031a1SLaurent Vivier 500c95031a1SLaurent Vivier socket_init(); 501c95031a1SLaurent Vivier g_test_init(&argc, &argv, NULL); 502c95031a1SLaurent Vivier 503c95031a1SLaurent Vivier if (socket_check_protocol_support(&has_ipv4, &has_ipv6) < 0) { 504c95031a1SLaurent Vivier g_error("socket_check_protocol_support() failed\n"); 505c95031a1SLaurent Vivier } 506c95031a1SLaurent Vivier 507c95031a1SLaurent Vivier tmpdir = g_dir_make_tmp("netdev-socket.XXXXXX", &err); 508c95031a1SLaurent Vivier if (tmpdir == NULL) { 509c95031a1SLaurent Vivier g_error("Can't create temporary directory in %s: %s", 510c95031a1SLaurent Vivier g_get_tmp_dir(), err->message); 511c95031a1SLaurent Vivier } 512c95031a1SLaurent Vivier 513c95031a1SLaurent Vivier if (has_ipv4) { 514c95031a1SLaurent Vivier qtest_add_func("/netdev/stream/inet/ipv4", test_stream_inet_ipv4); 515c95031a1SLaurent Vivier qtest_add_func("/netdev/dgram/inet", test_dgram_inet); 51602e8828aSPhilippe Mathieu-Daudé #if !defined(_WIN32) && !defined(CONFIG_DARWIN) 517c95031a1SLaurent Vivier qtest_add_func("/netdev/dgram/mcast", test_dgram_mcast); 518c95031a1SLaurent Vivier #endif 519c95031a1SLaurent Vivier } 520c95031a1SLaurent Vivier if (has_ipv6) { 521c95031a1SLaurent Vivier qtest_add_func("/netdev/stream/inet/ipv6", test_stream_inet_ipv6); 522c95031a1SLaurent Vivier } 523c95031a1SLaurent Vivier 524c95031a1SLaurent Vivier socket_check_afunix_support(&has_afunix); 525c95031a1SLaurent Vivier if (has_afunix) { 526c95031a1SLaurent Vivier #ifndef _WIN32 527c95031a1SLaurent Vivier qtest_add_func("/netdev/dgram/unix", test_dgram_unix); 528c95031a1SLaurent Vivier #endif 529c95031a1SLaurent Vivier qtest_add_func("/netdev/stream/unix", test_stream_unix); 530eb966605SLaurent Vivier qtest_add_func("/netdev/stream/unix/reconnect", 531eb966605SLaurent Vivier test_stream_unix_reconnect); 532c95031a1SLaurent Vivier #ifdef CONFIG_LINUX 533c95031a1SLaurent Vivier qtest_add_func("/netdev/stream/unix/abstract", 534c95031a1SLaurent Vivier test_stream_unix_abstract); 535c95031a1SLaurent Vivier #endif 536c95031a1SLaurent Vivier #ifndef _WIN32 537c95031a1SLaurent Vivier qtest_add_func("/netdev/stream/fd", test_stream_fd); 538c95031a1SLaurent Vivier qtest_add_func("/netdev/dgram/fd", test_dgram_fd); 539c95031a1SLaurent Vivier #endif 540c95031a1SLaurent Vivier } 541c95031a1SLaurent Vivier 542c95031a1SLaurent Vivier ret = g_test_run(); 543c95031a1SLaurent Vivier 544c95031a1SLaurent Vivier g_rmdir(tmpdir); 545c95031a1SLaurent Vivier g_free(tmpdir); 546c95031a1SLaurent Vivier 547c95031a1SLaurent Vivier return ret; 548c95031a1SLaurent Vivier } 549