xref: /qemu/tests/unit/test-io-channel-socket.c (revision c4b8ffcb)
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         g_assert(!passFD ||
183                  qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS));
184         g_assert(!passFD ||
185                  qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_FD_PASS));
186         g_assert(qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_SHUTDOWN));
187         g_assert(qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_SHUTDOWN));
188 
189         test_io_channel_socket_path_exists(listen_addr, true);
190 
191         test = qio_channel_test_new();
192         qio_channel_test_run_threads(test, true, src, dst);
193         qio_channel_test_validate(test);
194 
195         test_io_channel_socket_path_exists(listen_addr, true);
196 
197         /* unref without close, to ensure finalize() cleans up */
198 
199         object_unref(OBJECT(src));
200         object_unref(OBJECT(dst));
201         test_io_channel_socket_path_exists(listen_addr, true);
202 
203         object_unref(OBJECT(srv));
204         test_io_channel_socket_path_exists(listen_addr, false);
205 
206         test_io_channel_setup_async(listen_addr, connect_addr,
207                                     &srv, &src, &dst);
208 
209         g_assert(!passFD ||
210                  qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS));
211         g_assert(!passFD ||
212                  qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_FD_PASS));
213         g_assert(qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_SHUTDOWN));
214         g_assert(qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_SHUTDOWN));
215 
216         test = qio_channel_test_new();
217         qio_channel_test_run_threads(test, false, src, dst);
218         qio_channel_test_validate(test);
219 
220         /* close before unref, to ensure finalize copes with already closed */
221 
222         qio_channel_close(src, &error_abort);
223         qio_channel_close(dst, &error_abort);
224         test_io_channel_socket_path_exists(listen_addr, true);
225 
226         object_unref(OBJECT(src));
227         object_unref(OBJECT(dst));
228         test_io_channel_socket_path_exists(listen_addr, true);
229 
230         qio_channel_close(srv, &error_abort);
231         test_io_channel_socket_path_exists(listen_addr, false);
232 
233         object_unref(OBJECT(srv));
234         test_io_channel_socket_path_exists(listen_addr, false);
235     } else {
236         test_io_channel_setup_sync(listen_addr, connect_addr,
237                                    &srv, &src, &dst);
238 
239         g_assert(!passFD ||
240                  qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS));
241         g_assert(!passFD ||
242                  qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_FD_PASS));
243         g_assert(qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_SHUTDOWN));
244         g_assert(qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_SHUTDOWN));
245 
246         test_io_channel_socket_path_exists(listen_addr, true);
247 
248         test = qio_channel_test_new();
249         qio_channel_test_run_threads(test, true, src, dst);
250         qio_channel_test_validate(test);
251 
252         test_io_channel_socket_path_exists(listen_addr, true);
253 
254         /* unref without close, to ensure finalize() cleans up */
255 
256         object_unref(OBJECT(src));
257         object_unref(OBJECT(dst));
258         test_io_channel_socket_path_exists(listen_addr, true);
259 
260         object_unref(OBJECT(srv));
261         test_io_channel_socket_path_exists(listen_addr, false);
262 
263         test_io_channel_setup_sync(listen_addr, connect_addr,
264                                    &srv, &src, &dst);
265 
266         g_assert(!passFD ||
267                  qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS));
268         g_assert(!passFD ||
269                  qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_FD_PASS));
270         g_assert(qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_SHUTDOWN));
271         g_assert(qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_SHUTDOWN));
272 
273         test = qio_channel_test_new();
274         qio_channel_test_run_threads(test, false, src, dst);
275         qio_channel_test_validate(test);
276 
277         test_io_channel_socket_path_exists(listen_addr, true);
278 
279         /* close before unref, to ensure finalize copes with already closed */
280 
281         qio_channel_close(src, &error_abort);
282         qio_channel_close(dst, &error_abort);
283         test_io_channel_socket_path_exists(listen_addr, true);
284 
285         object_unref(OBJECT(src));
286         object_unref(OBJECT(dst));
287         test_io_channel_socket_path_exists(listen_addr, true);
288 
289         qio_channel_close(srv, &error_abort);
290         test_io_channel_socket_path_exists(listen_addr, false);
291 
292         object_unref(OBJECT(srv));
293         test_io_channel_socket_path_exists(listen_addr, false);
294     }
295 }
296 
297 
298 static void test_io_channel_ipv4(bool async)
299 {
300     SocketAddress *listen_addr = g_new0(SocketAddress, 1);
301     SocketAddress *connect_addr = g_new0(SocketAddress, 1);
302 
303     listen_addr->type = SOCKET_ADDRESS_TYPE_INET;
304     listen_addr->u.inet = (InetSocketAddress) {
305         .host = g_strdup("127.0.0.1"),
306         .port = NULL, /* Auto-select */
307     };
308 
309     connect_addr->type = SOCKET_ADDRESS_TYPE_INET;
310     connect_addr->u.inet = (InetSocketAddress) {
311         .host = g_strdup("127.0.0.1"),
312         .port = NULL, /* Filled in later */
313     };
314 
315     test_io_channel(async, listen_addr, connect_addr, false);
316 
317     qapi_free_SocketAddress(listen_addr);
318     qapi_free_SocketAddress(connect_addr);
319 }
320 
321 
322 static void test_io_channel_ipv4_sync(void)
323 {
324     return test_io_channel_ipv4(false);
325 }
326 
327 
328 static void test_io_channel_ipv4_async(void)
329 {
330     return test_io_channel_ipv4(true);
331 }
332 
333 
334 static void test_io_channel_ipv6(bool async)
335 {
336     SocketAddress *listen_addr = g_new0(SocketAddress, 1);
337     SocketAddress *connect_addr = g_new0(SocketAddress, 1);
338 
339     listen_addr->type = SOCKET_ADDRESS_TYPE_INET;
340     listen_addr->u.inet = (InetSocketAddress) {
341         .host = g_strdup("::1"),
342         .port = NULL, /* Auto-select */
343     };
344 
345     connect_addr->type = SOCKET_ADDRESS_TYPE_INET;
346     connect_addr->u.inet = (InetSocketAddress) {
347         .host = g_strdup("::1"),
348         .port = NULL, /* Filled in later */
349     };
350 
351     test_io_channel(async, listen_addr, connect_addr, false);
352 
353     qapi_free_SocketAddress(listen_addr);
354     qapi_free_SocketAddress(connect_addr);
355 }
356 
357 
358 static void test_io_channel_ipv6_sync(void)
359 {
360     return test_io_channel_ipv6(false);
361 }
362 
363 
364 static void test_io_channel_ipv6_async(void)
365 {
366     return test_io_channel_ipv6(true);
367 }
368 
369 
370 #ifndef _WIN32
371 static void test_io_channel_unix(bool async)
372 {
373     SocketAddress *listen_addr = g_new0(SocketAddress, 1);
374     SocketAddress *connect_addr = g_new0(SocketAddress, 1);
375 
376 #define TEST_SOCKET "test-io-channel-socket.sock"
377     listen_addr->type = SOCKET_ADDRESS_TYPE_UNIX;
378     listen_addr->u.q_unix.path = g_strdup(TEST_SOCKET);
379 
380     connect_addr->type = SOCKET_ADDRESS_TYPE_UNIX;
381     connect_addr->u.q_unix.path = g_strdup(TEST_SOCKET);
382 
383     test_io_channel(async, listen_addr, connect_addr, true);
384 
385     qapi_free_SocketAddress(listen_addr);
386     qapi_free_SocketAddress(connect_addr);
387 }
388 
389 
390 static void test_io_channel_unix_sync(void)
391 {
392     return test_io_channel_unix(false);
393 }
394 
395 
396 static void test_io_channel_unix_async(void)
397 {
398     return test_io_channel_unix(true);
399 }
400 
401 static void test_io_channel_unix_fd_pass(void)
402 {
403     SocketAddress *listen_addr = g_new0(SocketAddress, 1);
404     SocketAddress *connect_addr = g_new0(SocketAddress, 1);
405     QIOChannel *src, *dst, *srv;
406     int testfd;
407     int fdsend[3];
408     int *fdrecv = NULL;
409     size_t nfdrecv = 0;
410     size_t i;
411     char bufsend[12], bufrecv[12];
412     struct iovec iosend[1], iorecv[1];
413 
414 #define TEST_SOCKET "test-io-channel-socket.sock"
415 #define TEST_FILE "test-io-channel-socket.txt"
416 
417     testfd = open(TEST_FILE, O_RDWR|O_TRUNC|O_CREAT, 0700);
418     g_assert(testfd != -1);
419     fdsend[0] = testfd;
420     fdsend[1] = testfd;
421     fdsend[2] = testfd;
422 
423     listen_addr->type = SOCKET_ADDRESS_TYPE_UNIX;
424     listen_addr->u.q_unix.path = g_strdup(TEST_SOCKET);
425 
426     connect_addr->type = SOCKET_ADDRESS_TYPE_UNIX;
427     connect_addr->u.q_unix.path = g_strdup(TEST_SOCKET);
428 
429     test_io_channel_setup_sync(listen_addr, connect_addr, &srv, &src, &dst);
430 
431     memcpy(bufsend, "Hello World", G_N_ELEMENTS(bufsend));
432 
433     iosend[0].iov_base = bufsend;
434     iosend[0].iov_len = G_N_ELEMENTS(bufsend);
435 
436     iorecv[0].iov_base = bufrecv;
437     iorecv[0].iov_len = G_N_ELEMENTS(bufrecv);
438 
439     g_assert(qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS));
440     g_assert(qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_FD_PASS));
441 
442     qio_channel_writev_full(src,
443                             iosend,
444                             G_N_ELEMENTS(iosend),
445                             fdsend,
446                             G_N_ELEMENTS(fdsend),
447                             0,
448                             &error_abort);
449 
450     qio_channel_readv_full(dst,
451                            iorecv,
452                            G_N_ELEMENTS(iorecv),
453                            &fdrecv,
454                            &nfdrecv,
455                            &error_abort);
456 
457     g_assert(nfdrecv == G_N_ELEMENTS(fdsend));
458     /* Each recvd FD should be different from sent FD */
459     for (i = 0; i < nfdrecv; i++) {
460         g_assert_cmpint(fdrecv[i], !=, testfd);
461     }
462     /* Each recvd FD should be different from each other */
463     g_assert_cmpint(fdrecv[0], !=, fdrecv[1]);
464     g_assert_cmpint(fdrecv[0], !=, fdrecv[2]);
465     g_assert_cmpint(fdrecv[1], !=, fdrecv[2]);
466 
467     /* Check the I/O buf we sent at the same time matches */
468     g_assert(memcmp(bufsend, bufrecv, G_N_ELEMENTS(bufsend)) == 0);
469 
470     /* Write some data into the FD we received */
471     g_assert(write(fdrecv[0], bufsend, G_N_ELEMENTS(bufsend)) ==
472              G_N_ELEMENTS(bufsend));
473 
474     /* Read data from the original FD and make sure it matches */
475     memset(bufrecv, 0, G_N_ELEMENTS(bufrecv));
476     g_assert(lseek(testfd, 0, SEEK_SET) == 0);
477     g_assert(read(testfd, bufrecv, G_N_ELEMENTS(bufrecv)) ==
478              G_N_ELEMENTS(bufrecv));
479     g_assert(memcmp(bufsend, bufrecv, G_N_ELEMENTS(bufsend)) == 0);
480 
481     object_unref(OBJECT(src));
482     object_unref(OBJECT(dst));
483     object_unref(OBJECT(srv));
484     qapi_free_SocketAddress(listen_addr);
485     qapi_free_SocketAddress(connect_addr);
486     unlink(TEST_SOCKET);
487     unlink(TEST_FILE);
488     close(testfd);
489     for (i = 0; i < nfdrecv; i++) {
490         close(fdrecv[i]);
491     }
492     g_free(fdrecv);
493 }
494 
495 static void test_io_channel_unix_listen_cleanup(void)
496 {
497     QIOChannelSocket *ioc;
498     struct sockaddr_un un;
499     int sock;
500 
501 #define TEST_SOCKET "test-io-channel-socket.sock"
502 
503     ioc = qio_channel_socket_new();
504 
505     /* Manually bind ioc without calling the qio api to avoid setting
506      * the LISTEN feature */
507     sock = qemu_socket(PF_UNIX, SOCK_STREAM, 0);
508     memset(&un, 0, sizeof(un));
509     un.sun_family = AF_UNIX;
510     snprintf(un.sun_path, sizeof(un.sun_path), "%s", TEST_SOCKET);
511     unlink(TEST_SOCKET);
512     bind(sock, (struct sockaddr *)&un, sizeof(un));
513     ioc->fd = sock;
514     ioc->localAddrLen = sizeof(ioc->localAddr);
515     getsockname(sock, (struct sockaddr *)&ioc->localAddr,
516                 &ioc->localAddrLen);
517 
518     g_assert(g_file_test(TEST_SOCKET, G_FILE_TEST_EXISTS));
519     object_unref(OBJECT(ioc));
520     g_assert(g_file_test(TEST_SOCKET, G_FILE_TEST_EXISTS));
521 
522     unlink(TEST_SOCKET);
523 }
524 
525 #endif /* _WIN32 */
526 
527 
528 static void test_io_channel_ipv4_fd(void)
529 {
530     QIOChannel *ioc;
531     int fd = -1;
532     struct sockaddr_in sa = {
533         .sin_family = AF_INET,
534         .sin_addr = {
535             .s_addr =  htonl(INADDR_LOOPBACK),
536         }
537         /* Leave port unset for auto-assign */
538     };
539     socklen_t salen = sizeof(sa);
540 
541     fd = socket(AF_INET, SOCK_STREAM, 0);
542     g_assert_cmpint(fd, >, -1);
543 
544     g_assert_cmpint(bind(fd, (struct sockaddr *)&sa, salen), ==, 0);
545 
546     ioc = qio_channel_new_fd(fd, &error_abort);
547 
548     g_assert_cmpstr(object_get_typename(OBJECT(ioc)),
549                     ==,
550                     TYPE_QIO_CHANNEL_SOCKET);
551 
552     object_unref(OBJECT(ioc));
553 }
554 
555 
556 int main(int argc, char **argv)
557 {
558     bool has_ipv4, has_ipv6;
559 
560     module_call_init(MODULE_INIT_QOM);
561     qemu_init_main_loop(&error_abort);
562     socket_init();
563 
564     g_test_init(&argc, &argv, NULL);
565 
566     /* We're creating actual IPv4/6 sockets, so we should
567      * check if the host running tests actually supports
568      * each protocol to avoid breaking tests on machines
569      * with either IPv4 or IPv6 disabled.
570      */
571     if (socket_check_protocol_support(&has_ipv4, &has_ipv6) < 0) {
572         g_printerr("socket_check_protocol_support() failed\n");
573         goto end;
574     }
575 
576     if (has_ipv4) {
577         g_test_add_func("/io/channel/socket/ipv4-sync",
578                         test_io_channel_ipv4_sync);
579         g_test_add_func("/io/channel/socket/ipv4-async",
580                         test_io_channel_ipv4_async);
581         g_test_add_func("/io/channel/socket/ipv4-fd",
582                         test_io_channel_ipv4_fd);
583     }
584     if (has_ipv6) {
585         g_test_add_func("/io/channel/socket/ipv6-sync",
586                         test_io_channel_ipv6_sync);
587         g_test_add_func("/io/channel/socket/ipv6-async",
588                         test_io_channel_ipv6_async);
589     }
590 
591 #ifndef _WIN32
592     g_test_add_func("/io/channel/socket/unix-sync",
593                     test_io_channel_unix_sync);
594     g_test_add_func("/io/channel/socket/unix-async",
595                     test_io_channel_unix_async);
596     g_test_add_func("/io/channel/socket/unix-fd-pass",
597                     test_io_channel_unix_fd_pass);
598     g_test_add_func("/io/channel/socket/unix-listen-cleanup",
599                     test_io_channel_unix_listen_cleanup);
600 #endif /* _WIN32 */
601 
602 end:
603     return g_test_run();
604 }
605