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