xref: /qemu/tests/unit/test-io-channel-socket.c (revision 0ec8384f)
1 /*
2  * QEMU I/O channel sockets test
3  *
4  * Copyright (c) 2015-2016 Red Hat, Inc.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18  *
19  */
20 
21 #include "qemu/osdep.h"
22 #include "io/channel-socket.h"
23 #include "io/channel-util.h"
24 #include "io-channel-helpers.h"
25 #include "socket-helpers.h"
26 #include "qapi/error.h"
27 #include "qemu/module.h"
28 #include "qemu/main-loop.h"
29 
30 
31 static void test_io_channel_set_socket_bufs(QIOChannel *src,
32                                             QIOChannel *dst)
33 {
34     int buflen = 64 * 1024;
35 
36     /*
37      * Make the socket buffers small so that we see
38      * the effects of partial reads/writes
39      */
40     setsockopt(((QIOChannelSocket *)src)->fd,
41                SOL_SOCKET, SO_SNDBUF,
42                (char *)&buflen,
43                sizeof(buflen));
44 
45     setsockopt(((QIOChannelSocket *)dst)->fd,
46                SOL_SOCKET, SO_SNDBUF,
47                (char *)&buflen,
48                sizeof(buflen));
49 }
50 
51 
52 static void test_io_channel_setup_sync(SocketAddress *listen_addr,
53                                        SocketAddress *connect_addr,
54                                        QIOChannel **srv,
55                                        QIOChannel **src,
56                                        QIOChannel **dst)
57 {
58     QIOChannelSocket *lioc;
59 
60     lioc = qio_channel_socket_new();
61     qio_channel_socket_listen_sync(lioc, listen_addr, 1, &error_abort);
62 
63     if (listen_addr->type == SOCKET_ADDRESS_TYPE_INET) {
64         SocketAddress *laddr = qio_channel_socket_get_local_address(
65             lioc, &error_abort);
66 
67         g_free(connect_addr->u.inet.port);
68         connect_addr->u.inet.port = g_strdup(laddr->u.inet.port);
69 
70         qapi_free_SocketAddress(laddr);
71     }
72 
73     *src = QIO_CHANNEL(qio_channel_socket_new());
74     qio_channel_socket_connect_sync(
75         QIO_CHANNEL_SOCKET(*src), connect_addr, &error_abort);
76     qio_channel_set_delay(*src, false);
77 
78     qio_channel_wait(QIO_CHANNEL(lioc), G_IO_IN);
79     *dst = QIO_CHANNEL(qio_channel_socket_accept(lioc, &error_abort));
80     g_assert(*dst);
81 
82     test_io_channel_set_socket_bufs(*src, *dst);
83 
84     *srv = QIO_CHANNEL(lioc);
85 }
86 
87 
88 struct TestIOChannelData {
89     bool err;
90     GMainLoop *loop;
91 };
92 
93 
94 static void test_io_channel_complete(QIOTask *task,
95                                      gpointer opaque)
96 {
97     struct TestIOChannelData *data = opaque;
98     data->err = qio_task_propagate_error(task, NULL);
99     g_main_loop_quit(data->loop);
100 }
101 
102 
103 static void test_io_channel_setup_async(SocketAddress *listen_addr,
104                                         SocketAddress *connect_addr,
105                                         QIOChannel **srv,
106                                         QIOChannel **src,
107                                         QIOChannel **dst)
108 {
109     QIOChannelSocket *lioc;
110     struct TestIOChannelData data;
111 
112     data.loop = g_main_loop_new(g_main_context_default(),
113                                 TRUE);
114 
115     lioc = qio_channel_socket_new();
116     qio_channel_socket_listen_async(
117         lioc, listen_addr, 1,
118         test_io_channel_complete, &data, NULL, NULL);
119 
120     g_main_loop_run(data.loop);
121     g_main_context_iteration(g_main_context_default(), FALSE);
122 
123     g_assert(!data.err);
124 
125     if (listen_addr->type == SOCKET_ADDRESS_TYPE_INET) {
126         SocketAddress *laddr = qio_channel_socket_get_local_address(
127             lioc, &error_abort);
128 
129         g_free(connect_addr->u.inet.port);
130         connect_addr->u.inet.port = g_strdup(laddr->u.inet.port);
131 
132         qapi_free_SocketAddress(laddr);
133     }
134 
135     *src = QIO_CHANNEL(qio_channel_socket_new());
136 
137     qio_channel_socket_connect_async(
138         QIO_CHANNEL_SOCKET(*src), connect_addr,
139         test_io_channel_complete, &data, NULL, NULL);
140 
141     g_main_loop_run(data.loop);
142     g_main_context_iteration(g_main_context_default(), FALSE);
143 
144     g_assert(!data.err);
145 
146     qio_channel_wait(QIO_CHANNEL(lioc), G_IO_IN);
147     *dst = QIO_CHANNEL(qio_channel_socket_accept(lioc, &error_abort));
148     g_assert(*dst);
149 
150     qio_channel_set_delay(*src, false);
151     test_io_channel_set_socket_bufs(*src, *dst);
152 
153     *srv = QIO_CHANNEL(lioc);
154 
155     g_main_loop_unref(data.loop);
156 }
157 
158 
159 static void test_io_channel_socket_path_exists(SocketAddress *addr,
160                                                bool expectExists)
161 {
162     if (addr->type != SOCKET_ADDRESS_TYPE_UNIX) {
163         return;
164     }
165 
166     g_assert(g_file_test(addr->u.q_unix.path,
167                          G_FILE_TEST_EXISTS) == expectExists);
168 }
169 
170 
171 static void test_io_channel(bool async,
172                             SocketAddress *listen_addr,
173                             SocketAddress *connect_addr,
174                             bool passFD)
175 {
176     QIOChannel *src, *dst, *srv;
177     QIOChannelTest *test;
178     if (async) {
179         test_io_channel_setup_async(listen_addr, connect_addr,
180                                     &srv, &src, &dst);
181 
182 #ifndef _WIN32
183         g_assert(!passFD ||
184                  qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS));
185         g_assert(!passFD ||
186                  qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_FD_PASS));
187 #endif
188         g_assert(qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_SHUTDOWN));
189         g_assert(qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_SHUTDOWN));
190 
191         test_io_channel_socket_path_exists(listen_addr, true);
192 
193         test = qio_channel_test_new();
194         qio_channel_test_run_threads(test, true, src, dst);
195         qio_channel_test_validate(test);
196 
197         test_io_channel_socket_path_exists(listen_addr, true);
198 
199         /* unref without close, to ensure finalize() cleans up */
200 
201         object_unref(OBJECT(src));
202         object_unref(OBJECT(dst));
203         test_io_channel_socket_path_exists(listen_addr, true);
204 
205         object_unref(OBJECT(srv));
206         test_io_channel_socket_path_exists(listen_addr, false);
207 
208         test_io_channel_setup_async(listen_addr, connect_addr,
209                                     &srv, &src, &dst);
210 
211 #ifndef _WIN32
212         g_assert(!passFD ||
213                  qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS));
214         g_assert(!passFD ||
215                  qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_FD_PASS));
216 #endif
217         g_assert(qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_SHUTDOWN));
218         g_assert(qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_SHUTDOWN));
219 
220         test = qio_channel_test_new();
221         qio_channel_test_run_threads(test, false, src, dst);
222         qio_channel_test_validate(test);
223 
224         /* close before unref, to ensure finalize copes with already closed */
225 
226         qio_channel_close(src, &error_abort);
227         qio_channel_close(dst, &error_abort);
228         test_io_channel_socket_path_exists(listen_addr, true);
229 
230         object_unref(OBJECT(src));
231         object_unref(OBJECT(dst));
232         test_io_channel_socket_path_exists(listen_addr, true);
233 
234         qio_channel_close(srv, &error_abort);
235         test_io_channel_socket_path_exists(listen_addr, false);
236 
237         object_unref(OBJECT(srv));
238         test_io_channel_socket_path_exists(listen_addr, false);
239     } else {
240         test_io_channel_setup_sync(listen_addr, connect_addr,
241                                    &srv, &src, &dst);
242 
243 #ifndef _WIN32
244         g_assert(!passFD ||
245                  qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS));
246         g_assert(!passFD ||
247                  qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_FD_PASS));
248 #endif
249         g_assert(qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_SHUTDOWN));
250         g_assert(qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_SHUTDOWN));
251 
252         test_io_channel_socket_path_exists(listen_addr, true);
253 
254         test = qio_channel_test_new();
255         qio_channel_test_run_threads(test, true, src, dst);
256         qio_channel_test_validate(test);
257 
258         test_io_channel_socket_path_exists(listen_addr, true);
259 
260         /* unref without close, to ensure finalize() cleans up */
261 
262         object_unref(OBJECT(src));
263         object_unref(OBJECT(dst));
264         test_io_channel_socket_path_exists(listen_addr, true);
265 
266         object_unref(OBJECT(srv));
267         test_io_channel_socket_path_exists(listen_addr, false);
268 
269         test_io_channel_setup_sync(listen_addr, connect_addr,
270                                    &srv, &src, &dst);
271 
272 #ifndef _WIN32
273         g_assert(!passFD ||
274                  qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS));
275         g_assert(!passFD ||
276                  qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_FD_PASS));
277 #endif
278         g_assert(qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_SHUTDOWN));
279         g_assert(qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_SHUTDOWN));
280 
281         test = qio_channel_test_new();
282         qio_channel_test_run_threads(test, false, src, dst);
283         qio_channel_test_validate(test);
284 
285         test_io_channel_socket_path_exists(listen_addr, true);
286 
287         /* close before unref, to ensure finalize copes with already closed */
288 
289         qio_channel_close(src, &error_abort);
290         qio_channel_close(dst, &error_abort);
291         test_io_channel_socket_path_exists(listen_addr, true);
292 
293         object_unref(OBJECT(src));
294         object_unref(OBJECT(dst));
295         test_io_channel_socket_path_exists(listen_addr, true);
296 
297         qio_channel_close(srv, &error_abort);
298         test_io_channel_socket_path_exists(listen_addr, false);
299 
300         object_unref(OBJECT(srv));
301         test_io_channel_socket_path_exists(listen_addr, false);
302     }
303 }
304 
305 
306 static void test_io_channel_ipv4(bool async)
307 {
308     SocketAddress *listen_addr = g_new0(SocketAddress, 1);
309     SocketAddress *connect_addr = g_new0(SocketAddress, 1);
310 
311     listen_addr->type = SOCKET_ADDRESS_TYPE_INET;
312     listen_addr->u.inet = (InetSocketAddress) {
313         .host = g_strdup("127.0.0.1"),
314         .port = NULL, /* Auto-select */
315     };
316 
317     connect_addr->type = SOCKET_ADDRESS_TYPE_INET;
318     connect_addr->u.inet = (InetSocketAddress) {
319         .host = g_strdup("127.0.0.1"),
320         .port = NULL, /* Filled in later */
321     };
322 
323     test_io_channel(async, listen_addr, connect_addr, false);
324 
325     qapi_free_SocketAddress(listen_addr);
326     qapi_free_SocketAddress(connect_addr);
327 }
328 
329 
330 static void test_io_channel_ipv4_sync(void)
331 {
332     return test_io_channel_ipv4(false);
333 }
334 
335 
336 static void test_io_channel_ipv4_async(void)
337 {
338     return test_io_channel_ipv4(true);
339 }
340 
341 
342 static void test_io_channel_ipv6(bool async)
343 {
344     SocketAddress *listen_addr = g_new0(SocketAddress, 1);
345     SocketAddress *connect_addr = g_new0(SocketAddress, 1);
346 
347     listen_addr->type = SOCKET_ADDRESS_TYPE_INET;
348     listen_addr->u.inet = (InetSocketAddress) {
349         .host = g_strdup("::1"),
350         .port = NULL, /* Auto-select */
351     };
352 
353     connect_addr->type = SOCKET_ADDRESS_TYPE_INET;
354     connect_addr->u.inet = (InetSocketAddress) {
355         .host = g_strdup("::1"),
356         .port = NULL, /* Filled in later */
357     };
358 
359     test_io_channel(async, listen_addr, connect_addr, false);
360 
361     qapi_free_SocketAddress(listen_addr);
362     qapi_free_SocketAddress(connect_addr);
363 }
364 
365 
366 static void test_io_channel_ipv6_sync(void)
367 {
368     return test_io_channel_ipv6(false);
369 }
370 
371 
372 static void test_io_channel_ipv6_async(void)
373 {
374     return test_io_channel_ipv6(true);
375 }
376 
377 
378 static void test_io_channel_unix(bool async)
379 {
380     SocketAddress *listen_addr = g_new0(SocketAddress, 1);
381     SocketAddress *connect_addr = g_new0(SocketAddress, 1);
382 
383 #define TEST_SOCKET "test-io-channel-socket.sock"
384     listen_addr->type = SOCKET_ADDRESS_TYPE_UNIX;
385     listen_addr->u.q_unix.path = g_strdup(TEST_SOCKET);
386 
387     connect_addr->type = SOCKET_ADDRESS_TYPE_UNIX;
388     connect_addr->u.q_unix.path = g_strdup(TEST_SOCKET);
389 
390     test_io_channel(async, listen_addr, connect_addr, true);
391 
392     qapi_free_SocketAddress(listen_addr);
393     qapi_free_SocketAddress(connect_addr);
394 }
395 
396 
397 static void test_io_channel_unix_sync(void)
398 {
399     return test_io_channel_unix(false);
400 }
401 
402 
403 static void test_io_channel_unix_async(void)
404 {
405     return test_io_channel_unix(true);
406 }
407 
408 #ifndef _WIN32
409 static void test_io_channel_unix_fd_pass(void)
410 {
411     SocketAddress *listen_addr = g_new0(SocketAddress, 1);
412     SocketAddress *connect_addr = g_new0(SocketAddress, 1);
413     QIOChannel *src, *dst, *srv;
414     int testfd;
415     int fdsend[3];
416     int *fdrecv = NULL;
417     size_t nfdrecv = 0;
418     size_t i;
419     char bufsend[12], bufrecv[12];
420     struct iovec iosend[1], iorecv[1];
421 
422 #define TEST_SOCKET "test-io-channel-socket.sock"
423 #define TEST_FILE "test-io-channel-socket.txt"
424 
425     testfd = open(TEST_FILE, O_RDWR|O_TRUNC|O_CREAT, 0700);
426     g_assert(testfd != -1);
427     fdsend[0] = testfd;
428     fdsend[1] = testfd;
429     fdsend[2] = testfd;
430 
431     listen_addr->type = SOCKET_ADDRESS_TYPE_UNIX;
432     listen_addr->u.q_unix.path = g_strdup(TEST_SOCKET);
433 
434     connect_addr->type = SOCKET_ADDRESS_TYPE_UNIX;
435     connect_addr->u.q_unix.path = g_strdup(TEST_SOCKET);
436 
437     test_io_channel_setup_sync(listen_addr, connect_addr, &srv, &src, &dst);
438 
439     memcpy(bufsend, "Hello World", G_N_ELEMENTS(bufsend));
440 
441     iosend[0].iov_base = bufsend;
442     iosend[0].iov_len = G_N_ELEMENTS(bufsend);
443 
444     iorecv[0].iov_base = bufrecv;
445     iorecv[0].iov_len = G_N_ELEMENTS(bufrecv);
446 
447     g_assert(qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS));
448     g_assert(qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_FD_PASS));
449 
450     qio_channel_writev_full(src,
451                             iosend,
452                             G_N_ELEMENTS(iosend),
453                             fdsend,
454                             G_N_ELEMENTS(fdsend),
455                             0,
456                             &error_abort);
457 
458     qio_channel_readv_full(dst,
459                            iorecv,
460                            G_N_ELEMENTS(iorecv),
461                            &fdrecv,
462                            &nfdrecv,
463                            0,
464                            &error_abort);
465 
466     g_assert(nfdrecv == G_N_ELEMENTS(fdsend));
467     /* Each recvd FD should be different from sent FD */
468     for (i = 0; i < nfdrecv; i++) {
469         g_assert_cmpint(fdrecv[i], !=, testfd);
470     }
471     /* Each recvd FD should be different from each other */
472     g_assert_cmpint(fdrecv[0], !=, fdrecv[1]);
473     g_assert_cmpint(fdrecv[0], !=, fdrecv[2]);
474     g_assert_cmpint(fdrecv[1], !=, fdrecv[2]);
475 
476     /* Check the I/O buf we sent at the same time matches */
477     g_assert(memcmp(bufsend, bufrecv, G_N_ELEMENTS(bufsend)) == 0);
478 
479     /* Write some data into the FD we received */
480     g_assert(write(fdrecv[0], bufsend, G_N_ELEMENTS(bufsend)) ==
481              G_N_ELEMENTS(bufsend));
482 
483     /* Read data from the original FD and make sure it matches */
484     memset(bufrecv, 0, G_N_ELEMENTS(bufrecv));
485     g_assert(lseek(testfd, 0, SEEK_SET) == 0);
486     g_assert(read(testfd, bufrecv, G_N_ELEMENTS(bufrecv)) ==
487              G_N_ELEMENTS(bufrecv));
488     g_assert(memcmp(bufsend, bufrecv, G_N_ELEMENTS(bufsend)) == 0);
489 
490     object_unref(OBJECT(src));
491     object_unref(OBJECT(dst));
492     object_unref(OBJECT(srv));
493     qapi_free_SocketAddress(listen_addr);
494     qapi_free_SocketAddress(connect_addr);
495     unlink(TEST_SOCKET);
496     unlink(TEST_FILE);
497     close(testfd);
498     for (i = 0; i < nfdrecv; i++) {
499         close(fdrecv[i]);
500     }
501     g_free(fdrecv);
502 }
503 #endif /* _WIN32 */
504 
505 static void test_io_channel_unix_listen_cleanup(void)
506 {
507     QIOChannelSocket *ioc;
508     struct sockaddr_un un;
509     int sock;
510 
511 #define TEST_SOCKET "test-io-channel-socket.sock"
512 
513     ioc = qio_channel_socket_new();
514 
515     /* Manually bind ioc without calling the qio api to avoid setting
516      * the LISTEN feature */
517     sock = qemu_socket(PF_UNIX, SOCK_STREAM, 0);
518     memset(&un, 0, sizeof(un));
519     un.sun_family = AF_UNIX;
520     snprintf(un.sun_path, sizeof(un.sun_path), "%s", TEST_SOCKET);
521     unlink(TEST_SOCKET);
522     bind(sock, (struct sockaddr *)&un, sizeof(un));
523     ioc->fd = sock;
524     ioc->localAddrLen = sizeof(ioc->localAddr);
525     getsockname(sock, (struct sockaddr *)&ioc->localAddr,
526                 &ioc->localAddrLen);
527 
528     g_assert(g_file_test(TEST_SOCKET, G_FILE_TEST_EXISTS));
529     object_unref(OBJECT(ioc));
530     g_assert(g_file_test(TEST_SOCKET, G_FILE_TEST_EXISTS));
531 
532     unlink(TEST_SOCKET);
533 }
534 
535 static void test_io_channel_ipv4_fd(void)
536 {
537     QIOChannel *ioc;
538     int fd = -1;
539     struct sockaddr_in sa = {
540         .sin_family = AF_INET,
541         .sin_addr = {
542             .s_addr =  htonl(INADDR_LOOPBACK),
543         }
544         /* Leave port unset for auto-assign */
545     };
546     socklen_t salen = sizeof(sa);
547 
548     fd = socket(AF_INET, SOCK_STREAM, 0);
549     g_assert_cmpint(fd, >, -1);
550 
551     g_assert_cmpint(bind(fd, (struct sockaddr *)&sa, salen), ==, 0);
552 
553     ioc = qio_channel_new_fd(fd, &error_abort);
554 
555     g_assert_cmpstr(object_get_typename(OBJECT(ioc)),
556                     ==,
557                     TYPE_QIO_CHANNEL_SOCKET);
558 
559     object_unref(OBJECT(ioc));
560 }
561 
562 
563 int main(int argc, char **argv)
564 {
565     bool has_ipv4, has_ipv6, has_afunix;
566 
567     module_call_init(MODULE_INIT_QOM);
568     qemu_init_main_loop(&error_abort);
569     socket_init();
570 
571     g_test_init(&argc, &argv, NULL);
572 
573     /* We're creating actual IPv4/6 sockets, so we should
574      * check if the host running tests actually supports
575      * each protocol to avoid breaking tests on machines
576      * with either IPv4 or IPv6 disabled.
577      */
578     if (socket_check_protocol_support(&has_ipv4, &has_ipv6) < 0) {
579         g_printerr("socket_check_protocol_support() failed\n");
580         goto end;
581     }
582 
583     if (has_ipv4) {
584         g_test_add_func("/io/channel/socket/ipv4-sync",
585                         test_io_channel_ipv4_sync);
586         g_test_add_func("/io/channel/socket/ipv4-async",
587                         test_io_channel_ipv4_async);
588         g_test_add_func("/io/channel/socket/ipv4-fd",
589                         test_io_channel_ipv4_fd);
590     }
591     if (has_ipv6) {
592         g_test_add_func("/io/channel/socket/ipv6-sync",
593                         test_io_channel_ipv6_sync);
594         g_test_add_func("/io/channel/socket/ipv6-async",
595                         test_io_channel_ipv6_async);
596     }
597 
598     socket_check_afunix_support(&has_afunix);
599     if (has_afunix) {
600         g_test_add_func("/io/channel/socket/unix-sync",
601                         test_io_channel_unix_sync);
602         g_test_add_func("/io/channel/socket/unix-async",
603                         test_io_channel_unix_async);
604 #ifndef _WIN32
605         g_test_add_func("/io/channel/socket/unix-fd-pass",
606                         test_io_channel_unix_fd_pass);
607 #endif
608         g_test_add_func("/io/channel/socket/unix-listen-cleanup",
609                         test_io_channel_unix_listen_cleanup);
610     }
611 
612 end:
613     return g_test_run();
614 }
615