Merge tag 'pull-target-arm-20240701' of https://git.linaro.org/people/pmaydell/qemu...
[qemu/kevin.git] / tests / qtest / netdev-socket.c
blobfc7d11961eaa1659ffae58d5058ba123fc13cda9
1 /*
2 * QTest testcase for netdev stream and dgram
4 * Copyright (c) 2022 Red Hat, Inc.
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
9 #include "qemu/osdep.h"
10 #include "qemu/sockets.h"
11 #include <glib/gstdio.h>
12 #include "../unit/socket-helpers.h"
13 #include "libqtest.h"
14 #include "qapi/qmp/qstring.h"
15 #include "qemu/sockets.h"
16 #include "qapi/qobject-input-visitor.h"
17 #include "qapi/qapi-visit-sockets.h"
19 #define CONNECTION_TIMEOUT 60
21 #define EXPECT_STATE(q, e, t) \
22 do { \
23 char *resp = NULL; \
24 g_test_timer_start(); \
25 do { \
26 g_free(resp); \
27 resp = qtest_hmp(q, "info network"); \
28 if (t) { \
29 strrchr(resp, t)[0] = 0; \
30 } \
31 if (g_str_equal(resp, e)) { \
32 break; \
33 } \
34 } while (g_test_timer_elapsed() < CONNECTION_TIMEOUT); \
35 g_assert_cmpstr(resp, ==, e); \
36 g_free(resp); \
37 } while (0)
39 static gchar *tmpdir;
41 static int inet_get_free_port_socket_ipv4(int sock)
43 struct sockaddr_in addr;
44 socklen_t len;
46 memset(&addr, 0, sizeof(addr));
47 addr.sin_family = AF_INET;
48 addr.sin_addr.s_addr = INADDR_ANY;
49 addr.sin_port = 0;
50 if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
51 return -1;
54 len = sizeof(addr);
55 if (getsockname(sock, (struct sockaddr *)&addr, &len) < 0) {
56 return -1;
59 return ntohs(addr.sin_port);
62 static int inet_get_free_port_socket_ipv6(int sock)
64 struct sockaddr_in6 addr;
65 socklen_t len;
67 memset(&addr, 0, sizeof(addr));
68 addr.sin6_family = AF_INET6;
69 addr.sin6_addr = in6addr_any;
70 addr.sin6_port = 0;
71 if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
72 return -1;
75 len = sizeof(addr);
76 if (getsockname(sock, (struct sockaddr *)&addr, &len) < 0) {
77 return -1;
80 return ntohs(addr.sin6_port);
83 static int inet_get_free_port_multiple(int nb, int *port, bool ipv6)
85 g_autofree int *sock = g_new(int, nb);
86 int i;
88 for (i = 0; i < nb; i++) {
89 sock[i] = socket(ipv6 ? AF_INET6 : AF_INET, SOCK_STREAM, 0);
90 if (sock[i] < 0) {
91 break;
93 port[i] = ipv6 ? inet_get_free_port_socket_ipv6(sock[i]) :
94 inet_get_free_port_socket_ipv4(sock[i]);
95 if (port[i] == -1) {
96 break;
100 nb = i;
101 for (i = 0; i < nb; i++) {
102 close(sock[i]);
105 return nb;
108 static int inet_get_free_port(bool ipv6)
110 int nb, port;
112 nb = inet_get_free_port_multiple(1, &port, ipv6);
113 g_assert_cmpint(nb, ==, 1);
115 return port;
118 static void test_stream_inet_ipv4(void)
120 QTestState *qts0, *qts1;
121 char *expect;
122 int port;
124 port = inet_get_free_port(false);
125 qts0 = qtest_initf("-nodefaults -M none "
126 "-netdev stream,id=st0,server=true,addr.type=inet,"
127 "addr.ipv4=on,addr.ipv6=off,"
128 "addr.host=127.0.0.1,addr.port=%d", port);
130 EXPECT_STATE(qts0, "st0: index=0,type=stream,listening\r\n", 0);
132 qts1 = qtest_initf("-nodefaults -M none "
133 "-netdev stream,server=false,id=st0,addr.type=inet,"
134 "addr.ipv4=on,addr.ipv6=off,"
135 "addr.host=127.0.0.1,addr.port=%d", port);
137 expect = g_strdup_printf("st0: index=0,type=stream,tcp:127.0.0.1:%d\r\n",
138 port);
139 EXPECT_STATE(qts1, expect, 0);
140 g_free(expect);
142 /* the port is unknown, check only the address */
143 EXPECT_STATE(qts0, "st0: index=0,type=stream,tcp:127.0.0.1", ':');
145 qtest_quit(qts1);
146 qtest_quit(qts0);
149 static void wait_stream_connected(QTestState *qts, const char *id,
150 SocketAddress **addr)
152 QDict *resp, *data;
153 QString *qstr;
154 QObject *obj;
155 Visitor *v = NULL;
157 resp = qtest_qmp_eventwait_ref(qts, "NETDEV_STREAM_CONNECTED");
158 g_assert_nonnull(resp);
159 data = qdict_get_qdict(resp, "data");
160 g_assert_nonnull(data);
162 qstr = qobject_to(QString, qdict_get(data, "netdev-id"));
163 g_assert_nonnull(data);
165 g_assert(!strcmp(qstring_get_str(qstr), id));
167 obj = qdict_get(data, "addr");
169 v = qobject_input_visitor_new(obj);
170 visit_type_SocketAddress(v, NULL, addr, NULL);
171 visit_free(v);
172 qobject_unref(resp);
175 static void wait_stream_disconnected(QTestState *qts, const char *id)
177 QDict *resp, *data;
178 QString *qstr;
180 resp = qtest_qmp_eventwait_ref(qts, "NETDEV_STREAM_DISCONNECTED");
181 g_assert_nonnull(resp);
182 data = qdict_get_qdict(resp, "data");
183 g_assert_nonnull(data);
185 qstr = qobject_to(QString, qdict_get(data, "netdev-id"));
186 g_assert_nonnull(data);
188 g_assert(!strcmp(qstring_get_str(qstr), id));
189 qobject_unref(resp);
192 static void test_stream_unix_reconnect(void)
194 QTestState *qts0, *qts1;
195 SocketAddress *addr;
196 gchar *path;
198 path = g_strconcat(tmpdir, "/stream_unix_reconnect", NULL);
199 qts0 = qtest_initf("-nodefaults -M none "
200 "-netdev stream,id=st0,server=true,addr.type=unix,"
201 "addr.path=%s", path);
203 EXPECT_STATE(qts0, "st0: index=0,type=stream,listening\r\n", 0);
205 qts1 = qtest_initf("-nodefaults -M none "
206 "-netdev stream,server=false,id=st0,addr.type=unix,"
207 "addr.path=%s,reconnect=1", path);
209 wait_stream_connected(qts0, "st0", &addr);
210 g_assert_cmpint(addr->type, ==, SOCKET_ADDRESS_TYPE_UNIX);
211 g_assert_cmpstr(addr->u.q_unix.path, ==, path);
212 qapi_free_SocketAddress(addr);
214 /* kill server */
215 qtest_quit(qts0);
217 /* check client has been disconnected */
218 wait_stream_disconnected(qts1, "st0");
220 /* restart server */
221 qts0 = qtest_initf("-nodefaults -M none "
222 "-netdev stream,id=st0,server=true,addr.type=unix,"
223 "addr.path=%s", path);
225 /* wait connection events*/
226 wait_stream_connected(qts0, "st0", &addr);
227 g_assert_cmpint(addr->type, ==, SOCKET_ADDRESS_TYPE_UNIX);
228 g_assert_cmpstr(addr->u.q_unix.path, ==, path);
229 qapi_free_SocketAddress(addr);
231 wait_stream_connected(qts1, "st0", &addr);
232 g_assert_cmpint(addr->type, ==, SOCKET_ADDRESS_TYPE_UNIX);
233 g_assert_cmpstr(addr->u.q_unix.path, ==, path);
234 qapi_free_SocketAddress(addr);
236 qtest_quit(qts1);
237 qtest_quit(qts0);
238 g_free(path);
241 static void test_stream_inet_ipv6(void)
243 QTestState *qts0, *qts1;
244 char *expect;
245 int port;
247 port = inet_get_free_port(true);
248 qts0 = qtest_initf("-nodefaults -M none "
249 "-netdev stream,id=st0,server=true,addr.type=inet,"
250 "addr.ipv4=off,addr.ipv6=on,"
251 "addr.host=::1,addr.port=%d", port);
253 EXPECT_STATE(qts0, "st0: index=0,type=stream,listening\r\n", 0);
255 qts1 = qtest_initf("-nodefaults -M none "
256 "-netdev stream,server=false,id=st0,addr.type=inet,"
257 "addr.ipv4=off,addr.ipv6=on,"
258 "addr.host=::1,addr.port=%d", port);
260 expect = g_strdup_printf("st0: index=0,type=stream,tcp:::1:%d\r\n",
261 port);
262 EXPECT_STATE(qts1, expect, 0);
263 g_free(expect);
265 /* the port is unknown, check only the address */
266 EXPECT_STATE(qts0, "st0: index=0,type=stream,tcp:::1", ':');
268 qtest_quit(qts1);
269 qtest_quit(qts0);
272 static void test_stream_unix(void)
274 QTestState *qts0, *qts1;
275 char *expect;
276 gchar *path;
278 path = g_strconcat(tmpdir, "/stream_unix", NULL);
280 qts0 = qtest_initf("-nodefaults -M none "
281 "-netdev stream,id=st0,server=true,"
282 "addr.type=unix,addr.path=%s,",
283 path);
285 EXPECT_STATE(qts0, "st0: index=0,type=stream,listening\r\n", 0);
287 qts1 = qtest_initf("-nodefaults -M none "
288 "-netdev stream,id=st0,server=false,"
289 "addr.type=unix,addr.path=%s",
290 path);
292 expect = g_strdup_printf("st0: index=0,type=stream,unix:%s\r\n", path);
293 EXPECT_STATE(qts1, expect, 0);
294 EXPECT_STATE(qts0, expect, 0);
295 g_free(expect);
296 g_free(path);
298 qtest_quit(qts1);
299 qtest_quit(qts0);
302 #ifdef CONFIG_LINUX
303 static void test_stream_unix_abstract(void)
305 QTestState *qts0, *qts1;
306 char *expect;
307 gchar *path;
309 path = g_strconcat(tmpdir, "/stream_unix_abstract", NULL);
311 qts0 = qtest_initf("-nodefaults -M none "
312 "-netdev stream,id=st0,server=true,"
313 "addr.type=unix,addr.path=%s,"
314 "addr.abstract=on",
315 path);
317 EXPECT_STATE(qts0, "st0: index=0,type=stream,listening\r\n", 0);
319 qts1 = qtest_initf("-nodefaults -M none "
320 "-netdev stream,id=st0,server=false,"
321 "addr.type=unix,addr.path=%s,addr.abstract=on",
322 path);
324 expect = g_strdup_printf("st0: index=0,type=stream,unix:%s\r\n", path);
325 EXPECT_STATE(qts1, expect, 0);
326 EXPECT_STATE(qts0, expect, 0);
327 g_free(expect);
328 g_free(path);
330 qtest_quit(qts1);
331 qtest_quit(qts0);
333 #endif
335 #ifndef _WIN32
336 static void test_stream_fd(void)
338 QTestState *qts0, *qts1;
339 int sock[2];
340 int ret;
342 ret = socketpair(AF_LOCAL, SOCK_STREAM, 0, sock);
343 g_assert_true(ret == 0);
345 qts0 = qtest_initf("-nodefaults -M none "
346 "-netdev stream,id=st0,addr.type=fd,addr.str=%d",
347 sock[0]);
349 EXPECT_STATE(qts0, "st0: index=0,type=stream,unix:\r\n", 0);
351 qts1 = qtest_initf("-nodefaults -M none "
352 "-netdev stream,id=st0,addr.type=fd,addr.str=%d",
353 sock[1]);
355 EXPECT_STATE(qts1, "st0: index=0,type=stream,unix:\r\n", 0);
356 EXPECT_STATE(qts0, "st0: index=0,type=stream,unix:\r\n", 0);
358 qtest_quit(qts1);
359 qtest_quit(qts0);
361 close(sock[0]);
362 close(sock[1]);
364 #endif
366 static void test_dgram_inet(void)
368 QTestState *qts0, *qts1;
369 char *expect;
370 int port[2];
371 int nb;
373 nb = inet_get_free_port_multiple(2, port, false);
374 g_assert_cmpint(nb, ==, 2);
376 qts0 = qtest_initf("-nodefaults -M none "
377 "-netdev dgram,id=st0,"
378 "local.type=inet,local.host=127.0.0.1,local.port=%d,"
379 "remote.type=inet,remote.host=127.0.0.1,remote.port=%d",
380 port[0], port[1]);
382 expect = g_strdup_printf("st0: index=0,type=dgram,"
383 "udp=127.0.0.1:%d/127.0.0.1:%d\r\n",
384 port[0], port[1]);
385 EXPECT_STATE(qts0, expect, 0);
386 g_free(expect);
388 qts1 = qtest_initf("-nodefaults -M none "
389 "-netdev dgram,id=st0,"
390 "local.type=inet,local.host=127.0.0.1,local.port=%d,"
391 "remote.type=inet,remote.host=127.0.0.1,remote.port=%d",
392 port[1], port[0]);
394 expect = g_strdup_printf("st0: index=0,type=dgram,"
395 "udp=127.0.0.1:%d/127.0.0.1:%d\r\n",
396 port[1], port[0]);
397 EXPECT_STATE(qts1, expect, 0);
398 g_free(expect);
400 qtest_quit(qts1);
401 qtest_quit(qts0);
404 #if !defined(_WIN32) && !defined(CONFIG_DARWIN)
405 static void test_dgram_mcast(void)
407 QTestState *qts;
409 qts = qtest_initf("-nodefaults -M none "
410 "-netdev dgram,id=st0,"
411 "remote.type=inet,remote.host=230.0.0.1,remote.port=1234");
413 EXPECT_STATE(qts, "st0: index=0,type=dgram,mcast=230.0.0.1:1234\r\n", 0);
415 qtest_quit(qts);
417 #endif
419 #ifndef _WIN32
420 static void test_dgram_unix(void)
422 QTestState *qts0, *qts1;
423 char *expect;
424 gchar *path0, *path1;
426 path0 = g_strconcat(tmpdir, "/dgram_unix0", NULL);
427 path1 = g_strconcat(tmpdir, "/dgram_unix1", NULL);
429 qts0 = qtest_initf("-nodefaults -M none "
430 "-netdev dgram,id=st0,local.type=unix,local.path=%s,"
431 "remote.type=unix,remote.path=%s",
432 path0, path1);
434 expect = g_strdup_printf("st0: index=0,type=dgram,udp=%s:%s\r\n",
435 path0, path1);
436 EXPECT_STATE(qts0, expect, 0);
437 g_free(expect);
439 qts1 = qtest_initf("-nodefaults -M none "
440 "-netdev dgram,id=st0,local.type=unix,local.path=%s,"
441 "remote.type=unix,remote.path=%s",
442 path1, path0);
445 expect = g_strdup_printf("st0: index=0,type=dgram,udp=%s:%s\r\n",
446 path1, path0);
447 EXPECT_STATE(qts1, expect, 0);
448 g_free(expect);
450 unlink(path0);
451 g_free(path0);
452 unlink(path1);
453 g_free(path1);
455 qtest_quit(qts1);
456 qtest_quit(qts0);
459 static void test_dgram_fd(void)
461 QTestState *qts0, *qts1;
462 char *expect;
463 int ret;
464 int sv[2];
466 ret = socketpair(PF_UNIX, SOCK_DGRAM, 0, sv);
467 g_assert_cmpint(ret, !=, -1);
469 qts0 = qtest_initf("-nodefaults -M none "
470 "-netdev dgram,id=st0,local.type=fd,local.str=%d",
471 sv[0]);
473 expect = g_strdup_printf("st0: index=0,type=dgram,fd=%d unix\r\n", sv[0]);
474 EXPECT_STATE(qts0, expect, 0);
475 g_free(expect);
477 qts1 = qtest_initf("-nodefaults -M none "
478 "-netdev dgram,id=st0,local.type=fd,local.str=%d",
479 sv[1]);
482 expect = g_strdup_printf("st0: index=0,type=dgram,fd=%d unix\r\n", sv[1]);
483 EXPECT_STATE(qts1, expect, 0);
484 g_free(expect);
486 qtest_quit(qts1);
487 qtest_quit(qts0);
489 close(sv[0]);
490 close(sv[1]);
492 #endif
494 int main(int argc, char **argv)
496 int ret;
497 bool has_ipv4, has_ipv6, has_afunix;
498 g_autoptr(GError) err = NULL;
500 socket_init();
501 g_test_init(&argc, &argv, NULL);
503 if (socket_check_protocol_support(&has_ipv4, &has_ipv6) < 0) {
504 g_error("socket_check_protocol_support() failed\n");
507 tmpdir = g_dir_make_tmp("netdev-socket.XXXXXX", &err);
508 if (tmpdir == NULL) {
509 g_error("Can't create temporary directory in %s: %s",
510 g_get_tmp_dir(), err->message);
513 if (has_ipv4) {
514 qtest_add_func("/netdev/stream/inet/ipv4", test_stream_inet_ipv4);
515 qtest_add_func("/netdev/dgram/inet", test_dgram_inet);
516 #if !defined(_WIN32) && !defined(CONFIG_DARWIN)
517 qtest_add_func("/netdev/dgram/mcast", test_dgram_mcast);
518 #endif
520 if (has_ipv6) {
521 qtest_add_func("/netdev/stream/inet/ipv6", test_stream_inet_ipv6);
524 socket_check_afunix_support(&has_afunix);
525 if (has_afunix) {
526 #ifndef _WIN32
527 qtest_add_func("/netdev/dgram/unix", test_dgram_unix);
528 #endif
529 qtest_add_func("/netdev/stream/unix/oneshot", test_stream_unix);
530 qtest_add_func("/netdev/stream/unix/reconnect",
531 test_stream_unix_reconnect);
532 #ifdef CONFIG_LINUX
533 qtest_add_func("/netdev/stream/unix/abstract",
534 test_stream_unix_abstract);
535 #endif
536 #ifndef _WIN32
537 qtest_add_func("/netdev/stream/fd", test_stream_fd);
538 qtest_add_func("/netdev/dgram/fd", test_dgram_fd);
539 #endif
542 ret = g_test_run();
544 g_rmdir(tmpdir);
545 g_free(tmpdir);
547 return ret;