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
inet_get_free_port_socket_ipv4(int sock)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
inet_get_free_port_socket_ipv6(int sock)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
inet_get_free_port_multiple(int nb,int * port,bool ipv6)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
inet_get_free_port(bool ipv6)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
test_stream_inet_ipv4(void)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
130cc91ca64SDaniel 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
wait_stream_connected(QTestState * qts,const char * id,SocketAddress ** addr)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
wait_stream_disconnected(QTestState * qts,const char * id)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
test_stream_unix_reconnect(void)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
203cc91ca64SDaniel 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,"
207*c40e962dSDaniil Tatianin "addr.path=%s,reconnect-ms=1000", 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
test_stream_inet_ipv6(void)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
253cc91ca64SDaniel 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
test_stream_unix(void)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
285cc91ca64SDaniel 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
test_stream_unix_abstract(void)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
317cc91ca64SDaniel 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
test_stream_fd(void)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
test_dgram_inet(void)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)
test_dgram_mcast(void)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
test_dgram_unix(void)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
test_dgram_fd(void)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
main(int argc,char ** argv)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
529f51d3fb1SDaniel P. Berrangé qtest_add_func("/netdev/stream/unix/oneshot", 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