xref: /openbmc/qemu/tests/qtest/netdev-socket.c (revision 148fbf0d58a6fa9c6881db28fced8c071c3be100)
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"
14*148fbf0dSLaurent Vivier #include "qapi/qmp/qstring.h"
15*148fbf0dSLaurent Vivier #include "qemu/sockets.h"
16*148fbf0dSLaurent Vivier #include "qapi/qobject-input-visitor.h"
17*148fbf0dSLaurent 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++) {
102c95031a1SLaurent Vivier         closesocket(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 
149*148fbf0dSLaurent Vivier static void wait_stream_connected(QTestState *qts, const char *id,
150*148fbf0dSLaurent Vivier                                   SocketAddress **addr)
151*148fbf0dSLaurent Vivier {
152*148fbf0dSLaurent Vivier     QDict *resp, *data;
153*148fbf0dSLaurent Vivier     QString *qstr;
154*148fbf0dSLaurent Vivier     QObject *obj;
155*148fbf0dSLaurent Vivier     Visitor *v = NULL;
156*148fbf0dSLaurent Vivier 
157*148fbf0dSLaurent Vivier     resp = qtest_qmp_eventwait_ref(qts, "NETDEV_STREAM_CONNECTED");
158*148fbf0dSLaurent Vivier     g_assert_nonnull(resp);
159*148fbf0dSLaurent Vivier     data = qdict_get_qdict(resp, "data");
160*148fbf0dSLaurent Vivier     g_assert_nonnull(data);
161*148fbf0dSLaurent Vivier 
162*148fbf0dSLaurent Vivier     qstr = qobject_to(QString, qdict_get(data, "netdev-id"));
163*148fbf0dSLaurent Vivier     g_assert_nonnull(data);
164*148fbf0dSLaurent Vivier 
165*148fbf0dSLaurent Vivier     g_assert(!strcmp(qstring_get_str(qstr), id));
166*148fbf0dSLaurent Vivier 
167*148fbf0dSLaurent Vivier     obj = qdict_get(data, "addr");
168*148fbf0dSLaurent Vivier 
169*148fbf0dSLaurent Vivier     v = qobject_input_visitor_new(obj);
170*148fbf0dSLaurent Vivier     visit_type_SocketAddress(v, NULL, addr, NULL);
171*148fbf0dSLaurent Vivier     visit_free(v);
172*148fbf0dSLaurent Vivier     qobject_unref(resp);
173*148fbf0dSLaurent Vivier }
174*148fbf0dSLaurent Vivier 
175*148fbf0dSLaurent Vivier static void wait_stream_disconnected(QTestState *qts, const char *id)
176*148fbf0dSLaurent Vivier {
177*148fbf0dSLaurent Vivier     QDict *resp, *data;
178*148fbf0dSLaurent Vivier     QString *qstr;
179*148fbf0dSLaurent Vivier 
180*148fbf0dSLaurent Vivier     resp = qtest_qmp_eventwait_ref(qts, "NETDEV_STREAM_DISCONNECTED");
181*148fbf0dSLaurent Vivier     g_assert_nonnull(resp);
182*148fbf0dSLaurent Vivier     data = qdict_get_qdict(resp, "data");
183*148fbf0dSLaurent Vivier     g_assert_nonnull(data);
184*148fbf0dSLaurent Vivier 
185*148fbf0dSLaurent Vivier     qstr = qobject_to(QString, qdict_get(data, "netdev-id"));
186*148fbf0dSLaurent Vivier     g_assert_nonnull(data);
187*148fbf0dSLaurent Vivier 
188*148fbf0dSLaurent Vivier     g_assert(!strcmp(qstring_get_str(qstr), id));
189*148fbf0dSLaurent Vivier     qobject_unref(resp);
190*148fbf0dSLaurent Vivier }
191*148fbf0dSLaurent Vivier 
192*148fbf0dSLaurent Vivier static void test_stream_inet_reconnect(void)
193*148fbf0dSLaurent Vivier {
194*148fbf0dSLaurent Vivier     QTestState *qts0, *qts1;
195*148fbf0dSLaurent Vivier     int port;
196*148fbf0dSLaurent Vivier     SocketAddress *addr;
197*148fbf0dSLaurent Vivier 
198*148fbf0dSLaurent Vivier     port = inet_get_free_port(false);
199*148fbf0dSLaurent Vivier     qts0 = qtest_initf("-nodefaults -M none "
200*148fbf0dSLaurent Vivier                        "-netdev stream,id=st0,server=true,addr.type=inet,"
201*148fbf0dSLaurent Vivier                        "addr.ipv4=on,addr.ipv6=off,"
202*148fbf0dSLaurent Vivier                        "addr.host=127.0.0.1,addr.port=%d", port);
203*148fbf0dSLaurent Vivier 
204*148fbf0dSLaurent Vivier     EXPECT_STATE(qts0, "st0: index=0,type=stream,\r\n", 0);
205*148fbf0dSLaurent Vivier 
206*148fbf0dSLaurent Vivier     qts1 = qtest_initf("-nodefaults -M none "
207*148fbf0dSLaurent Vivier                        "-netdev stream,server=false,id=st0,addr.type=inet,"
208*148fbf0dSLaurent Vivier                        "addr.ipv4=on,addr.ipv6=off,reconnect=1,"
209*148fbf0dSLaurent Vivier                        "addr.host=127.0.0.1,addr.port=%d", port);
210*148fbf0dSLaurent Vivier 
211*148fbf0dSLaurent Vivier     wait_stream_connected(qts0, "st0", &addr);
212*148fbf0dSLaurent Vivier     g_assert_cmpint(addr->type, ==, SOCKET_ADDRESS_TYPE_INET);
213*148fbf0dSLaurent Vivier     g_assert_cmpstr(addr->u.inet.host, ==, "127.0.0.1");
214*148fbf0dSLaurent Vivier     qapi_free_SocketAddress(addr);
215*148fbf0dSLaurent Vivier 
216*148fbf0dSLaurent Vivier     /* kill server */
217*148fbf0dSLaurent Vivier     qtest_quit(qts0);
218*148fbf0dSLaurent Vivier 
219*148fbf0dSLaurent Vivier     /* check client has been disconnected */
220*148fbf0dSLaurent Vivier     wait_stream_disconnected(qts1, "st0");
221*148fbf0dSLaurent Vivier 
222*148fbf0dSLaurent Vivier     /* restart server */
223*148fbf0dSLaurent Vivier     qts0 = qtest_initf("-nodefaults -M none "
224*148fbf0dSLaurent Vivier                        "-netdev stream,id=st0,server=true,addr.type=inet,"
225*148fbf0dSLaurent Vivier                        "addr.ipv4=on,addr.ipv6=off,"
226*148fbf0dSLaurent Vivier                        "addr.host=127.0.0.1,addr.port=%d", port);
227*148fbf0dSLaurent Vivier 
228*148fbf0dSLaurent Vivier     /* wait connection events*/
229*148fbf0dSLaurent Vivier     wait_stream_connected(qts0, "st0", &addr);
230*148fbf0dSLaurent Vivier     g_assert_cmpint(addr->type, ==, SOCKET_ADDRESS_TYPE_INET);
231*148fbf0dSLaurent Vivier     g_assert_cmpstr(addr->u.inet.host, ==, "127.0.0.1");
232*148fbf0dSLaurent Vivier     qapi_free_SocketAddress(addr);
233*148fbf0dSLaurent Vivier 
234*148fbf0dSLaurent Vivier     wait_stream_connected(qts1, "st0", &addr);
235*148fbf0dSLaurent Vivier     g_assert_cmpint(addr->type, ==, SOCKET_ADDRESS_TYPE_INET);
236*148fbf0dSLaurent Vivier     g_assert_cmpstr(addr->u.inet.host, ==, "127.0.0.1");
237*148fbf0dSLaurent Vivier     g_assert_cmpint(atoi(addr->u.inet.port), ==, port);
238*148fbf0dSLaurent Vivier     qapi_free_SocketAddress(addr);
239*148fbf0dSLaurent Vivier 
240*148fbf0dSLaurent Vivier     qtest_quit(qts1);
241*148fbf0dSLaurent Vivier     qtest_quit(qts0);
242*148fbf0dSLaurent Vivier }
243*148fbf0dSLaurent 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 
364c95031a1SLaurent Vivier     closesocket(sock[0]);
365c95031a1SLaurent Vivier     closesocket(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 
490c95031a1SLaurent Vivier     closesocket(sv[0]);
491c95031a1SLaurent Vivier     closesocket(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
520*148fbf0dSLaurent Vivier         qtest_add_func("/netdev/stream/inet/reconnect",
521*148fbf0dSLaurent 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