These changes are the raw update to qemu-2.6.
[kvmfornfv.git] / qemu / 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 "qapi/error.h"
26
27 #ifndef AI_ADDRCONFIG
28 # define AI_ADDRCONFIG 0
29 #endif
30 #ifndef EAI_ADDRFAMILY
31 # define EAI_ADDRFAMILY 0
32 #endif
33
34 static int check_bind(const char *hostname, bool *has_proto)
35 {
36     int fd = -1;
37     struct addrinfo ai, *res = NULL;
38     int rc;
39     int ret = -1;
40
41     memset(&ai, 0, sizeof(ai));
42     ai.ai_flags = AI_CANONNAME | AI_ADDRCONFIG;
43     ai.ai_family = AF_UNSPEC;
44     ai.ai_socktype = SOCK_STREAM;
45
46     /* lookup */
47     rc = getaddrinfo(hostname, NULL, &ai, &res);
48     if (rc != 0) {
49         if (rc == EAI_ADDRFAMILY ||
50             rc == EAI_FAMILY) {
51             *has_proto = false;
52             goto done;
53         }
54         goto cleanup;
55     }
56
57     fd = qemu_socket(res->ai_family, res->ai_socktype, res->ai_protocol);
58     if (fd < 0) {
59         goto cleanup;
60     }
61
62     if (bind(fd, res->ai_addr, res->ai_addrlen) < 0) {
63         if (errno == EADDRNOTAVAIL) {
64             *has_proto = false;
65             goto done;
66         }
67         goto cleanup;
68     }
69
70     *has_proto = true;
71  done:
72     ret = 0;
73
74  cleanup:
75     if (fd != -1) {
76         close(fd);
77     }
78     if (res) {
79         freeaddrinfo(res);
80     }
81     return ret;
82 }
83
84 static int check_protocol_support(bool *has_ipv4, bool *has_ipv6)
85 {
86     if (check_bind("127.0.0.1", has_ipv4) < 0) {
87         return -1;
88     }
89     if (check_bind("::1", has_ipv6) < 0) {
90         return -1;
91     }
92
93     return 0;
94 }
95
96
97 static void test_io_channel_set_socket_bufs(QIOChannel *src,
98                                             QIOChannel *dst)
99 {
100     int buflen = 64 * 1024;
101
102     /*
103      * Make the socket buffers small so that we see
104      * the effects of partial reads/writes
105      */
106     setsockopt(((QIOChannelSocket *)src)->fd,
107                SOL_SOCKET, SO_SNDBUF,
108                (char *)&buflen,
109                sizeof(buflen));
110
111     setsockopt(((QIOChannelSocket *)dst)->fd,
112                SOL_SOCKET, SO_SNDBUF,
113                (char *)&buflen,
114                sizeof(buflen));
115 }
116
117
118 static void test_io_channel_setup_sync(SocketAddress *listen_addr,
119                                        SocketAddress *connect_addr,
120                                        QIOChannel **src,
121                                        QIOChannel **dst)
122 {
123     QIOChannelSocket *lioc;
124
125     lioc = qio_channel_socket_new();
126     qio_channel_socket_listen_sync(lioc, listen_addr, &error_abort);
127
128     if (listen_addr->type == SOCKET_ADDRESS_KIND_INET) {
129         SocketAddress *laddr = qio_channel_socket_get_local_address(
130             lioc, &error_abort);
131
132         g_free(connect_addr->u.inet.data->port);
133         connect_addr->u.inet.data->port = g_strdup(laddr->u.inet.data->port);
134
135         qapi_free_SocketAddress(laddr);
136     }
137
138     *src = QIO_CHANNEL(qio_channel_socket_new());
139     qio_channel_socket_connect_sync(
140         QIO_CHANNEL_SOCKET(*src), connect_addr, &error_abort);
141     qio_channel_set_delay(*src, false);
142
143     qio_channel_wait(QIO_CHANNEL(lioc), G_IO_IN);
144     *dst = QIO_CHANNEL(qio_channel_socket_accept(lioc, &error_abort));
145     g_assert(*dst);
146
147     test_io_channel_set_socket_bufs(*src, *dst);
148
149     object_unref(OBJECT(lioc));
150 }
151
152
153 struct TestIOChannelData {
154     bool err;
155     GMainLoop *loop;
156 };
157
158
159 static void test_io_channel_complete(Object *src,
160                                      Error *err,
161                                      gpointer opaque)
162 {
163     struct TestIOChannelData *data = opaque;
164     data->err = err != NULL;
165     g_main_loop_quit(data->loop);
166 }
167
168
169 static void test_io_channel_setup_async(SocketAddress *listen_addr,
170                                         SocketAddress *connect_addr,
171                                         QIOChannel **src,
172                                         QIOChannel **dst)
173 {
174     QIOChannelSocket *lioc;
175     struct TestIOChannelData data;
176
177     data.loop = g_main_loop_new(g_main_context_default(),
178                                 TRUE);
179
180     lioc = qio_channel_socket_new();
181     qio_channel_socket_listen_async(
182         lioc, listen_addr,
183         test_io_channel_complete, &data, NULL);
184
185     g_main_loop_run(data.loop);
186     g_main_context_iteration(g_main_context_default(), FALSE);
187
188     g_assert(!data.err);
189
190     if (listen_addr->type == SOCKET_ADDRESS_KIND_INET) {
191         SocketAddress *laddr = qio_channel_socket_get_local_address(
192             lioc, &error_abort);
193
194         g_free(connect_addr->u.inet.data->port);
195         connect_addr->u.inet.data->port = g_strdup(laddr->u.inet.data->port);
196
197         qapi_free_SocketAddress(laddr);
198     }
199
200     *src = QIO_CHANNEL(qio_channel_socket_new());
201
202     qio_channel_socket_connect_async(
203         QIO_CHANNEL_SOCKET(*src), connect_addr,
204         test_io_channel_complete, &data, NULL);
205
206     g_main_loop_run(data.loop);
207     g_main_context_iteration(g_main_context_default(), FALSE);
208
209     g_assert(!data.err);
210
211     qio_channel_wait(QIO_CHANNEL(lioc), G_IO_IN);
212     *dst = QIO_CHANNEL(qio_channel_socket_accept(lioc, &error_abort));
213     g_assert(*dst);
214
215     qio_channel_set_delay(*src, false);
216     test_io_channel_set_socket_bufs(*src, *dst);
217
218     object_unref(OBJECT(lioc));
219
220     g_main_loop_unref(data.loop);
221 }
222
223
224 static void test_io_channel(bool async,
225                             SocketAddress *listen_addr,
226                             SocketAddress *connect_addr,
227                             bool passFD)
228 {
229     QIOChannel *src, *dst;
230     QIOChannelTest *test;
231     if (async) {
232         test_io_channel_setup_async(listen_addr, connect_addr, &src, &dst);
233
234         g_assert(!passFD ||
235                  qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS));
236         g_assert(!passFD ||
237                  qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_FD_PASS));
238
239         test = qio_channel_test_new();
240         qio_channel_test_run_threads(test, true, src, dst);
241         qio_channel_test_validate(test);
242
243         object_unref(OBJECT(src));
244         object_unref(OBJECT(dst));
245
246         test_io_channel_setup_async(listen_addr, connect_addr, &src, &dst);
247
248         g_assert(!passFD ||
249                  qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS));
250         g_assert(!passFD ||
251                  qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_FD_PASS));
252
253         test = qio_channel_test_new();
254         qio_channel_test_run_threads(test, false, src, dst);
255         qio_channel_test_validate(test);
256
257         object_unref(OBJECT(src));
258         object_unref(OBJECT(dst));
259     } else {
260         test_io_channel_setup_sync(listen_addr, connect_addr, &src, &dst);
261
262         g_assert(!passFD ||
263                  qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS));
264         g_assert(!passFD ||
265                  qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_FD_PASS));
266
267         test = qio_channel_test_new();
268         qio_channel_test_run_threads(test, true, src, dst);
269         qio_channel_test_validate(test);
270
271         object_unref(OBJECT(src));
272         object_unref(OBJECT(dst));
273
274         test_io_channel_setup_sync(listen_addr, connect_addr, &src, &dst);
275
276         g_assert(!passFD ||
277                  qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS));
278         g_assert(!passFD ||
279                  qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_FD_PASS));
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         object_unref(OBJECT(src));
286         object_unref(OBJECT(dst));
287     }
288 }
289
290
291 static void test_io_channel_ipv4(bool async)
292 {
293     SocketAddress *listen_addr = g_new0(SocketAddress, 1);
294     SocketAddress *connect_addr = g_new0(SocketAddress, 1);
295
296     listen_addr->type = SOCKET_ADDRESS_KIND_INET;
297     listen_addr->u.inet.data = g_new(InetSocketAddress, 1);
298     *listen_addr->u.inet.data = (InetSocketAddress) {
299         .host = g_strdup("127.0.0.1"),
300         .port = NULL, /* Auto-select */
301     };
302
303     connect_addr->type = SOCKET_ADDRESS_KIND_INET;
304     connect_addr->u.inet.data = g_new(InetSocketAddress, 1);
305     *connect_addr->u.inet.data = (InetSocketAddress) {
306         .host = g_strdup("127.0.0.1"),
307         .port = NULL, /* Filled in later */
308     };
309
310     test_io_channel(async, listen_addr, connect_addr, false);
311
312     qapi_free_SocketAddress(listen_addr);
313     qapi_free_SocketAddress(connect_addr);
314 }
315
316
317 static void test_io_channel_ipv4_sync(void)
318 {
319     return test_io_channel_ipv4(false);
320 }
321
322
323 static void test_io_channel_ipv4_async(void)
324 {
325     return test_io_channel_ipv4(true);
326 }
327
328
329 static void test_io_channel_ipv6(bool async)
330 {
331     SocketAddress *listen_addr = g_new0(SocketAddress, 1);
332     SocketAddress *connect_addr = g_new0(SocketAddress, 1);
333
334     listen_addr->type = SOCKET_ADDRESS_KIND_INET;
335     listen_addr->u.inet.data = g_new(InetSocketAddress, 1);
336     *listen_addr->u.inet.data = (InetSocketAddress) {
337         .host = g_strdup("::1"),
338         .port = NULL, /* Auto-select */
339     };
340
341     connect_addr->type = SOCKET_ADDRESS_KIND_INET;
342     connect_addr->u.inet.data = g_new(InetSocketAddress, 1);
343     *connect_addr->u.inet.data = (InetSocketAddress) {
344         .host = g_strdup("::1"),
345         .port = NULL, /* Filled in later */
346     };
347
348     test_io_channel(async, listen_addr, connect_addr, false);
349
350     qapi_free_SocketAddress(listen_addr);
351     qapi_free_SocketAddress(connect_addr);
352 }
353
354
355 static void test_io_channel_ipv6_sync(void)
356 {
357     return test_io_channel_ipv6(false);
358 }
359
360
361 static void test_io_channel_ipv6_async(void)
362 {
363     return test_io_channel_ipv6(true);
364 }
365
366
367 #ifndef _WIN32
368 static void test_io_channel_unix(bool async)
369 {
370     SocketAddress *listen_addr = g_new0(SocketAddress, 1);
371     SocketAddress *connect_addr = g_new0(SocketAddress, 1);
372
373 #define TEST_SOCKET "test-io-channel-socket.sock"
374     listen_addr->type = SOCKET_ADDRESS_KIND_UNIX;
375     listen_addr->u.q_unix.data = g_new0(UnixSocketAddress, 1);
376     listen_addr->u.q_unix.data->path = g_strdup(TEST_SOCKET);
377
378     connect_addr->type = SOCKET_ADDRESS_KIND_UNIX;
379     connect_addr->u.q_unix.data = g_new0(UnixSocketAddress, 1);
380     connect_addr->u.q_unix.data->path = g_strdup(TEST_SOCKET);
381
382     test_io_channel(async, listen_addr, connect_addr, true);
383
384     qapi_free_SocketAddress(listen_addr);
385     qapi_free_SocketAddress(connect_addr);
386     unlink(TEST_SOCKET);
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;
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_KIND_UNIX;
424     listen_addr->u.q_unix.data = g_new0(UnixSocketAddress, 1);
425     listen_addr->u.q_unix.data->path = g_strdup(TEST_SOCKET);
426
427     connect_addr->type = SOCKET_ADDRESS_KIND_UNIX;
428     connect_addr->u.q_unix.data = g_new0(UnixSocketAddress, 1);
429     connect_addr->u.q_unix.data->path = g_strdup(TEST_SOCKET);
430
431     test_io_channel_setup_sync(listen_addr, connect_addr, &src, &dst);
432
433     memcpy(bufsend, "Hello World", G_N_ELEMENTS(bufsend));
434
435     iosend[0].iov_base = bufsend;
436     iosend[0].iov_len = G_N_ELEMENTS(bufsend);
437
438     iorecv[0].iov_base = bufrecv;
439     iorecv[0].iov_len = G_N_ELEMENTS(bufrecv);
440
441     g_assert(qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS));
442     g_assert(qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_FD_PASS));
443
444     qio_channel_writev_full(src,
445                             iosend,
446                             G_N_ELEMENTS(iosend),
447                             fdsend,
448                             G_N_ELEMENTS(fdsend),
449                             &error_abort);
450
451     qio_channel_readv_full(dst,
452                            iorecv,
453                            G_N_ELEMENTS(iorecv),
454                            &fdrecv,
455                            &nfdrecv,
456                            &error_abort);
457
458     g_assert(nfdrecv == G_N_ELEMENTS(fdsend));
459     /* Each recvd FD should be different from sent FD */
460     for (i = 0; i < nfdrecv; i++) {
461         g_assert_cmpint(fdrecv[i], !=, testfd);
462     }
463     /* Each recvd FD should be different from each other */
464     g_assert_cmpint(fdrecv[0], !=, fdrecv[1]);
465     g_assert_cmpint(fdrecv[0], !=, fdrecv[2]);
466     g_assert_cmpint(fdrecv[1], !=, fdrecv[2]);
467
468     /* Check the I/O buf we sent at the same time matches */
469     g_assert(memcmp(bufsend, bufrecv, G_N_ELEMENTS(bufsend)) == 0);
470
471     /* Write some data into the FD we received */
472     g_assert(write(fdrecv[0], bufsend, G_N_ELEMENTS(bufsend)) ==
473              G_N_ELEMENTS(bufsend));
474
475     /* Read data from the original FD and make sure it matches */
476     memset(bufrecv, 0, G_N_ELEMENTS(bufrecv));
477     g_assert(lseek(testfd, 0, SEEK_SET) == 0);
478     g_assert(read(testfd, bufrecv, G_N_ELEMENTS(bufrecv)) ==
479              G_N_ELEMENTS(bufrecv));
480     g_assert(memcmp(bufsend, bufrecv, G_N_ELEMENTS(bufsend)) == 0);
481
482     object_unref(OBJECT(src));
483     object_unref(OBJECT(dst));
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 #endif /* _WIN32 */
495
496
497 static void test_io_channel_ipv4_fd(void)
498 {
499     QIOChannel *ioc;
500     int fd = -1;
501     struct sockaddr_in sa = {
502         .sin_family = AF_INET,
503         .sin_addr = {
504             .s_addr =  htonl(INADDR_LOOPBACK),
505         }
506         /* Leave port unset for auto-assign */
507     };
508     socklen_t salen = sizeof(sa);
509
510     fd = socket(AF_INET, SOCK_STREAM, 0);
511     g_assert_cmpint(fd, >, -1);
512
513     g_assert_cmpint(bind(fd, (struct sockaddr *)&sa, salen), ==, 0);
514
515     ioc = qio_channel_new_fd(fd, &error_abort);
516
517     g_assert_cmpstr(object_get_typename(OBJECT(ioc)),
518                     ==,
519                     TYPE_QIO_CHANNEL_SOCKET);
520
521     object_unref(OBJECT(ioc));
522 }
523
524
525 int main(int argc, char **argv)
526 {
527     bool has_ipv4, has_ipv6;
528
529     module_call_init(MODULE_INIT_QOM);
530     socket_init();
531
532     g_test_init(&argc, &argv, NULL);
533
534     /* We're creating actual IPv4/6 sockets, so we should
535      * check if the host running tests actually supports
536      * each protocol to avoid breaking tests on machines
537      * with either IPv4 or IPv6 disabled.
538      */
539     if (check_protocol_support(&has_ipv4, &has_ipv6) < 0) {
540         return 1;
541     }
542
543     if (has_ipv4) {
544         g_test_add_func("/io/channel/socket/ipv4-sync",
545                         test_io_channel_ipv4_sync);
546         g_test_add_func("/io/channel/socket/ipv4-async",
547                         test_io_channel_ipv4_async);
548         g_test_add_func("/io/channel/socket/ipv4-fd",
549                         test_io_channel_ipv4_fd);
550     }
551     if (has_ipv6) {
552         g_test_add_func("/io/channel/socket/ipv6-sync",
553                         test_io_channel_ipv6_sync);
554         g_test_add_func("/io/channel/socket/ipv6-async",
555                         test_io_channel_ipv6_async);
556     }
557
558 #ifndef _WIN32
559     g_test_add_func("/io/channel/socket/unix-sync",
560                     test_io_channel_unix_sync);
561     g_test_add_func("/io/channel/socket/unix-async",
562                     test_io_channel_unix_async);
563     g_test_add_func("/io/channel/socket/unix-fd-pass",
564                     test_io_channel_unix_fd_pass);
565 #endif /* _WIN32 */
566
567     return g_test_run();
568 }