1da668aa1SThomas Huth /*
2da668aa1SThomas Huth * Tests for util/qemu-sockets.c
3da668aa1SThomas Huth *
4da668aa1SThomas Huth * Copyright 2018 Red Hat, Inc.
5da668aa1SThomas Huth *
6da668aa1SThomas Huth * This program is free software; you can redistribute it and/or modify
7da668aa1SThomas Huth * it under the terms of the GNU General Public License as published by
8da668aa1SThomas Huth * the Free Software Foundation; either version 2 of the License, or
9da668aa1SThomas Huth * (at your option) any later version.
10da668aa1SThomas Huth *
11da668aa1SThomas Huth * This program is distributed in the hope that it will be useful,
12da668aa1SThomas Huth * but WITHOUT ANY WARRANTY; without even the implied warranty of
13da668aa1SThomas Huth * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14da668aa1SThomas Huth * GNU General Public License for more details.
15da668aa1SThomas Huth *
16da668aa1SThomas Huth * You should have received a copy of the GNU General Public License
17da668aa1SThomas Huth * along with this library; if not, see <http://www.gnu.org/licenses/>.
18da668aa1SThomas Huth *
19da668aa1SThomas Huth */
20da668aa1SThomas Huth
21da668aa1SThomas Huth #include "qemu/osdep.h"
22da668aa1SThomas Huth #include "qemu/sockets.h"
23da668aa1SThomas Huth #include "qapi/error.h"
24da668aa1SThomas Huth #include "socket-helpers.h"
25da668aa1SThomas Huth #include "monitor/monitor.h"
26da668aa1SThomas Huth
test_fd_is_socket_bad(void)27da668aa1SThomas Huth static void test_fd_is_socket_bad(void)
28da668aa1SThomas Huth {
29da668aa1SThomas Huth char *tmp = g_strdup("qemu-test-util-sockets-XXXXXX");
30da668aa1SThomas Huth int fd = mkstemp(tmp);
31da668aa1SThomas Huth if (fd != 0) {
32da668aa1SThomas Huth unlink(tmp);
33da668aa1SThomas Huth }
34da668aa1SThomas Huth g_free(tmp);
35da668aa1SThomas Huth
36da668aa1SThomas Huth g_assert(fd >= 0);
37da668aa1SThomas Huth
38da668aa1SThomas Huth g_assert(!fd_is_socket(fd));
39da668aa1SThomas Huth close(fd);
40da668aa1SThomas Huth }
41da668aa1SThomas Huth
test_fd_is_socket_good(void)42da668aa1SThomas Huth static void test_fd_is_socket_good(void)
43da668aa1SThomas Huth {
44da668aa1SThomas Huth int fd = qemu_socket(PF_INET, SOCK_STREAM, 0);
45da668aa1SThomas Huth
46da668aa1SThomas Huth g_assert(fd >= 0);
47da668aa1SThomas Huth
48da668aa1SThomas Huth g_assert(fd_is_socket(fd));
49da668aa1SThomas Huth close(fd);
50da668aa1SThomas Huth }
51da668aa1SThomas Huth
52da668aa1SThomas Huth static int mon_fd = -1;
53da668aa1SThomas Huth static const char *mon_fdname;
54da668aa1SThomas Huth __thread Monitor *cur_mon;
55da668aa1SThomas Huth
monitor_get_fd(Monitor * mon,const char * fdname,Error ** errp)56da668aa1SThomas Huth int monitor_get_fd(Monitor *mon, const char *fdname, Error **errp)
57da668aa1SThomas Huth {
58da668aa1SThomas Huth g_assert(cur_mon);
59da668aa1SThomas Huth g_assert(mon == cur_mon);
60da668aa1SThomas Huth if (mon_fd == -1 || !g_str_equal(mon_fdname, fdname)) {
61da668aa1SThomas Huth error_setg(errp, "No fd named %s", fdname);
62da668aa1SThomas Huth return -1;
63da668aa1SThomas Huth }
64da668aa1SThomas Huth return dup(mon_fd);
65da668aa1SThomas Huth }
66da668aa1SThomas Huth
67da668aa1SThomas Huth /*
68da668aa1SThomas Huth * Syms of stubs in libqemuutil.a are discarded at .o file
69da668aa1SThomas Huth * granularity. To replace monitor_get_fd() and monitor_cur(), we
70da668aa1SThomas Huth * must ensure that we also replace any other symbol that is used in
71da668aa1SThomas Huth * the binary and would be taken from the same stub object file,
72da668aa1SThomas Huth * otherwise we get duplicate syms at link time.
73da668aa1SThomas Huth */
monitor_cur(void)74da668aa1SThomas Huth Monitor *monitor_cur(void) { return cur_mon; }
monitor_set_cur(Coroutine * co,Monitor * mon)75130d4824SMarkus Armbruster Monitor *monitor_set_cur(Coroutine *co, Monitor *mon) { abort(); }
monitor_vprintf(Monitor * mon,const char * fmt,va_list ap)76da668aa1SThomas Huth int monitor_vprintf(Monitor *mon, const char *fmt, va_list ap) { abort(); }
77da668aa1SThomas Huth
78da668aa1SThomas Huth #ifndef _WIN32
test_socket_fd_pass_name_good(void)79da668aa1SThomas Huth static void test_socket_fd_pass_name_good(void)
80da668aa1SThomas Huth {
81da668aa1SThomas Huth SocketAddress addr;
82da668aa1SThomas Huth int fd;
83da668aa1SThomas Huth
84da668aa1SThomas Huth cur_mon = g_malloc(1); /* Fake a monitor */
85da668aa1SThomas Huth mon_fdname = "myfd";
86da668aa1SThomas Huth mon_fd = qemu_socket(AF_INET, SOCK_STREAM, 0);
87da668aa1SThomas Huth g_assert_cmpint(mon_fd, >, STDERR_FILENO);
88da668aa1SThomas Huth
89da668aa1SThomas Huth addr.type = SOCKET_ADDRESS_TYPE_FD;
90da668aa1SThomas Huth addr.u.fd.str = g_strdup(mon_fdname);
91da668aa1SThomas Huth
92da668aa1SThomas Huth fd = socket_connect(&addr, &error_abort);
93da668aa1SThomas Huth g_assert_cmpint(fd, !=, -1);
94da668aa1SThomas Huth g_assert_cmpint(fd, !=, mon_fd);
95da668aa1SThomas Huth close(fd);
96da668aa1SThomas Huth
97da668aa1SThomas Huth fd = socket_listen(&addr, 1, &error_abort);
98da668aa1SThomas Huth g_assert_cmpint(fd, !=, -1);
99da668aa1SThomas Huth g_assert_cmpint(fd, !=, mon_fd);
100da668aa1SThomas Huth close(fd);
101da668aa1SThomas Huth
102da668aa1SThomas Huth g_free(addr.u.fd.str);
103da668aa1SThomas Huth mon_fdname = NULL;
104da668aa1SThomas Huth close(mon_fd);
105da668aa1SThomas Huth mon_fd = -1;
106da668aa1SThomas Huth g_free(cur_mon);
107da668aa1SThomas Huth cur_mon = NULL;
108da668aa1SThomas Huth }
109da668aa1SThomas Huth
test_socket_fd_pass_name_bad(void)110da668aa1SThomas Huth static void test_socket_fd_pass_name_bad(void)
111da668aa1SThomas Huth {
112da668aa1SThomas Huth SocketAddress addr;
113da668aa1SThomas Huth Error *err = NULL;
114da668aa1SThomas Huth int fd;
115da668aa1SThomas Huth
116da668aa1SThomas Huth cur_mon = g_malloc(1); /* Fake a monitor */
117da668aa1SThomas Huth mon_fdname = "myfd";
118da668aa1SThomas Huth mon_fd = dup(STDOUT_FILENO);
119da668aa1SThomas Huth g_assert_cmpint(mon_fd, >, STDERR_FILENO);
120da668aa1SThomas Huth
121da668aa1SThomas Huth addr.type = SOCKET_ADDRESS_TYPE_FD;
122da668aa1SThomas Huth addr.u.fd.str = g_strdup(mon_fdname);
123da668aa1SThomas Huth
124da668aa1SThomas Huth fd = socket_connect(&addr, &err);
125da668aa1SThomas Huth g_assert_cmpint(fd, ==, -1);
126da668aa1SThomas Huth error_free_or_abort(&err);
127da668aa1SThomas Huth
128da668aa1SThomas Huth fd = socket_listen(&addr, 1, &err);
129da668aa1SThomas Huth g_assert_cmpint(fd, ==, -1);
130da668aa1SThomas Huth error_free_or_abort(&err);
131da668aa1SThomas Huth
132da668aa1SThomas Huth g_free(addr.u.fd.str);
133da668aa1SThomas Huth mon_fdname = NULL;
134da668aa1SThomas Huth close(mon_fd);
135da668aa1SThomas Huth mon_fd = -1;
136da668aa1SThomas Huth g_free(cur_mon);
137da668aa1SThomas Huth cur_mon = NULL;
138da668aa1SThomas Huth }
139da668aa1SThomas Huth
test_socket_fd_pass_name_nomon(void)140da668aa1SThomas Huth static void test_socket_fd_pass_name_nomon(void)
141da668aa1SThomas Huth {
142da668aa1SThomas Huth SocketAddress addr;
143da668aa1SThomas Huth Error *err = NULL;
144da668aa1SThomas Huth int fd;
145da668aa1SThomas Huth
146da668aa1SThomas Huth g_assert(cur_mon == NULL);
147da668aa1SThomas Huth
148da668aa1SThomas Huth addr.type = SOCKET_ADDRESS_TYPE_FD;
149da668aa1SThomas Huth addr.u.fd.str = g_strdup("myfd");
150da668aa1SThomas Huth
151da668aa1SThomas Huth fd = socket_connect(&addr, &err);
152da668aa1SThomas Huth g_assert_cmpint(fd, ==, -1);
153da668aa1SThomas Huth error_free_or_abort(&err);
154da668aa1SThomas Huth
155da668aa1SThomas Huth fd = socket_listen(&addr, 1, &err);
156da668aa1SThomas Huth g_assert_cmpint(fd, ==, -1);
157da668aa1SThomas Huth error_free_or_abort(&err);
158da668aa1SThomas Huth
159da668aa1SThomas Huth g_free(addr.u.fd.str);
160da668aa1SThomas Huth }
161da668aa1SThomas Huth
162da668aa1SThomas Huth
test_socket_fd_pass_num_good(void)163da668aa1SThomas Huth static void test_socket_fd_pass_num_good(void)
164da668aa1SThomas Huth {
165da668aa1SThomas Huth SocketAddress addr;
166da668aa1SThomas Huth int fd, sfd;
167da668aa1SThomas Huth
168da668aa1SThomas Huth g_assert(cur_mon == NULL);
169da668aa1SThomas Huth sfd = qemu_socket(AF_INET, SOCK_STREAM, 0);
170da668aa1SThomas Huth g_assert_cmpint(sfd, >, STDERR_FILENO);
171da668aa1SThomas Huth
172da668aa1SThomas Huth addr.type = SOCKET_ADDRESS_TYPE_FD;
173da668aa1SThomas Huth addr.u.fd.str = g_strdup_printf("%d", sfd);
174da668aa1SThomas Huth
175da668aa1SThomas Huth fd = socket_connect(&addr, &error_abort);
176da668aa1SThomas Huth g_assert_cmpint(fd, ==, sfd);
177da668aa1SThomas Huth
178da668aa1SThomas Huth fd = socket_listen(&addr, 1, &error_abort);
179da668aa1SThomas Huth g_assert_cmpint(fd, ==, sfd);
180da668aa1SThomas Huth
181da668aa1SThomas Huth g_free(addr.u.fd.str);
182da668aa1SThomas Huth close(sfd);
183da668aa1SThomas Huth }
184da668aa1SThomas Huth
test_socket_fd_pass_num_bad(void)185da668aa1SThomas Huth static void test_socket_fd_pass_num_bad(void)
186da668aa1SThomas Huth {
187da668aa1SThomas Huth SocketAddress addr;
188da668aa1SThomas Huth Error *err = NULL;
189da668aa1SThomas Huth int fd, sfd;
190da668aa1SThomas Huth
191da668aa1SThomas Huth g_assert(cur_mon == NULL);
192da668aa1SThomas Huth sfd = dup(STDOUT_FILENO);
193da668aa1SThomas Huth
194da668aa1SThomas Huth addr.type = SOCKET_ADDRESS_TYPE_FD;
195da668aa1SThomas Huth addr.u.fd.str = g_strdup_printf("%d", sfd);
196da668aa1SThomas Huth
197da668aa1SThomas Huth fd = socket_connect(&addr, &err);
198da668aa1SThomas Huth g_assert_cmpint(fd, ==, -1);
199da668aa1SThomas Huth error_free_or_abort(&err);
200da668aa1SThomas Huth
201da668aa1SThomas Huth fd = socket_listen(&addr, 1, &err);
202da668aa1SThomas Huth g_assert_cmpint(fd, ==, -1);
203da668aa1SThomas Huth error_free_or_abort(&err);
204da668aa1SThomas Huth
205da668aa1SThomas Huth g_free(addr.u.fd.str);
206da668aa1SThomas Huth close(sfd);
207da668aa1SThomas Huth }
208da668aa1SThomas Huth
test_socket_fd_pass_num_nocli(void)209da668aa1SThomas Huth static void test_socket_fd_pass_num_nocli(void)
210da668aa1SThomas Huth {
211da668aa1SThomas Huth SocketAddress addr;
212da668aa1SThomas Huth Error *err = NULL;
213da668aa1SThomas Huth int fd;
214da668aa1SThomas Huth
215da668aa1SThomas Huth cur_mon = g_malloc(1); /* Fake a monitor */
216da668aa1SThomas Huth
217da668aa1SThomas Huth addr.type = SOCKET_ADDRESS_TYPE_FD;
218da668aa1SThomas Huth addr.u.fd.str = g_strdup_printf("%d", STDOUT_FILENO);
219da668aa1SThomas Huth
220da668aa1SThomas Huth fd = socket_connect(&addr, &err);
221da668aa1SThomas Huth g_assert_cmpint(fd, ==, -1);
222da668aa1SThomas Huth error_free_or_abort(&err);
223da668aa1SThomas Huth
224da668aa1SThomas Huth fd = socket_listen(&addr, 1, &err);
225da668aa1SThomas Huth g_assert_cmpint(fd, ==, -1);
226da668aa1SThomas Huth error_free_or_abort(&err);
227da668aa1SThomas Huth
228da668aa1SThomas Huth g_free(addr.u.fd.str);
229da668aa1SThomas Huth }
230da668aa1SThomas Huth #endif
231da668aa1SThomas Huth
232da668aa1SThomas Huth #ifdef CONFIG_LINUX
233da668aa1SThomas Huth
234da668aa1SThomas Huth #define ABSTRACT_SOCKET_VARIANTS 3
235da668aa1SThomas Huth
236da668aa1SThomas Huth typedef struct {
237da668aa1SThomas Huth SocketAddress *server, *client[ABSTRACT_SOCKET_VARIANTS];
238da668aa1SThomas Huth bool expect_connect[ABSTRACT_SOCKET_VARIANTS];
239da668aa1SThomas Huth } abstract_socket_matrix_row;
240da668aa1SThomas Huth
unix_client_thread_func(gpointer user_data)241da668aa1SThomas Huth static gpointer unix_client_thread_func(gpointer user_data)
242da668aa1SThomas Huth {
243da668aa1SThomas Huth abstract_socket_matrix_row *row = user_data;
244da668aa1SThomas Huth Error *err = NULL;
245da668aa1SThomas Huth int i, fd;
246da668aa1SThomas Huth
247da668aa1SThomas Huth for (i = 0; i < ABSTRACT_SOCKET_VARIANTS; i++) {
248da668aa1SThomas Huth if (row->expect_connect[i]) {
249da668aa1SThomas Huth fd = socket_connect(row->client[i], &error_abort);
250da668aa1SThomas Huth g_assert_cmpint(fd, >=, 0);
251da668aa1SThomas Huth } else {
252da668aa1SThomas Huth fd = socket_connect(row->client[i], &err);
253da668aa1SThomas Huth g_assert_cmpint(fd, ==, -1);
254da668aa1SThomas Huth error_free_or_abort(&err);
255da668aa1SThomas Huth }
256da668aa1SThomas Huth close(fd);
257da668aa1SThomas Huth }
258da668aa1SThomas Huth return NULL;
259da668aa1SThomas Huth }
260da668aa1SThomas Huth
test_socket_unix_abstract_row(abstract_socket_matrix_row * test)261da668aa1SThomas Huth static void test_socket_unix_abstract_row(abstract_socket_matrix_row *test)
262da668aa1SThomas Huth {
263da668aa1SThomas Huth int fd, connfd, i;
264da668aa1SThomas Huth GThread *cli;
265da668aa1SThomas Huth struct sockaddr_un un;
266da668aa1SThomas Huth socklen_t len = sizeof(un);
267da668aa1SThomas Huth
268da668aa1SThomas Huth /* Last one must connect, or else accept() below hangs */
269da668aa1SThomas Huth assert(test->expect_connect[ABSTRACT_SOCKET_VARIANTS - 1]);
270da668aa1SThomas Huth
271da668aa1SThomas Huth fd = socket_listen(test->server, 1, &error_abort);
272da668aa1SThomas Huth g_assert_cmpint(fd, >=, 0);
273da668aa1SThomas Huth g_assert(fd_is_socket(fd));
274da668aa1SThomas Huth
275da668aa1SThomas Huth cli = g_thread_new("abstract_unix_client",
276da668aa1SThomas Huth unix_client_thread_func,
277da668aa1SThomas Huth test);
278da668aa1SThomas Huth
279da668aa1SThomas Huth for (i = 0; i < ABSTRACT_SOCKET_VARIANTS; i++) {
280da668aa1SThomas Huth if (test->expect_connect[i]) {
281da668aa1SThomas Huth connfd = accept(fd, (struct sockaddr *)&un, &len);
282da668aa1SThomas Huth g_assert_cmpint(connfd, !=, -1);
283da668aa1SThomas Huth close(connfd);
284da668aa1SThomas Huth }
285da668aa1SThomas Huth }
286da668aa1SThomas Huth
287da668aa1SThomas Huth close(fd);
288da668aa1SThomas Huth g_thread_join(cli);
289da668aa1SThomas Huth }
290da668aa1SThomas Huth
test_socket_unix_abstract(void)291da668aa1SThomas Huth static void test_socket_unix_abstract(void)
292da668aa1SThomas Huth {
293da668aa1SThomas Huth SocketAddress addr, addr_tight, addr_padded;
294da668aa1SThomas Huth abstract_socket_matrix_row matrix[ABSTRACT_SOCKET_VARIANTS] = {
295da668aa1SThomas Huth { &addr,
296da668aa1SThomas Huth { &addr_tight, &addr_padded, &addr },
297da668aa1SThomas Huth { true, false, true } },
298da668aa1SThomas Huth { &addr_tight,
299da668aa1SThomas Huth { &addr_padded, &addr, &addr_tight },
300da668aa1SThomas Huth { false, true, true } },
301da668aa1SThomas Huth { &addr_padded,
302da668aa1SThomas Huth { &addr, &addr_tight, &addr_padded },
303da668aa1SThomas Huth { false, false, true } }
304da668aa1SThomas Huth };
305da668aa1SThomas Huth int i;
306da668aa1SThomas Huth
30758550701SPhilippe Mathieu-Daudé i = g_file_open_tmp("unix-XXXXXX", &addr.u.q_unix.path, NULL);
30858550701SPhilippe Mathieu-Daudé g_assert_true(i >= 0);
30958550701SPhilippe Mathieu-Daudé close(i);
31058550701SPhilippe Mathieu-Daudé
311da668aa1SThomas Huth addr.type = SOCKET_ADDRESS_TYPE_UNIX;
312da668aa1SThomas Huth addr.u.q_unix.has_abstract = true;
313da668aa1SThomas Huth addr.u.q_unix.abstract = true;
314da668aa1SThomas Huth addr.u.q_unix.has_tight = false;
315da668aa1SThomas Huth addr.u.q_unix.tight = false;
316da668aa1SThomas Huth
317da668aa1SThomas Huth addr_tight = addr;
318da668aa1SThomas Huth addr_tight.u.q_unix.has_tight = true;
319da668aa1SThomas Huth addr_tight.u.q_unix.tight = true;
320da668aa1SThomas Huth
321da668aa1SThomas Huth addr_padded = addr;
322da668aa1SThomas Huth addr_padded.u.q_unix.has_tight = true;
323da668aa1SThomas Huth addr_padded.u.q_unix.tight = false;
324da668aa1SThomas Huth
325da668aa1SThomas Huth for (i = 0; i < ABSTRACT_SOCKET_VARIANTS; i++) {
326da668aa1SThomas Huth test_socket_unix_abstract_row(&matrix[i]);
327da668aa1SThomas Huth }
328da668aa1SThomas Huth
329*2a97c057SThomas Huth unlink(addr.u.q_unix.path);
330da668aa1SThomas Huth g_free(addr.u.q_unix.path);
331da668aa1SThomas Huth }
332da668aa1SThomas Huth
333da668aa1SThomas Huth #endif /* CONFIG_LINUX */
334da668aa1SThomas Huth
main(int argc,char ** argv)335da668aa1SThomas Huth int main(int argc, char **argv)
336da668aa1SThomas Huth {
337da668aa1SThomas Huth bool has_ipv4, has_ipv6;
338da668aa1SThomas Huth
339da668aa1SThomas Huth qemu_init_main_loop(&error_abort);
340da668aa1SThomas Huth socket_init();
341da668aa1SThomas Huth
342da668aa1SThomas Huth g_test_init(&argc, &argv, NULL);
343da668aa1SThomas Huth
344da668aa1SThomas Huth /* We're creating actual IPv4/6 sockets, so we should
345da668aa1SThomas Huth * check if the host running tests actually supports
346da668aa1SThomas Huth * each protocol to avoid breaking tests on machines
347da668aa1SThomas Huth * with either IPv4 or IPv6 disabled.
348da668aa1SThomas Huth */
349da668aa1SThomas Huth if (socket_check_protocol_support(&has_ipv4, &has_ipv6) < 0) {
350da668aa1SThomas Huth g_printerr("socket_check_protocol_support() failed\n");
351da668aa1SThomas Huth goto end;
352da668aa1SThomas Huth }
353da668aa1SThomas Huth
354da668aa1SThomas Huth if (has_ipv4) {
355da668aa1SThomas Huth g_test_add_func("/util/socket/is-socket/bad",
356da668aa1SThomas Huth test_fd_is_socket_bad);
357da668aa1SThomas Huth g_test_add_func("/util/socket/is-socket/good",
358da668aa1SThomas Huth test_fd_is_socket_good);
359da668aa1SThomas Huth #ifndef _WIN32
360da668aa1SThomas Huth g_test_add_func("/socket/fd-pass/name/good",
361da668aa1SThomas Huth test_socket_fd_pass_name_good);
362da668aa1SThomas Huth g_test_add_func("/socket/fd-pass/name/bad",
363da668aa1SThomas Huth test_socket_fd_pass_name_bad);
364da668aa1SThomas Huth g_test_add_func("/socket/fd-pass/name/nomon",
365da668aa1SThomas Huth test_socket_fd_pass_name_nomon);
366da668aa1SThomas Huth g_test_add_func("/socket/fd-pass/num/good",
367da668aa1SThomas Huth test_socket_fd_pass_num_good);
368da668aa1SThomas Huth g_test_add_func("/socket/fd-pass/num/bad",
369da668aa1SThomas Huth test_socket_fd_pass_num_bad);
370da668aa1SThomas Huth g_test_add_func("/socket/fd-pass/num/nocli",
371da668aa1SThomas Huth test_socket_fd_pass_num_nocli);
372da668aa1SThomas Huth #endif
373da668aa1SThomas Huth }
374da668aa1SThomas Huth
375da668aa1SThomas Huth #ifdef CONFIG_LINUX
376da668aa1SThomas Huth g_test_add_func("/util/socket/unix-abstract",
377da668aa1SThomas Huth test_socket_unix_abstract);
378da668aa1SThomas Huth #endif
379da668aa1SThomas Huth
380da668aa1SThomas Huth end:
381da668aa1SThomas Huth return g_test_run();
382da668aa1SThomas Huth }
383