2 * QTest testcase for netdev stream and dgram
4 * Copyright (c) 2022 Red Hat, Inc.
6 * SPDX-License-Identifier: GPL-2.0-or-later
9 #include "qemu/osdep.h"
10 #include "qemu/sockets.h"
11 #include <glib/gstdio.h>
12 #include "../unit/socket-helpers.h"
15 #define CONNECTION_TIMEOUT 5
17 #define EXPECT_STATE(q, e, t) \
20 g_test_timer_start(); \
23 resp = qtest_hmp(q, "info network"); \
25 strrchr(resp, t)[0] = 0; \
27 if (g_str_equal(resp, e)) { \
30 } while (g_test_timer_elapsed() < CONNECTION_TIMEOUT); \
31 g_assert_cmpstr(resp, ==, e); \
37 static int inet_get_free_port_socket_ipv4(int sock
)
39 struct sockaddr_in addr
;
42 memset(&addr
, 0, sizeof(addr
));
43 addr
.sin_family
= AF_INET
;
44 addr
.sin_addr
.s_addr
= INADDR_ANY
;
46 if (bind(sock
, (struct sockaddr
*)&addr
, sizeof(addr
)) < 0) {
51 if (getsockname(sock
, (struct sockaddr
*)&addr
, &len
) < 0) {
55 return ntohs(addr
.sin_port
);
58 static int inet_get_free_port_socket_ipv6(int sock
)
60 struct sockaddr_in6 addr
;
63 memset(&addr
, 0, sizeof(addr
));
64 addr
.sin6_family
= AF_INET6
;
65 addr
.sin6_addr
= in6addr_any
;
67 if (bind(sock
, (struct sockaddr
*)&addr
, sizeof(addr
)) < 0) {
72 if (getsockname(sock
, (struct sockaddr
*)&addr
, &len
) < 0) {
76 return ntohs(addr
.sin6_port
);
79 static int inet_get_free_port_multiple(int nb
, int *port
, bool ipv6
)
84 for (i
= 0; i
< nb
; i
++) {
85 sock
[i
] = socket(ipv6
? AF_INET6
: AF_INET
, SOCK_STREAM
, 0);
89 port
[i
] = ipv6
? inet_get_free_port_socket_ipv6(sock
[i
]) :
90 inet_get_free_port_socket_ipv4(sock
[i
]);
97 for (i
= 0; i
< nb
; i
++) {
104 static int inet_get_free_port(bool ipv6
)
108 nb
= inet_get_free_port_multiple(1, &port
, ipv6
);
109 g_assert_cmpint(nb
, ==, 1);
114 static void test_stream_inet_ipv4(void)
116 QTestState
*qts0
, *qts1
;
120 port
= inet_get_free_port(false);
121 qts0
= qtest_initf("-nodefaults -M none "
122 "-netdev stream,id=st0,server=true,addr.type=inet,"
123 "addr.ipv4=on,addr.ipv6=off,"
124 "addr.host=127.0.0.1,addr.port=%d", port
);
126 EXPECT_STATE(qts0
, "st0: index=0,type=stream,\r\n", 0);
128 qts1
= qtest_initf("-nodefaults -M none "
129 "-netdev stream,server=false,id=st0,addr.type=inet,"
130 "addr.ipv4=on,addr.ipv6=off,"
131 "addr.host=127.0.0.1,addr.port=%d", port
);
133 expect
= g_strdup_printf("st0: index=0,type=stream,tcp:127.0.0.1:%d\r\n",
135 EXPECT_STATE(qts1
, expect
, 0);
138 /* the port is unknown, check only the address */
139 EXPECT_STATE(qts0
, "st0: index=0,type=stream,tcp:127.0.0.1", ':');
145 static void test_stream_inet_ipv6(void)
147 QTestState
*qts0
, *qts1
;
151 port
= inet_get_free_port(true);
152 qts0
= qtest_initf("-nodefaults -M none "
153 "-netdev stream,id=st0,server=true,addr.type=inet,"
154 "addr.ipv4=off,addr.ipv6=on,"
155 "addr.host=::1,addr.port=%d", port
);
157 EXPECT_STATE(qts0
, "st0: index=0,type=stream,\r\n", 0);
159 qts1
= qtest_initf("-nodefaults -M none "
160 "-netdev stream,server=false,id=st0,addr.type=inet,"
161 "addr.ipv4=off,addr.ipv6=on,"
162 "addr.host=::1,addr.port=%d", port
);
164 expect
= g_strdup_printf("st0: index=0,type=stream,tcp:::1:%d\r\n",
166 EXPECT_STATE(qts1
, expect
, 0);
169 /* the port is unknown, check only the address */
170 EXPECT_STATE(qts0
, "st0: index=0,type=stream,tcp:::1", ':');
176 static void test_stream_unix(void)
178 QTestState
*qts0
, *qts1
;
182 path
= g_strconcat(tmpdir
, "/stream_unix", NULL
);
184 qts0
= qtest_initf("-nodefaults -M none "
185 "-netdev stream,id=st0,server=true,"
186 "addr.type=unix,addr.path=%s,",
189 EXPECT_STATE(qts0
, "st0: index=0,type=stream,\r\n", 0);
191 qts1
= qtest_initf("-nodefaults -M none "
192 "-netdev stream,id=st0,server=false,"
193 "addr.type=unix,addr.path=%s",
196 expect
= g_strdup_printf("st0: index=0,type=stream,unix:%s\r\n", path
);
197 EXPECT_STATE(qts1
, expect
, 0);
198 EXPECT_STATE(qts0
, expect
, 0);
207 static void test_stream_unix_abstract(void)
209 QTestState
*qts0
, *qts1
;
213 path
= g_strconcat(tmpdir
, "/stream_unix_abstract", NULL
);
215 qts0
= qtest_initf("-nodefaults -M none "
216 "-netdev stream,id=st0,server=true,"
217 "addr.type=unix,addr.path=%s,"
221 EXPECT_STATE(qts0
, "st0: index=0,type=stream,\r\n", 0);
223 qts1
= qtest_initf("-nodefaults -M none "
224 "-netdev stream,id=st0,server=false,"
225 "addr.type=unix,addr.path=%s,addr.abstract=on",
228 expect
= g_strdup_printf("st0: index=0,type=stream,unix:%s\r\n", path
);
229 EXPECT_STATE(qts1
, expect
, 0);
230 EXPECT_STATE(qts0
, expect
, 0);
240 static void test_stream_fd(void)
242 QTestState
*qts0
, *qts1
;
246 ret
= socketpair(AF_LOCAL
, SOCK_STREAM
, 0, sock
);
247 g_assert_true(ret
== 0);
249 qts0
= qtest_initf("-nodefaults -M none "
250 "-netdev stream,id=st0,addr.type=fd,addr.str=%d",
253 EXPECT_STATE(qts0
, "st0: index=0,type=stream,unix:\r\n", 0);
255 qts1
= qtest_initf("-nodefaults -M none "
256 "-netdev stream,id=st0,addr.type=fd,addr.str=%d",
259 EXPECT_STATE(qts1
, "st0: index=0,type=stream,unix:\r\n", 0);
260 EXPECT_STATE(qts0
, "st0: index=0,type=stream,unix:\r\n", 0);
265 closesocket(sock
[0]);
266 closesocket(sock
[1]);
270 static void test_dgram_inet(void)
272 QTestState
*qts0
, *qts1
;
277 nb
= inet_get_free_port_multiple(2, port
, false);
278 g_assert_cmpint(nb
, ==, 2);
280 qts0
= qtest_initf("-nodefaults -M none "
281 "-netdev dgram,id=st0,"
282 "local.type=inet,local.host=127.0.0.1,local.port=%d,"
283 "remote.type=inet,remote.host=127.0.0.1,remote.port=%d",
286 expect
= g_strdup_printf("st0: index=0,type=dgram,"
287 "udp=127.0.0.1:%d/127.0.0.1:%d\r\n",
289 EXPECT_STATE(qts0
, expect
, 0);
292 qts1
= qtest_initf("-nodefaults -M none "
293 "-netdev dgram,id=st0,"
294 "local.type=inet,local.host=127.0.0.1,local.port=%d,"
295 "remote.type=inet,remote.host=127.0.0.1,remote.port=%d",
298 expect
= g_strdup_printf("st0: index=0,type=dgram,"
299 "udp=127.0.0.1:%d/127.0.0.1:%d\r\n",
301 EXPECT_STATE(qts1
, expect
, 0);
309 static void test_dgram_mcast(void)
313 qts
= qtest_initf("-nodefaults -M none "
314 "-netdev dgram,id=st0,"
315 "remote.type=inet,remote.host=230.0.0.1,remote.port=1234");
317 EXPECT_STATE(qts
, "st0: index=0,type=dgram,mcast=230.0.0.1:1234\r\n", 0);
322 static void test_dgram_unix(void)
324 QTestState
*qts0
, *qts1
;
326 gchar
*path0
, *path1
;
328 path0
= g_strconcat(tmpdir
, "/dgram_unix0", NULL
);
329 path1
= g_strconcat(tmpdir
, "/dgram_unix1", NULL
);
331 qts0
= qtest_initf("-nodefaults -M none "
332 "-netdev dgram,id=st0,local.type=unix,local.path=%s,"
333 "remote.type=unix,remote.path=%s",
336 expect
= g_strdup_printf("st0: index=0,type=dgram,udp=%s:%s\r\n",
338 EXPECT_STATE(qts0
, expect
, 0);
341 qts1
= qtest_initf("-nodefaults -M none "
342 "-netdev dgram,id=st0,local.type=unix,local.path=%s,"
343 "remote.type=unix,remote.path=%s",
347 expect
= g_strdup_printf("st0: index=0,type=dgram,udp=%s:%s\r\n",
349 EXPECT_STATE(qts1
, expect
, 0);
361 static void test_dgram_fd(void)
363 QTestState
*qts0
, *qts1
;
368 ret
= socketpair(PF_UNIX
, SOCK_DGRAM
, 0, sv
);
369 g_assert_cmpint(ret
, !=, -1);
371 qts0
= qtest_initf("-nodefaults -M none "
372 "-netdev dgram,id=st0,local.type=fd,local.str=%d",
375 expect
= g_strdup_printf("st0: index=0,type=dgram,fd=%d unix\r\n", sv
[0]);
376 EXPECT_STATE(qts0
, expect
, 0);
379 qts1
= qtest_initf("-nodefaults -M none "
380 "-netdev dgram,id=st0,local.type=fd,local.str=%d",
384 expect
= g_strdup_printf("st0: index=0,type=dgram,fd=%d unix\r\n", sv
[1]);
385 EXPECT_STATE(qts1
, expect
, 0);
396 int main(int argc
, char **argv
)
399 bool has_ipv4
, has_ipv6
, has_afunix
;
400 g_autoptr(GError
) err
= NULL
;
403 g_test_init(&argc
, &argv
, NULL
);
405 if (socket_check_protocol_support(&has_ipv4
, &has_ipv6
) < 0) {
406 g_error("socket_check_protocol_support() failed\n");
409 tmpdir
= g_dir_make_tmp("netdev-socket.XXXXXX", &err
);
410 if (tmpdir
== NULL
) {
411 g_error("Can't create temporary directory in %s: %s",
412 g_get_tmp_dir(), err
->message
);
416 qtest_add_func("/netdev/stream/inet/ipv4", test_stream_inet_ipv4
);
417 qtest_add_func("/netdev/dgram/inet", test_dgram_inet
);
419 qtest_add_func("/netdev/dgram/mcast", test_dgram_mcast
);
423 qtest_add_func("/netdev/stream/inet/ipv6", test_stream_inet_ipv6
);
426 socket_check_afunix_support(&has_afunix
);
429 qtest_add_func("/netdev/dgram/unix", test_dgram_unix
);
431 qtest_add_func("/netdev/stream/unix", test_stream_unix
);
433 qtest_add_func("/netdev/stream/unix/abstract",
434 test_stream_unix_abstract
);
437 qtest_add_func("/netdev/stream/fd", test_stream_fd
);
438 qtest_add_func("/netdev/dgram/fd", test_dgram_fd
);