xref: /openbmc/qemu/tests/qtest/netdev-socket.c (revision 58d49b5895f2e0b5cfe4b2901bf24f3320b74f29)
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