Loading...
Note: File does not exist in v3.5.6.
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * vsock_test - vsock.ko test suite
4 *
5 * Copyright (C) 2017 Red Hat, Inc.
6 *
7 * Author: Stefan Hajnoczi <stefanha@redhat.com>
8 */
9
10#include <getopt.h>
11#include <stdio.h>
12#include <stdlib.h>
13#include <string.h>
14#include <errno.h>
15#include <unistd.h>
16#include <linux/kernel.h>
17#include <sys/types.h>
18#include <sys/socket.h>
19#include <time.h>
20#include <sys/mman.h>
21#include <poll.h>
22
23#include "timeout.h"
24#include "control.h"
25#include "util.h"
26
27static void test_stream_connection_reset(const struct test_opts *opts)
28{
29 union {
30 struct sockaddr sa;
31 struct sockaddr_vm svm;
32 } addr = {
33 .svm = {
34 .svm_family = AF_VSOCK,
35 .svm_port = 1234,
36 .svm_cid = opts->peer_cid,
37 },
38 };
39 int ret;
40 int fd;
41
42 fd = socket(AF_VSOCK, SOCK_STREAM, 0);
43
44 timeout_begin(TIMEOUT);
45 do {
46 ret = connect(fd, &addr.sa, sizeof(addr.svm));
47 timeout_check("connect");
48 } while (ret < 0 && errno == EINTR);
49 timeout_end();
50
51 if (ret != -1) {
52 fprintf(stderr, "expected connect(2) failure, got %d\n", ret);
53 exit(EXIT_FAILURE);
54 }
55 if (errno != ECONNRESET) {
56 fprintf(stderr, "unexpected connect(2) errno %d\n", errno);
57 exit(EXIT_FAILURE);
58 }
59
60 close(fd);
61}
62
63static void test_stream_bind_only_client(const struct test_opts *opts)
64{
65 union {
66 struct sockaddr sa;
67 struct sockaddr_vm svm;
68 } addr = {
69 .svm = {
70 .svm_family = AF_VSOCK,
71 .svm_port = 1234,
72 .svm_cid = opts->peer_cid,
73 },
74 };
75 int ret;
76 int fd;
77
78 /* Wait for the server to be ready */
79 control_expectln("BIND");
80
81 fd = socket(AF_VSOCK, SOCK_STREAM, 0);
82
83 timeout_begin(TIMEOUT);
84 do {
85 ret = connect(fd, &addr.sa, sizeof(addr.svm));
86 timeout_check("connect");
87 } while (ret < 0 && errno == EINTR);
88 timeout_end();
89
90 if (ret != -1) {
91 fprintf(stderr, "expected connect(2) failure, got %d\n", ret);
92 exit(EXIT_FAILURE);
93 }
94 if (errno != ECONNRESET) {
95 fprintf(stderr, "unexpected connect(2) errno %d\n", errno);
96 exit(EXIT_FAILURE);
97 }
98
99 /* Notify the server that the client has finished */
100 control_writeln("DONE");
101
102 close(fd);
103}
104
105static void test_stream_bind_only_server(const struct test_opts *opts)
106{
107 union {
108 struct sockaddr sa;
109 struct sockaddr_vm svm;
110 } addr = {
111 .svm = {
112 .svm_family = AF_VSOCK,
113 .svm_port = 1234,
114 .svm_cid = VMADDR_CID_ANY,
115 },
116 };
117 int fd;
118
119 fd = socket(AF_VSOCK, SOCK_STREAM, 0);
120
121 if (bind(fd, &addr.sa, sizeof(addr.svm)) < 0) {
122 perror("bind");
123 exit(EXIT_FAILURE);
124 }
125
126 /* Notify the client that the server is ready */
127 control_writeln("BIND");
128
129 /* Wait for the client to finish */
130 control_expectln("DONE");
131
132 close(fd);
133}
134
135static void test_stream_client_close_client(const struct test_opts *opts)
136{
137 int fd;
138
139 fd = vsock_stream_connect(opts->peer_cid, 1234);
140 if (fd < 0) {
141 perror("connect");
142 exit(EXIT_FAILURE);
143 }
144
145 send_byte(fd, 1, 0);
146 close(fd);
147}
148
149static void test_stream_client_close_server(const struct test_opts *opts)
150{
151 int fd;
152
153 fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
154 if (fd < 0) {
155 perror("accept");
156 exit(EXIT_FAILURE);
157 }
158
159 /* Wait for the remote to close the connection, before check
160 * -EPIPE error on send.
161 */
162 vsock_wait_remote_close(fd);
163
164 send_byte(fd, -EPIPE, 0);
165 recv_byte(fd, 1, 0);
166 recv_byte(fd, 0, 0);
167 close(fd);
168}
169
170static void test_stream_server_close_client(const struct test_opts *opts)
171{
172 int fd;
173
174 fd = vsock_stream_connect(opts->peer_cid, 1234);
175 if (fd < 0) {
176 perror("connect");
177 exit(EXIT_FAILURE);
178 }
179
180 /* Wait for the remote to close the connection, before check
181 * -EPIPE error on send.
182 */
183 vsock_wait_remote_close(fd);
184
185 send_byte(fd, -EPIPE, 0);
186 recv_byte(fd, 1, 0);
187 recv_byte(fd, 0, 0);
188 close(fd);
189}
190
191static void test_stream_server_close_server(const struct test_opts *opts)
192{
193 int fd;
194
195 fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
196 if (fd < 0) {
197 perror("accept");
198 exit(EXIT_FAILURE);
199 }
200
201 send_byte(fd, 1, 0);
202 close(fd);
203}
204
205/* With the standard socket sizes, VMCI is able to support about 100
206 * concurrent stream connections.
207 */
208#define MULTICONN_NFDS 100
209
210static void test_stream_multiconn_client(const struct test_opts *opts)
211{
212 int fds[MULTICONN_NFDS];
213 int i;
214
215 for (i = 0; i < MULTICONN_NFDS; i++) {
216 fds[i] = vsock_stream_connect(opts->peer_cid, 1234);
217 if (fds[i] < 0) {
218 perror("connect");
219 exit(EXIT_FAILURE);
220 }
221 }
222
223 for (i = 0; i < MULTICONN_NFDS; i++) {
224 if (i % 2)
225 recv_byte(fds[i], 1, 0);
226 else
227 send_byte(fds[i], 1, 0);
228 }
229
230 for (i = 0; i < MULTICONN_NFDS; i++)
231 close(fds[i]);
232}
233
234static void test_stream_multiconn_server(const struct test_opts *opts)
235{
236 int fds[MULTICONN_NFDS];
237 int i;
238
239 for (i = 0; i < MULTICONN_NFDS; i++) {
240 fds[i] = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
241 if (fds[i] < 0) {
242 perror("accept");
243 exit(EXIT_FAILURE);
244 }
245 }
246
247 for (i = 0; i < MULTICONN_NFDS; i++) {
248 if (i % 2)
249 send_byte(fds[i], 1, 0);
250 else
251 recv_byte(fds[i], 1, 0);
252 }
253
254 for (i = 0; i < MULTICONN_NFDS; i++)
255 close(fds[i]);
256}
257
258static void test_stream_msg_peek_client(const struct test_opts *opts)
259{
260 int fd;
261
262 fd = vsock_stream_connect(opts->peer_cid, 1234);
263 if (fd < 0) {
264 perror("connect");
265 exit(EXIT_FAILURE);
266 }
267
268 send_byte(fd, 1, 0);
269 close(fd);
270}
271
272static void test_stream_msg_peek_server(const struct test_opts *opts)
273{
274 int fd;
275
276 fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
277 if (fd < 0) {
278 perror("accept");
279 exit(EXIT_FAILURE);
280 }
281
282 recv_byte(fd, 1, MSG_PEEK);
283 recv_byte(fd, 1, 0);
284 close(fd);
285}
286
287#define MESSAGES_CNT 7
288#define MSG_EOR_IDX (MESSAGES_CNT / 2)
289static void test_seqpacket_msg_bounds_client(const struct test_opts *opts)
290{
291 int fd;
292
293 fd = vsock_seqpacket_connect(opts->peer_cid, 1234);
294 if (fd < 0) {
295 perror("connect");
296 exit(EXIT_FAILURE);
297 }
298
299 /* Send several messages, one with MSG_EOR flag */
300 for (int i = 0; i < MESSAGES_CNT; i++)
301 send_byte(fd, 1, (i == MSG_EOR_IDX) ? MSG_EOR : 0);
302
303 control_writeln("SENDDONE");
304 close(fd);
305}
306
307static void test_seqpacket_msg_bounds_server(const struct test_opts *opts)
308{
309 int fd;
310 char buf[16];
311 struct msghdr msg = {0};
312 struct iovec iov = {0};
313
314 fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL);
315 if (fd < 0) {
316 perror("accept");
317 exit(EXIT_FAILURE);
318 }
319
320 control_expectln("SENDDONE");
321 iov.iov_base = buf;
322 iov.iov_len = sizeof(buf);
323 msg.msg_iov = &iov;
324 msg.msg_iovlen = 1;
325
326 for (int i = 0; i < MESSAGES_CNT; i++) {
327 if (recvmsg(fd, &msg, 0) != 1) {
328 perror("message bound violated");
329 exit(EXIT_FAILURE);
330 }
331
332 if ((i == MSG_EOR_IDX) ^ !!(msg.msg_flags & MSG_EOR)) {
333 perror("MSG_EOR");
334 exit(EXIT_FAILURE);
335 }
336 }
337
338 close(fd);
339}
340
341#define MESSAGE_TRUNC_SZ 32
342static void test_seqpacket_msg_trunc_client(const struct test_opts *opts)
343{
344 int fd;
345 char buf[MESSAGE_TRUNC_SZ];
346
347 fd = vsock_seqpacket_connect(opts->peer_cid, 1234);
348 if (fd < 0) {
349 perror("connect");
350 exit(EXIT_FAILURE);
351 }
352
353 if (send(fd, buf, sizeof(buf), 0) != sizeof(buf)) {
354 perror("send failed");
355 exit(EXIT_FAILURE);
356 }
357
358 control_writeln("SENDDONE");
359 close(fd);
360}
361
362static void test_seqpacket_msg_trunc_server(const struct test_opts *opts)
363{
364 int fd;
365 char buf[MESSAGE_TRUNC_SZ / 2];
366 struct msghdr msg = {0};
367 struct iovec iov = {0};
368
369 fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL);
370 if (fd < 0) {
371 perror("accept");
372 exit(EXIT_FAILURE);
373 }
374
375 control_expectln("SENDDONE");
376 iov.iov_base = buf;
377 iov.iov_len = sizeof(buf);
378 msg.msg_iov = &iov;
379 msg.msg_iovlen = 1;
380
381 ssize_t ret = recvmsg(fd, &msg, MSG_TRUNC);
382
383 if (ret != MESSAGE_TRUNC_SZ) {
384 printf("%zi\n", ret);
385 perror("MSG_TRUNC doesn't work");
386 exit(EXIT_FAILURE);
387 }
388
389 if (!(msg.msg_flags & MSG_TRUNC)) {
390 fprintf(stderr, "MSG_TRUNC expected\n");
391 exit(EXIT_FAILURE);
392 }
393
394 close(fd);
395}
396
397static time_t current_nsec(void)
398{
399 struct timespec ts;
400
401 if (clock_gettime(CLOCK_REALTIME, &ts)) {
402 perror("clock_gettime(3) failed");
403 exit(EXIT_FAILURE);
404 }
405
406 return (ts.tv_sec * 1000000000ULL) + ts.tv_nsec;
407}
408
409#define RCVTIMEO_TIMEOUT_SEC 1
410#define READ_OVERHEAD_NSEC 250000000 /* 0.25 sec */
411
412static void test_seqpacket_timeout_client(const struct test_opts *opts)
413{
414 int fd;
415 struct timeval tv;
416 char dummy;
417 time_t read_enter_ns;
418 time_t read_overhead_ns;
419
420 fd = vsock_seqpacket_connect(opts->peer_cid, 1234);
421 if (fd < 0) {
422 perror("connect");
423 exit(EXIT_FAILURE);
424 }
425
426 tv.tv_sec = RCVTIMEO_TIMEOUT_SEC;
427 tv.tv_usec = 0;
428
429 if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (void *)&tv, sizeof(tv)) == -1) {
430 perror("setsockopt 'SO_RCVTIMEO'");
431 exit(EXIT_FAILURE);
432 }
433
434 read_enter_ns = current_nsec();
435
436 if (read(fd, &dummy, sizeof(dummy)) != -1) {
437 fprintf(stderr,
438 "expected 'dummy' read(2) failure\n");
439 exit(EXIT_FAILURE);
440 }
441
442 if (errno != EAGAIN) {
443 perror("EAGAIN expected");
444 exit(EXIT_FAILURE);
445 }
446
447 read_overhead_ns = current_nsec() - read_enter_ns -
448 1000000000ULL * RCVTIMEO_TIMEOUT_SEC;
449
450 if (read_overhead_ns > READ_OVERHEAD_NSEC) {
451 fprintf(stderr,
452 "too much time in read(2), %lu > %i ns\n",
453 read_overhead_ns, READ_OVERHEAD_NSEC);
454 exit(EXIT_FAILURE);
455 }
456
457 control_writeln("WAITDONE");
458 close(fd);
459}
460
461static void test_seqpacket_timeout_server(const struct test_opts *opts)
462{
463 int fd;
464
465 fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL);
466 if (fd < 0) {
467 perror("accept");
468 exit(EXIT_FAILURE);
469 }
470
471 control_expectln("WAITDONE");
472 close(fd);
473}
474
475#define BUF_PATTERN_1 'a'
476#define BUF_PATTERN_2 'b'
477
478static void test_seqpacket_invalid_rec_buffer_client(const struct test_opts *opts)
479{
480 int fd;
481 unsigned char *buf1;
482 unsigned char *buf2;
483 int buf_size = getpagesize() * 3;
484
485 fd = vsock_seqpacket_connect(opts->peer_cid, 1234);
486 if (fd < 0) {
487 perror("connect");
488 exit(EXIT_FAILURE);
489 }
490
491 buf1 = malloc(buf_size);
492 if (!buf1) {
493 perror("'malloc()' for 'buf1'");
494 exit(EXIT_FAILURE);
495 }
496
497 buf2 = malloc(buf_size);
498 if (!buf2) {
499 perror("'malloc()' for 'buf2'");
500 exit(EXIT_FAILURE);
501 }
502
503 memset(buf1, BUF_PATTERN_1, buf_size);
504 memset(buf2, BUF_PATTERN_2, buf_size);
505
506 if (send(fd, buf1, buf_size, 0) != buf_size) {
507 perror("send failed");
508 exit(EXIT_FAILURE);
509 }
510
511 if (send(fd, buf2, buf_size, 0) != buf_size) {
512 perror("send failed");
513 exit(EXIT_FAILURE);
514 }
515
516 close(fd);
517}
518
519static void test_seqpacket_invalid_rec_buffer_server(const struct test_opts *opts)
520{
521 int fd;
522 unsigned char *broken_buf;
523 unsigned char *valid_buf;
524 int page_size = getpagesize();
525 int buf_size = page_size * 3;
526 ssize_t res;
527 int prot = PROT_READ | PROT_WRITE;
528 int flags = MAP_PRIVATE | MAP_ANONYMOUS;
529 int i;
530
531 fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL);
532 if (fd < 0) {
533 perror("accept");
534 exit(EXIT_FAILURE);
535 }
536
537 /* Setup first buffer. */
538 broken_buf = mmap(NULL, buf_size, prot, flags, -1, 0);
539 if (broken_buf == MAP_FAILED) {
540 perror("mmap for 'broken_buf'");
541 exit(EXIT_FAILURE);
542 }
543
544 /* Unmap "hole" in buffer. */
545 if (munmap(broken_buf + page_size, page_size)) {
546 perror("'broken_buf' setup");
547 exit(EXIT_FAILURE);
548 }
549
550 valid_buf = mmap(NULL, buf_size, prot, flags, -1, 0);
551 if (valid_buf == MAP_FAILED) {
552 perror("mmap for 'valid_buf'");
553 exit(EXIT_FAILURE);
554 }
555
556 /* Try to fill buffer with unmapped middle. */
557 res = read(fd, broken_buf, buf_size);
558 if (res != -1) {
559 fprintf(stderr,
560 "expected 'broken_buf' read(2) failure, got %zi\n",
561 res);
562 exit(EXIT_FAILURE);
563 }
564
565 if (errno != ENOMEM) {
566 perror("unexpected errno of 'broken_buf'");
567 exit(EXIT_FAILURE);
568 }
569
570 /* Try to fill valid buffer. */
571 res = read(fd, valid_buf, buf_size);
572 if (res < 0) {
573 perror("unexpected 'valid_buf' read(2) failure");
574 exit(EXIT_FAILURE);
575 }
576
577 if (res != buf_size) {
578 fprintf(stderr,
579 "invalid 'valid_buf' read(2), expected %i, got %zi\n",
580 buf_size, res);
581 exit(EXIT_FAILURE);
582 }
583
584 for (i = 0; i < buf_size; i++) {
585 if (valid_buf[i] != BUF_PATTERN_2) {
586 fprintf(stderr,
587 "invalid pattern for 'valid_buf' at %i, expected %hhX, got %hhX\n",
588 i, BUF_PATTERN_2, valid_buf[i]);
589 exit(EXIT_FAILURE);
590 }
591 }
592
593 /* Unmap buffers. */
594 munmap(broken_buf, page_size);
595 munmap(broken_buf + page_size * 2, page_size);
596 munmap(valid_buf, buf_size);
597 close(fd);
598}
599
600#define RCVLOWAT_BUF_SIZE 128
601
602static void test_stream_poll_rcvlowat_server(const struct test_opts *opts)
603{
604 int fd;
605 int i;
606
607 fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
608 if (fd < 0) {
609 perror("accept");
610 exit(EXIT_FAILURE);
611 }
612
613 /* Send 1 byte. */
614 send_byte(fd, 1, 0);
615
616 control_writeln("SRVSENT");
617
618 /* Wait until client is ready to receive rest of data. */
619 control_expectln("CLNSENT");
620
621 for (i = 0; i < RCVLOWAT_BUF_SIZE - 1; i++)
622 send_byte(fd, 1, 0);
623
624 /* Keep socket in active state. */
625 control_expectln("POLLDONE");
626
627 close(fd);
628}
629
630static void test_stream_poll_rcvlowat_client(const struct test_opts *opts)
631{
632 unsigned long lowat_val = RCVLOWAT_BUF_SIZE;
633 char buf[RCVLOWAT_BUF_SIZE];
634 struct pollfd fds;
635 ssize_t read_res;
636 short poll_flags;
637 int fd;
638
639 fd = vsock_stream_connect(opts->peer_cid, 1234);
640 if (fd < 0) {
641 perror("connect");
642 exit(EXIT_FAILURE);
643 }
644
645 if (setsockopt(fd, SOL_SOCKET, SO_RCVLOWAT,
646 &lowat_val, sizeof(lowat_val))) {
647 perror("setsockopt");
648 exit(EXIT_FAILURE);
649 }
650
651 control_expectln("SRVSENT");
652
653 /* At this point, server sent 1 byte. */
654 fds.fd = fd;
655 poll_flags = POLLIN | POLLRDNORM;
656 fds.events = poll_flags;
657
658 /* Try to wait for 1 sec. */
659 if (poll(&fds, 1, 1000) < 0) {
660 perror("poll");
661 exit(EXIT_FAILURE);
662 }
663
664 /* poll() must return nothing. */
665 if (fds.revents) {
666 fprintf(stderr, "Unexpected poll result %hx\n",
667 fds.revents);
668 exit(EXIT_FAILURE);
669 }
670
671 /* Tell server to send rest of data. */
672 control_writeln("CLNSENT");
673
674 /* Poll for data. */
675 if (poll(&fds, 1, 10000) < 0) {
676 perror("poll");
677 exit(EXIT_FAILURE);
678 }
679
680 /* Only these two bits are expected. */
681 if (fds.revents != poll_flags) {
682 fprintf(stderr, "Unexpected poll result %hx\n",
683 fds.revents);
684 exit(EXIT_FAILURE);
685 }
686
687 /* Use MSG_DONTWAIT, if call is going to wait, EAGAIN
688 * will be returned.
689 */
690 read_res = recv(fd, buf, sizeof(buf), MSG_DONTWAIT);
691 if (read_res != RCVLOWAT_BUF_SIZE) {
692 fprintf(stderr, "Unexpected recv result %zi\n",
693 read_res);
694 exit(EXIT_FAILURE);
695 }
696
697 control_writeln("POLLDONE");
698
699 close(fd);
700}
701
702static struct test_case test_cases[] = {
703 {
704 .name = "SOCK_STREAM connection reset",
705 .run_client = test_stream_connection_reset,
706 },
707 {
708 .name = "SOCK_STREAM bind only",
709 .run_client = test_stream_bind_only_client,
710 .run_server = test_stream_bind_only_server,
711 },
712 {
713 .name = "SOCK_STREAM client close",
714 .run_client = test_stream_client_close_client,
715 .run_server = test_stream_client_close_server,
716 },
717 {
718 .name = "SOCK_STREAM server close",
719 .run_client = test_stream_server_close_client,
720 .run_server = test_stream_server_close_server,
721 },
722 {
723 .name = "SOCK_STREAM multiple connections",
724 .run_client = test_stream_multiconn_client,
725 .run_server = test_stream_multiconn_server,
726 },
727 {
728 .name = "SOCK_STREAM MSG_PEEK",
729 .run_client = test_stream_msg_peek_client,
730 .run_server = test_stream_msg_peek_server,
731 },
732 {
733 .name = "SOCK_SEQPACKET msg bounds",
734 .run_client = test_seqpacket_msg_bounds_client,
735 .run_server = test_seqpacket_msg_bounds_server,
736 },
737 {
738 .name = "SOCK_SEQPACKET MSG_TRUNC flag",
739 .run_client = test_seqpacket_msg_trunc_client,
740 .run_server = test_seqpacket_msg_trunc_server,
741 },
742 {
743 .name = "SOCK_SEQPACKET timeout",
744 .run_client = test_seqpacket_timeout_client,
745 .run_server = test_seqpacket_timeout_server,
746 },
747 {
748 .name = "SOCK_SEQPACKET invalid receive buffer",
749 .run_client = test_seqpacket_invalid_rec_buffer_client,
750 .run_server = test_seqpacket_invalid_rec_buffer_server,
751 },
752 {
753 .name = "SOCK_STREAM poll() + SO_RCVLOWAT",
754 .run_client = test_stream_poll_rcvlowat_client,
755 .run_server = test_stream_poll_rcvlowat_server,
756 },
757 {},
758};
759
760static const char optstring[] = "";
761static const struct option longopts[] = {
762 {
763 .name = "control-host",
764 .has_arg = required_argument,
765 .val = 'H',
766 },
767 {
768 .name = "control-port",
769 .has_arg = required_argument,
770 .val = 'P',
771 },
772 {
773 .name = "mode",
774 .has_arg = required_argument,
775 .val = 'm',
776 },
777 {
778 .name = "peer-cid",
779 .has_arg = required_argument,
780 .val = 'p',
781 },
782 {
783 .name = "list",
784 .has_arg = no_argument,
785 .val = 'l',
786 },
787 {
788 .name = "skip",
789 .has_arg = required_argument,
790 .val = 's',
791 },
792 {
793 .name = "help",
794 .has_arg = no_argument,
795 .val = '?',
796 },
797 {},
798};
799
800static void usage(void)
801{
802 fprintf(stderr, "Usage: vsock_test [--help] [--control-host=<host>] --control-port=<port> --mode=client|server --peer-cid=<cid> [--list] [--skip=<test_id>]\n"
803 "\n"
804 " Server: vsock_test --control-port=1234 --mode=server --peer-cid=3\n"
805 " Client: vsock_test --control-host=192.168.0.1 --control-port=1234 --mode=client --peer-cid=2\n"
806 "\n"
807 "Run vsock.ko tests. Must be launched in both guest\n"
808 "and host. One side must use --mode=client and\n"
809 "the other side must use --mode=server.\n"
810 "\n"
811 "A TCP control socket connection is used to coordinate tests\n"
812 "between the client and the server. The server requires a\n"
813 "listen address and the client requires an address to\n"
814 "connect to.\n"
815 "\n"
816 "The CID of the other side must be given with --peer-cid=<cid>.\n"
817 "\n"
818 "Options:\n"
819 " --help This help message\n"
820 " --control-host <host> Server IP address to connect to\n"
821 " --control-port <port> Server port to listen on/connect to\n"
822 " --mode client|server Server or client mode\n"
823 " --peer-cid <cid> CID of the other side\n"
824 " --list List of tests that will be executed\n"
825 " --skip <test_id> Test ID to skip;\n"
826 " use multiple --skip options to skip more tests\n"
827 );
828 exit(EXIT_FAILURE);
829}
830
831int main(int argc, char **argv)
832{
833 const char *control_host = NULL;
834 const char *control_port = NULL;
835 struct test_opts opts = {
836 .mode = TEST_MODE_UNSET,
837 .peer_cid = VMADDR_CID_ANY,
838 };
839
840 init_signals();
841
842 for (;;) {
843 int opt = getopt_long(argc, argv, optstring, longopts, NULL);
844
845 if (opt == -1)
846 break;
847
848 switch (opt) {
849 case 'H':
850 control_host = optarg;
851 break;
852 case 'm':
853 if (strcmp(optarg, "client") == 0)
854 opts.mode = TEST_MODE_CLIENT;
855 else if (strcmp(optarg, "server") == 0)
856 opts.mode = TEST_MODE_SERVER;
857 else {
858 fprintf(stderr, "--mode must be \"client\" or \"server\"\n");
859 return EXIT_FAILURE;
860 }
861 break;
862 case 'p':
863 opts.peer_cid = parse_cid(optarg);
864 break;
865 case 'P':
866 control_port = optarg;
867 break;
868 case 'l':
869 list_tests(test_cases);
870 break;
871 case 's':
872 skip_test(test_cases, ARRAY_SIZE(test_cases) - 1,
873 optarg);
874 break;
875 case '?':
876 default:
877 usage();
878 }
879 }
880
881 if (!control_port)
882 usage();
883 if (opts.mode == TEST_MODE_UNSET)
884 usage();
885 if (opts.peer_cid == VMADDR_CID_ANY)
886 usage();
887
888 if (!control_host) {
889 if (opts.mode != TEST_MODE_SERVER)
890 usage();
891 control_host = "0.0.0.0";
892 }
893
894 control_init(control_host, control_port,
895 opts.mode == TEST_MODE_SERVER);
896
897 run_tests(test_cases, &opts);
898
899 control_cleanup();
900 return EXIT_SUCCESS;
901}