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 19417296c8SPeter Maydell #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 } \ 34c95031a1SLaurent Vivier } 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 { 85c95031a1SLaurent Vivier int sock[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++) { 102*25657fc6SMarc-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 130c95031a1SLaurent Vivier EXPECT_STATE(qts0, "st0: index=0,type=stream,\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 192148fbf0dSLaurent Vivier static void test_stream_inet_reconnect(void) 193148fbf0dSLaurent Vivier { 194148fbf0dSLaurent Vivier QTestState *qts0, *qts1; 195148fbf0dSLaurent Vivier int port; 196148fbf0dSLaurent Vivier SocketAddress *addr; 197148fbf0dSLaurent Vivier 198148fbf0dSLaurent Vivier port = inet_get_free_port(false); 199148fbf0dSLaurent Vivier qts0 = qtest_initf("-nodefaults -M none " 200148fbf0dSLaurent Vivier "-netdev stream,id=st0,server=true,addr.type=inet," 201148fbf0dSLaurent Vivier "addr.ipv4=on,addr.ipv6=off," 202148fbf0dSLaurent Vivier "addr.host=127.0.0.1,addr.port=%d", port); 203148fbf0dSLaurent Vivier 204148fbf0dSLaurent Vivier EXPECT_STATE(qts0, "st0: index=0,type=stream,\r\n", 0); 205148fbf0dSLaurent Vivier 206148fbf0dSLaurent Vivier qts1 = qtest_initf("-nodefaults -M none " 207148fbf0dSLaurent Vivier "-netdev stream,server=false,id=st0,addr.type=inet," 208148fbf0dSLaurent Vivier "addr.ipv4=on,addr.ipv6=off,reconnect=1," 209148fbf0dSLaurent Vivier "addr.host=127.0.0.1,addr.port=%d", port); 210148fbf0dSLaurent Vivier 211148fbf0dSLaurent Vivier wait_stream_connected(qts0, "st0", &addr); 212148fbf0dSLaurent Vivier g_assert_cmpint(addr->type, ==, SOCKET_ADDRESS_TYPE_INET); 213148fbf0dSLaurent Vivier g_assert_cmpstr(addr->u.inet.host, ==, "127.0.0.1"); 214148fbf0dSLaurent Vivier qapi_free_SocketAddress(addr); 215148fbf0dSLaurent Vivier 216148fbf0dSLaurent Vivier /* kill server */ 217148fbf0dSLaurent Vivier qtest_quit(qts0); 218148fbf0dSLaurent Vivier 219148fbf0dSLaurent Vivier /* check client has been disconnected */ 220148fbf0dSLaurent Vivier wait_stream_disconnected(qts1, "st0"); 221148fbf0dSLaurent Vivier 222148fbf0dSLaurent Vivier /* restart server */ 223148fbf0dSLaurent Vivier qts0 = qtest_initf("-nodefaults -M none " 224148fbf0dSLaurent Vivier "-netdev stream,id=st0,server=true,addr.type=inet," 225148fbf0dSLaurent Vivier "addr.ipv4=on,addr.ipv6=off," 226148fbf0dSLaurent Vivier "addr.host=127.0.0.1,addr.port=%d", port); 227148fbf0dSLaurent Vivier 228148fbf0dSLaurent Vivier /* wait connection events*/ 229148fbf0dSLaurent Vivier wait_stream_connected(qts0, "st0", &addr); 230148fbf0dSLaurent Vivier g_assert_cmpint(addr->type, ==, SOCKET_ADDRESS_TYPE_INET); 231148fbf0dSLaurent Vivier g_assert_cmpstr(addr->u.inet.host, ==, "127.0.0.1"); 232148fbf0dSLaurent Vivier qapi_free_SocketAddress(addr); 233148fbf0dSLaurent Vivier 234148fbf0dSLaurent Vivier wait_stream_connected(qts1, "st0", &addr); 235148fbf0dSLaurent Vivier g_assert_cmpint(addr->type, ==, SOCKET_ADDRESS_TYPE_INET); 236148fbf0dSLaurent Vivier g_assert_cmpstr(addr->u.inet.host, ==, "127.0.0.1"); 237148fbf0dSLaurent Vivier g_assert_cmpint(atoi(addr->u.inet.port), ==, port); 238148fbf0dSLaurent Vivier qapi_free_SocketAddress(addr); 239148fbf0dSLaurent Vivier 240148fbf0dSLaurent Vivier qtest_quit(qts1); 241148fbf0dSLaurent Vivier qtest_quit(qts0); 242148fbf0dSLaurent Vivier } 243148fbf0dSLaurent Vivier 244c95031a1SLaurent Vivier static void test_stream_inet_ipv6(void) 245c95031a1SLaurent Vivier { 246c95031a1SLaurent Vivier QTestState *qts0, *qts1; 247c95031a1SLaurent Vivier char *expect; 248c95031a1SLaurent Vivier int port; 249c95031a1SLaurent Vivier 250c95031a1SLaurent Vivier port = inet_get_free_port(true); 251c95031a1SLaurent Vivier qts0 = qtest_initf("-nodefaults -M none " 252c95031a1SLaurent Vivier "-netdev stream,id=st0,server=true,addr.type=inet," 253c95031a1SLaurent Vivier "addr.ipv4=off,addr.ipv6=on," 254c95031a1SLaurent Vivier "addr.host=::1,addr.port=%d", port); 255c95031a1SLaurent Vivier 256c95031a1SLaurent Vivier EXPECT_STATE(qts0, "st0: index=0,type=stream,\r\n", 0); 257c95031a1SLaurent Vivier 258c95031a1SLaurent Vivier qts1 = qtest_initf("-nodefaults -M none " 259c95031a1SLaurent Vivier "-netdev stream,server=false,id=st0,addr.type=inet," 260c95031a1SLaurent Vivier "addr.ipv4=off,addr.ipv6=on," 261c95031a1SLaurent Vivier "addr.host=::1,addr.port=%d", port); 262c95031a1SLaurent Vivier 263c95031a1SLaurent Vivier expect = g_strdup_printf("st0: index=0,type=stream,tcp:::1:%d\r\n", 264c95031a1SLaurent Vivier port); 265c95031a1SLaurent Vivier EXPECT_STATE(qts1, expect, 0); 266c95031a1SLaurent Vivier g_free(expect); 267c95031a1SLaurent Vivier 268c95031a1SLaurent Vivier /* the port is unknown, check only the address */ 269c95031a1SLaurent Vivier EXPECT_STATE(qts0, "st0: index=0,type=stream,tcp:::1", ':'); 270c95031a1SLaurent Vivier 271c95031a1SLaurent Vivier qtest_quit(qts1); 272c95031a1SLaurent Vivier qtest_quit(qts0); 273c95031a1SLaurent Vivier } 274c95031a1SLaurent Vivier 275c95031a1SLaurent Vivier static void test_stream_unix(void) 276c95031a1SLaurent Vivier { 277c95031a1SLaurent Vivier QTestState *qts0, *qts1; 278c95031a1SLaurent Vivier char *expect; 279c95031a1SLaurent Vivier gchar *path; 280c95031a1SLaurent Vivier 281c95031a1SLaurent Vivier path = g_strconcat(tmpdir, "/stream_unix", NULL); 282c95031a1SLaurent Vivier 283c95031a1SLaurent Vivier qts0 = qtest_initf("-nodefaults -M none " 284c95031a1SLaurent Vivier "-netdev stream,id=st0,server=true," 285c95031a1SLaurent Vivier "addr.type=unix,addr.path=%s,", 286c95031a1SLaurent Vivier path); 287c95031a1SLaurent Vivier 288c95031a1SLaurent Vivier EXPECT_STATE(qts0, "st0: index=0,type=stream,\r\n", 0); 289c95031a1SLaurent Vivier 290c95031a1SLaurent Vivier qts1 = qtest_initf("-nodefaults -M none " 291c95031a1SLaurent Vivier "-netdev stream,id=st0,server=false," 292c95031a1SLaurent Vivier "addr.type=unix,addr.path=%s", 293c95031a1SLaurent Vivier path); 294c95031a1SLaurent Vivier 295c95031a1SLaurent Vivier expect = g_strdup_printf("st0: index=0,type=stream,unix:%s\r\n", path); 296c95031a1SLaurent Vivier EXPECT_STATE(qts1, expect, 0); 297c95031a1SLaurent Vivier EXPECT_STATE(qts0, expect, 0); 298c95031a1SLaurent Vivier g_free(expect); 299c95031a1SLaurent Vivier g_free(path); 300c95031a1SLaurent Vivier 301c95031a1SLaurent Vivier qtest_quit(qts1); 302c95031a1SLaurent Vivier qtest_quit(qts0); 303c95031a1SLaurent Vivier } 304c95031a1SLaurent Vivier 305c95031a1SLaurent Vivier #ifdef CONFIG_LINUX 306c95031a1SLaurent Vivier static void test_stream_unix_abstract(void) 307c95031a1SLaurent Vivier { 308c95031a1SLaurent Vivier QTestState *qts0, *qts1; 309c95031a1SLaurent Vivier char *expect; 310c95031a1SLaurent Vivier gchar *path; 311c95031a1SLaurent Vivier 312c95031a1SLaurent Vivier path = g_strconcat(tmpdir, "/stream_unix_abstract", NULL); 313c95031a1SLaurent Vivier 314c95031a1SLaurent Vivier qts0 = qtest_initf("-nodefaults -M none " 315c95031a1SLaurent Vivier "-netdev stream,id=st0,server=true," 316c95031a1SLaurent Vivier "addr.type=unix,addr.path=%s," 317c95031a1SLaurent Vivier "addr.abstract=on", 318c95031a1SLaurent Vivier path); 319c95031a1SLaurent Vivier 320c95031a1SLaurent Vivier EXPECT_STATE(qts0, "st0: index=0,type=stream,\r\n", 0); 321c95031a1SLaurent Vivier 322c95031a1SLaurent Vivier qts1 = qtest_initf("-nodefaults -M none " 323c95031a1SLaurent Vivier "-netdev stream,id=st0,server=false," 324c95031a1SLaurent Vivier "addr.type=unix,addr.path=%s,addr.abstract=on", 325c95031a1SLaurent Vivier path); 326c95031a1SLaurent Vivier 327c95031a1SLaurent Vivier expect = g_strdup_printf("st0: index=0,type=stream,unix:%s\r\n", path); 328c95031a1SLaurent Vivier EXPECT_STATE(qts1, expect, 0); 329c95031a1SLaurent Vivier EXPECT_STATE(qts0, expect, 0); 330c95031a1SLaurent Vivier g_free(expect); 331c95031a1SLaurent Vivier g_free(path); 332c95031a1SLaurent Vivier 333c95031a1SLaurent Vivier qtest_quit(qts1); 334c95031a1SLaurent Vivier qtest_quit(qts0); 335c95031a1SLaurent Vivier } 336c95031a1SLaurent Vivier #endif 337c95031a1SLaurent Vivier 338c95031a1SLaurent Vivier #ifndef _WIN32 339c95031a1SLaurent Vivier static void test_stream_fd(void) 340c95031a1SLaurent Vivier { 341c95031a1SLaurent Vivier QTestState *qts0, *qts1; 342c95031a1SLaurent Vivier int sock[2]; 343c95031a1SLaurent Vivier int ret; 344c95031a1SLaurent Vivier 345c95031a1SLaurent Vivier ret = socketpair(AF_LOCAL, SOCK_STREAM, 0, sock); 346c95031a1SLaurent Vivier g_assert_true(ret == 0); 347c95031a1SLaurent Vivier 348c95031a1SLaurent Vivier qts0 = qtest_initf("-nodefaults -M none " 349c95031a1SLaurent Vivier "-netdev stream,id=st0,addr.type=fd,addr.str=%d", 350c95031a1SLaurent Vivier sock[0]); 351c95031a1SLaurent Vivier 352c95031a1SLaurent Vivier EXPECT_STATE(qts0, "st0: index=0,type=stream,unix:\r\n", 0); 353c95031a1SLaurent Vivier 354c95031a1SLaurent Vivier qts1 = qtest_initf("-nodefaults -M none " 355c95031a1SLaurent Vivier "-netdev stream,id=st0,addr.type=fd,addr.str=%d", 356c95031a1SLaurent Vivier sock[1]); 357c95031a1SLaurent Vivier 358c95031a1SLaurent Vivier EXPECT_STATE(qts1, "st0: index=0,type=stream,unix:\r\n", 0); 359c95031a1SLaurent Vivier EXPECT_STATE(qts0, "st0: index=0,type=stream,unix:\r\n", 0); 360c95031a1SLaurent Vivier 361c95031a1SLaurent Vivier qtest_quit(qts1); 362c95031a1SLaurent Vivier qtest_quit(qts0); 363c95031a1SLaurent Vivier 364*25657fc6SMarc-André Lureau close(sock[0]); 365*25657fc6SMarc-André Lureau close(sock[1]); 366c95031a1SLaurent Vivier } 367c95031a1SLaurent Vivier #endif 368c95031a1SLaurent Vivier 369c95031a1SLaurent Vivier static void test_dgram_inet(void) 370c95031a1SLaurent Vivier { 371c95031a1SLaurent Vivier QTestState *qts0, *qts1; 372c95031a1SLaurent Vivier char *expect; 373c95031a1SLaurent Vivier int port[2]; 374c95031a1SLaurent Vivier int nb; 375c95031a1SLaurent Vivier 376c95031a1SLaurent Vivier nb = inet_get_free_port_multiple(2, port, false); 377c95031a1SLaurent Vivier g_assert_cmpint(nb, ==, 2); 378c95031a1SLaurent Vivier 379c95031a1SLaurent Vivier qts0 = qtest_initf("-nodefaults -M none " 380c95031a1SLaurent Vivier "-netdev dgram,id=st0," 381c95031a1SLaurent Vivier "local.type=inet,local.host=127.0.0.1,local.port=%d," 382c95031a1SLaurent Vivier "remote.type=inet,remote.host=127.0.0.1,remote.port=%d", 383c95031a1SLaurent Vivier port[0], port[1]); 384c95031a1SLaurent Vivier 385c95031a1SLaurent Vivier expect = g_strdup_printf("st0: index=0,type=dgram," 386c95031a1SLaurent Vivier "udp=127.0.0.1:%d/127.0.0.1:%d\r\n", 387c95031a1SLaurent Vivier port[0], port[1]); 388c95031a1SLaurent Vivier EXPECT_STATE(qts0, expect, 0); 389c95031a1SLaurent Vivier g_free(expect); 390c95031a1SLaurent Vivier 391c95031a1SLaurent Vivier qts1 = qtest_initf("-nodefaults -M none " 392c95031a1SLaurent Vivier "-netdev dgram,id=st0," 393c95031a1SLaurent Vivier "local.type=inet,local.host=127.0.0.1,local.port=%d," 394c95031a1SLaurent Vivier "remote.type=inet,remote.host=127.0.0.1,remote.port=%d", 395c95031a1SLaurent Vivier port[1], port[0]); 396c95031a1SLaurent Vivier 397c95031a1SLaurent Vivier expect = g_strdup_printf("st0: index=0,type=dgram," 398c95031a1SLaurent Vivier "udp=127.0.0.1:%d/127.0.0.1:%d\r\n", 399c95031a1SLaurent Vivier port[1], port[0]); 400c95031a1SLaurent Vivier EXPECT_STATE(qts1, expect, 0); 401c95031a1SLaurent Vivier g_free(expect); 402c95031a1SLaurent Vivier 403c95031a1SLaurent Vivier qtest_quit(qts1); 404c95031a1SLaurent Vivier qtest_quit(qts0); 405c95031a1SLaurent Vivier } 406c95031a1SLaurent Vivier 407c95031a1SLaurent Vivier #ifndef _WIN32 408c95031a1SLaurent Vivier static void test_dgram_mcast(void) 409c95031a1SLaurent Vivier { 410c95031a1SLaurent Vivier QTestState *qts; 411c95031a1SLaurent Vivier 412c95031a1SLaurent Vivier qts = qtest_initf("-nodefaults -M none " 413c95031a1SLaurent Vivier "-netdev dgram,id=st0," 414c95031a1SLaurent Vivier "remote.type=inet,remote.host=230.0.0.1,remote.port=1234"); 415c95031a1SLaurent Vivier 416c95031a1SLaurent Vivier EXPECT_STATE(qts, "st0: index=0,type=dgram,mcast=230.0.0.1:1234\r\n", 0); 417c95031a1SLaurent Vivier 418c95031a1SLaurent Vivier qtest_quit(qts); 419c95031a1SLaurent Vivier } 420c95031a1SLaurent Vivier 421c95031a1SLaurent Vivier static void test_dgram_unix(void) 422c95031a1SLaurent Vivier { 423c95031a1SLaurent Vivier QTestState *qts0, *qts1; 424c95031a1SLaurent Vivier char *expect; 425c95031a1SLaurent Vivier gchar *path0, *path1; 426c95031a1SLaurent Vivier 427c95031a1SLaurent Vivier path0 = g_strconcat(tmpdir, "/dgram_unix0", NULL); 428c95031a1SLaurent Vivier path1 = g_strconcat(tmpdir, "/dgram_unix1", NULL); 429c95031a1SLaurent Vivier 430c95031a1SLaurent Vivier qts0 = qtest_initf("-nodefaults -M none " 431c95031a1SLaurent Vivier "-netdev dgram,id=st0,local.type=unix,local.path=%s," 432c95031a1SLaurent Vivier "remote.type=unix,remote.path=%s", 433c95031a1SLaurent Vivier path0, path1); 434c95031a1SLaurent Vivier 435c95031a1SLaurent Vivier expect = g_strdup_printf("st0: index=0,type=dgram,udp=%s:%s\r\n", 436c95031a1SLaurent Vivier path0, path1); 437c95031a1SLaurent Vivier EXPECT_STATE(qts0, expect, 0); 438c95031a1SLaurent Vivier g_free(expect); 439c95031a1SLaurent Vivier 440c95031a1SLaurent Vivier qts1 = qtest_initf("-nodefaults -M none " 441c95031a1SLaurent Vivier "-netdev dgram,id=st0,local.type=unix,local.path=%s," 442c95031a1SLaurent Vivier "remote.type=unix,remote.path=%s", 443c95031a1SLaurent Vivier path1, path0); 444c95031a1SLaurent Vivier 445c95031a1SLaurent Vivier 446c95031a1SLaurent Vivier expect = g_strdup_printf("st0: index=0,type=dgram,udp=%s:%s\r\n", 447c95031a1SLaurent Vivier path1, path0); 448c95031a1SLaurent Vivier EXPECT_STATE(qts1, expect, 0); 449c95031a1SLaurent Vivier g_free(expect); 450c95031a1SLaurent Vivier 451c95031a1SLaurent Vivier unlink(path0); 452c95031a1SLaurent Vivier g_free(path0); 453c95031a1SLaurent Vivier unlink(path1); 454c95031a1SLaurent Vivier g_free(path1); 455c95031a1SLaurent Vivier 456c95031a1SLaurent Vivier qtest_quit(qts1); 457c95031a1SLaurent Vivier qtest_quit(qts0); 458c95031a1SLaurent Vivier } 459c95031a1SLaurent Vivier 460c95031a1SLaurent Vivier static void test_dgram_fd(void) 461c95031a1SLaurent Vivier { 462c95031a1SLaurent Vivier QTestState *qts0, *qts1; 463c95031a1SLaurent Vivier char *expect; 464c95031a1SLaurent Vivier int ret; 465c95031a1SLaurent Vivier int sv[2]; 466c95031a1SLaurent Vivier 467c95031a1SLaurent Vivier ret = socketpair(PF_UNIX, SOCK_DGRAM, 0, sv); 468c95031a1SLaurent Vivier g_assert_cmpint(ret, !=, -1); 469c95031a1SLaurent Vivier 470c95031a1SLaurent Vivier qts0 = qtest_initf("-nodefaults -M none " 471c95031a1SLaurent Vivier "-netdev dgram,id=st0,local.type=fd,local.str=%d", 472c95031a1SLaurent Vivier sv[0]); 473c95031a1SLaurent Vivier 474c95031a1SLaurent Vivier expect = g_strdup_printf("st0: index=0,type=dgram,fd=%d unix\r\n", sv[0]); 475c95031a1SLaurent Vivier EXPECT_STATE(qts0, expect, 0); 476c95031a1SLaurent Vivier g_free(expect); 477c95031a1SLaurent Vivier 478c95031a1SLaurent Vivier qts1 = qtest_initf("-nodefaults -M none " 479c95031a1SLaurent Vivier "-netdev dgram,id=st0,local.type=fd,local.str=%d", 480c95031a1SLaurent Vivier sv[1]); 481c95031a1SLaurent Vivier 482c95031a1SLaurent Vivier 483c95031a1SLaurent Vivier expect = g_strdup_printf("st0: index=0,type=dgram,fd=%d unix\r\n", sv[1]); 484c95031a1SLaurent Vivier EXPECT_STATE(qts1, expect, 0); 485c95031a1SLaurent Vivier g_free(expect); 486c95031a1SLaurent Vivier 487c95031a1SLaurent Vivier qtest_quit(qts1); 488c95031a1SLaurent Vivier qtest_quit(qts0); 489c95031a1SLaurent Vivier 490*25657fc6SMarc-André Lureau close(sv[0]); 491*25657fc6SMarc-André Lureau close(sv[1]); 492c95031a1SLaurent Vivier } 493c95031a1SLaurent Vivier #endif 494c95031a1SLaurent Vivier 495c95031a1SLaurent Vivier int main(int argc, char **argv) 496c95031a1SLaurent Vivier { 497c95031a1SLaurent Vivier int ret; 498c95031a1SLaurent Vivier bool has_ipv4, has_ipv6, has_afunix; 499c95031a1SLaurent Vivier g_autoptr(GError) err = NULL; 500c95031a1SLaurent Vivier 501c95031a1SLaurent Vivier socket_init(); 502c95031a1SLaurent Vivier g_test_init(&argc, &argv, NULL); 503c95031a1SLaurent Vivier 504c95031a1SLaurent Vivier if (socket_check_protocol_support(&has_ipv4, &has_ipv6) < 0) { 505c95031a1SLaurent Vivier g_error("socket_check_protocol_support() failed\n"); 506c95031a1SLaurent Vivier } 507c95031a1SLaurent Vivier 508c95031a1SLaurent Vivier tmpdir = g_dir_make_tmp("netdev-socket.XXXXXX", &err); 509c95031a1SLaurent Vivier if (tmpdir == NULL) { 510c95031a1SLaurent Vivier g_error("Can't create temporary directory in %s: %s", 511c95031a1SLaurent Vivier g_get_tmp_dir(), err->message); 512c95031a1SLaurent Vivier } 513c95031a1SLaurent Vivier 514c95031a1SLaurent Vivier if (has_ipv4) { 515c95031a1SLaurent Vivier qtest_add_func("/netdev/stream/inet/ipv4", test_stream_inet_ipv4); 516c95031a1SLaurent Vivier qtest_add_func("/netdev/dgram/inet", test_dgram_inet); 517c95031a1SLaurent Vivier #ifndef _WIN32 518c95031a1SLaurent Vivier qtest_add_func("/netdev/dgram/mcast", test_dgram_mcast); 519c95031a1SLaurent Vivier #endif 520148fbf0dSLaurent Vivier qtest_add_func("/netdev/stream/inet/reconnect", 521148fbf0dSLaurent Vivier test_stream_inet_reconnect); 522c95031a1SLaurent Vivier } 523c95031a1SLaurent Vivier if (has_ipv6) { 524c95031a1SLaurent Vivier qtest_add_func("/netdev/stream/inet/ipv6", test_stream_inet_ipv6); 525c95031a1SLaurent Vivier } 526c95031a1SLaurent Vivier 527c95031a1SLaurent Vivier socket_check_afunix_support(&has_afunix); 528c95031a1SLaurent Vivier if (has_afunix) { 529c95031a1SLaurent Vivier #ifndef _WIN32 530c95031a1SLaurent Vivier qtest_add_func("/netdev/dgram/unix", test_dgram_unix); 531c95031a1SLaurent Vivier #endif 532c95031a1SLaurent Vivier qtest_add_func("/netdev/stream/unix", test_stream_unix); 533c95031a1SLaurent Vivier #ifdef CONFIG_LINUX 534c95031a1SLaurent Vivier qtest_add_func("/netdev/stream/unix/abstract", 535c95031a1SLaurent Vivier test_stream_unix_abstract); 536c95031a1SLaurent Vivier #endif 537c95031a1SLaurent Vivier #ifndef _WIN32 538c95031a1SLaurent Vivier qtest_add_func("/netdev/stream/fd", test_stream_fd); 539c95031a1SLaurent Vivier qtest_add_func("/netdev/dgram/fd", test_dgram_fd); 540c95031a1SLaurent Vivier #endif 541c95031a1SLaurent Vivier } 542c95031a1SLaurent Vivier 543c95031a1SLaurent Vivier ret = g_test_run(); 544c95031a1SLaurent Vivier 545c95031a1SLaurent Vivier g_rmdir(tmpdir); 546c95031a1SLaurent Vivier g_free(tmpdir); 547c95031a1SLaurent Vivier 548c95031a1SLaurent Vivier return ret; 549c95031a1SLaurent Vivier } 550