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