xref: /openbmc/linux/tools/testing/vsock/vsock_test.c (revision e89600eb)
1cdbcc18dSStefan Hajnoczi // SPDX-License-Identifier: GPL-2.0-only
2cdbcc18dSStefan Hajnoczi /*
3cdbcc18dSStefan Hajnoczi  * vsock_test - vsock.ko test suite
4cdbcc18dSStefan Hajnoczi  *
5cdbcc18dSStefan Hajnoczi  * Copyright (C) 2017 Red Hat, Inc.
6cdbcc18dSStefan Hajnoczi  *
7cdbcc18dSStefan Hajnoczi  * Author: Stefan Hajnoczi <stefanha@redhat.com>
8cdbcc18dSStefan Hajnoczi  */
9cdbcc18dSStefan Hajnoczi 
10cdbcc18dSStefan Hajnoczi #include <getopt.h>
11cdbcc18dSStefan Hajnoczi #include <stdio.h>
12cdbcc18dSStefan Hajnoczi #include <stdlib.h>
13cdbcc18dSStefan Hajnoczi #include <string.h>
14cdbcc18dSStefan Hajnoczi #include <errno.h>
15cdbcc18dSStefan Hajnoczi #include <unistd.h>
165a2b2425SStefano Garzarella #include <linux/kernel.h>
1741b792d7SArseny Krasnov #include <sys/types.h>
1841b792d7SArseny Krasnov #include <sys/socket.h>
19efb3719fSKrasnov Arseniy Vladimirovich #include <time.h>
20*e89600ebSKrasnov Arseniy Vladimirovich #include <sys/mman.h>
21cdbcc18dSStefan Hajnoczi 
22cdbcc18dSStefan Hajnoczi #include "timeout.h"
23cdbcc18dSStefan Hajnoczi #include "control.h"
24cdbcc18dSStefan Hajnoczi #include "util.h"
25cdbcc18dSStefan Hajnoczi 
26cdbcc18dSStefan Hajnoczi static void test_stream_connection_reset(const struct test_opts *opts)
27cdbcc18dSStefan Hajnoczi {
28cdbcc18dSStefan Hajnoczi 	union {
29cdbcc18dSStefan Hajnoczi 		struct sockaddr sa;
30cdbcc18dSStefan Hajnoczi 		struct sockaddr_vm svm;
31cdbcc18dSStefan Hajnoczi 	} addr = {
32cdbcc18dSStefan Hajnoczi 		.svm = {
33cdbcc18dSStefan Hajnoczi 			.svm_family = AF_VSOCK,
34cdbcc18dSStefan Hajnoczi 			.svm_port = 1234,
35cdbcc18dSStefan Hajnoczi 			.svm_cid = opts->peer_cid,
36cdbcc18dSStefan Hajnoczi 		},
37cdbcc18dSStefan Hajnoczi 	};
38cdbcc18dSStefan Hajnoczi 	int ret;
39cdbcc18dSStefan Hajnoczi 	int fd;
40cdbcc18dSStefan Hajnoczi 
41cdbcc18dSStefan Hajnoczi 	fd = socket(AF_VSOCK, SOCK_STREAM, 0);
42cdbcc18dSStefan Hajnoczi 
43cdbcc18dSStefan Hajnoczi 	timeout_begin(TIMEOUT);
44cdbcc18dSStefan Hajnoczi 	do {
45cdbcc18dSStefan Hajnoczi 		ret = connect(fd, &addr.sa, sizeof(addr.svm));
46cdbcc18dSStefan Hajnoczi 		timeout_check("connect");
47cdbcc18dSStefan Hajnoczi 	} while (ret < 0 && errno == EINTR);
48cdbcc18dSStefan Hajnoczi 	timeout_end();
49cdbcc18dSStefan Hajnoczi 
50cdbcc18dSStefan Hajnoczi 	if (ret != -1) {
51cdbcc18dSStefan Hajnoczi 		fprintf(stderr, "expected connect(2) failure, got %d\n", ret);
52cdbcc18dSStefan Hajnoczi 		exit(EXIT_FAILURE);
53cdbcc18dSStefan Hajnoczi 	}
54cdbcc18dSStefan Hajnoczi 	if (errno != ECONNRESET) {
55cdbcc18dSStefan Hajnoczi 		fprintf(stderr, "unexpected connect(2) errno %d\n", errno);
56cdbcc18dSStefan Hajnoczi 		exit(EXIT_FAILURE);
57cdbcc18dSStefan Hajnoczi 	}
58cdbcc18dSStefan Hajnoczi 
59cdbcc18dSStefan Hajnoczi 	close(fd);
60cdbcc18dSStefan Hajnoczi }
61cdbcc18dSStefan Hajnoczi 
629de9f7d1SSebastien Boeuf static void test_stream_bind_only_client(const struct test_opts *opts)
639de9f7d1SSebastien Boeuf {
649de9f7d1SSebastien Boeuf 	union {
659de9f7d1SSebastien Boeuf 		struct sockaddr sa;
669de9f7d1SSebastien Boeuf 		struct sockaddr_vm svm;
679de9f7d1SSebastien Boeuf 	} addr = {
689de9f7d1SSebastien Boeuf 		.svm = {
699de9f7d1SSebastien Boeuf 			.svm_family = AF_VSOCK,
709de9f7d1SSebastien Boeuf 			.svm_port = 1234,
719de9f7d1SSebastien Boeuf 			.svm_cid = opts->peer_cid,
729de9f7d1SSebastien Boeuf 		},
739de9f7d1SSebastien Boeuf 	};
749de9f7d1SSebastien Boeuf 	int ret;
759de9f7d1SSebastien Boeuf 	int fd;
769de9f7d1SSebastien Boeuf 
779de9f7d1SSebastien Boeuf 	/* Wait for the server to be ready */
789de9f7d1SSebastien Boeuf 	control_expectln("BIND");
799de9f7d1SSebastien Boeuf 
809de9f7d1SSebastien Boeuf 	fd = socket(AF_VSOCK, SOCK_STREAM, 0);
819de9f7d1SSebastien Boeuf 
829de9f7d1SSebastien Boeuf 	timeout_begin(TIMEOUT);
839de9f7d1SSebastien Boeuf 	do {
849de9f7d1SSebastien Boeuf 		ret = connect(fd, &addr.sa, sizeof(addr.svm));
859de9f7d1SSebastien Boeuf 		timeout_check("connect");
869de9f7d1SSebastien Boeuf 	} while (ret < 0 && errno == EINTR);
879de9f7d1SSebastien Boeuf 	timeout_end();
889de9f7d1SSebastien Boeuf 
899de9f7d1SSebastien Boeuf 	if (ret != -1) {
909de9f7d1SSebastien Boeuf 		fprintf(stderr, "expected connect(2) failure, got %d\n", ret);
919de9f7d1SSebastien Boeuf 		exit(EXIT_FAILURE);
929de9f7d1SSebastien Boeuf 	}
939de9f7d1SSebastien Boeuf 	if (errno != ECONNRESET) {
949de9f7d1SSebastien Boeuf 		fprintf(stderr, "unexpected connect(2) errno %d\n", errno);
959de9f7d1SSebastien Boeuf 		exit(EXIT_FAILURE);
969de9f7d1SSebastien Boeuf 	}
979de9f7d1SSebastien Boeuf 
989de9f7d1SSebastien Boeuf 	/* Notify the server that the client has finished */
999de9f7d1SSebastien Boeuf 	control_writeln("DONE");
1009de9f7d1SSebastien Boeuf 
1019de9f7d1SSebastien Boeuf 	close(fd);
1029de9f7d1SSebastien Boeuf }
1039de9f7d1SSebastien Boeuf 
1049de9f7d1SSebastien Boeuf static void test_stream_bind_only_server(const struct test_opts *opts)
1059de9f7d1SSebastien Boeuf {
1069de9f7d1SSebastien Boeuf 	union {
1079de9f7d1SSebastien Boeuf 		struct sockaddr sa;
1089de9f7d1SSebastien Boeuf 		struct sockaddr_vm svm;
1099de9f7d1SSebastien Boeuf 	} addr = {
1109de9f7d1SSebastien Boeuf 		.svm = {
1119de9f7d1SSebastien Boeuf 			.svm_family = AF_VSOCK,
1129de9f7d1SSebastien Boeuf 			.svm_port = 1234,
1139de9f7d1SSebastien Boeuf 			.svm_cid = VMADDR_CID_ANY,
1149de9f7d1SSebastien Boeuf 		},
1159de9f7d1SSebastien Boeuf 	};
1169de9f7d1SSebastien Boeuf 	int fd;
1179de9f7d1SSebastien Boeuf 
1189de9f7d1SSebastien Boeuf 	fd = socket(AF_VSOCK, SOCK_STREAM, 0);
1199de9f7d1SSebastien Boeuf 
1209de9f7d1SSebastien Boeuf 	if (bind(fd, &addr.sa, sizeof(addr.svm)) < 0) {
1219de9f7d1SSebastien Boeuf 		perror("bind");
1229de9f7d1SSebastien Boeuf 		exit(EXIT_FAILURE);
1239de9f7d1SSebastien Boeuf 	}
1249de9f7d1SSebastien Boeuf 
1259de9f7d1SSebastien Boeuf 	/* Notify the client that the server is ready */
1269de9f7d1SSebastien Boeuf 	control_writeln("BIND");
1279de9f7d1SSebastien Boeuf 
1289de9f7d1SSebastien Boeuf 	/* Wait for the client to finish */
1299de9f7d1SSebastien Boeuf 	control_expectln("DONE");
1309de9f7d1SSebastien Boeuf 
1319de9f7d1SSebastien Boeuf 	close(fd);
1329de9f7d1SSebastien Boeuf }
1339de9f7d1SSebastien Boeuf 
134cdbcc18dSStefan Hajnoczi static void test_stream_client_close_client(const struct test_opts *opts)
135cdbcc18dSStefan Hajnoczi {
136cdbcc18dSStefan Hajnoczi 	int fd;
137cdbcc18dSStefan Hajnoczi 
138cdbcc18dSStefan Hajnoczi 	fd = vsock_stream_connect(opts->peer_cid, 1234);
139cdbcc18dSStefan Hajnoczi 	if (fd < 0) {
140cdbcc18dSStefan Hajnoczi 		perror("connect");
141cdbcc18dSStefan Hajnoczi 		exit(EXIT_FAILURE);
142cdbcc18dSStefan Hajnoczi 	}
143cdbcc18dSStefan Hajnoczi 
144cdbcc18dSStefan Hajnoczi 	send_byte(fd, 1, 0);
145cdbcc18dSStefan Hajnoczi 	close(fd);
146cdbcc18dSStefan Hajnoczi }
147cdbcc18dSStefan Hajnoczi 
148cdbcc18dSStefan Hajnoczi static void test_stream_client_close_server(const struct test_opts *opts)
149cdbcc18dSStefan Hajnoczi {
150cdbcc18dSStefan Hajnoczi 	int fd;
151cdbcc18dSStefan Hajnoczi 
152cdbcc18dSStefan Hajnoczi 	fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
153cdbcc18dSStefan Hajnoczi 	if (fd < 0) {
154cdbcc18dSStefan Hajnoczi 		perror("accept");
155cdbcc18dSStefan Hajnoczi 		exit(EXIT_FAILURE);
156cdbcc18dSStefan Hajnoczi 	}
157cdbcc18dSStefan Hajnoczi 
158770ce007SStefano Garzarella 	/* Wait for the remote to close the connection, before check
159770ce007SStefano Garzarella 	 * -EPIPE error on send.
160770ce007SStefano Garzarella 	 */
161770ce007SStefano Garzarella 	vsock_wait_remote_close(fd);
162cdbcc18dSStefan Hajnoczi 
163cdbcc18dSStefan Hajnoczi 	send_byte(fd, -EPIPE, 0);
164cdbcc18dSStefan Hajnoczi 	recv_byte(fd, 1, 0);
165cdbcc18dSStefan Hajnoczi 	recv_byte(fd, 0, 0);
166cdbcc18dSStefan Hajnoczi 	close(fd);
167cdbcc18dSStefan Hajnoczi }
168cdbcc18dSStefan Hajnoczi 
169cdbcc18dSStefan Hajnoczi static void test_stream_server_close_client(const struct test_opts *opts)
170cdbcc18dSStefan Hajnoczi {
171cdbcc18dSStefan Hajnoczi 	int fd;
172cdbcc18dSStefan Hajnoczi 
173cdbcc18dSStefan Hajnoczi 	fd = vsock_stream_connect(opts->peer_cid, 1234);
174cdbcc18dSStefan Hajnoczi 	if (fd < 0) {
175cdbcc18dSStefan Hajnoczi 		perror("connect");
176cdbcc18dSStefan Hajnoczi 		exit(EXIT_FAILURE);
177cdbcc18dSStefan Hajnoczi 	}
178cdbcc18dSStefan Hajnoczi 
179770ce007SStefano Garzarella 	/* Wait for the remote to close the connection, before check
180770ce007SStefano Garzarella 	 * -EPIPE error on send.
181770ce007SStefano Garzarella 	 */
182770ce007SStefano Garzarella 	vsock_wait_remote_close(fd);
183cdbcc18dSStefan Hajnoczi 
184cdbcc18dSStefan Hajnoczi 	send_byte(fd, -EPIPE, 0);
185cdbcc18dSStefan Hajnoczi 	recv_byte(fd, 1, 0);
186cdbcc18dSStefan Hajnoczi 	recv_byte(fd, 0, 0);
187cdbcc18dSStefan Hajnoczi 	close(fd);
188cdbcc18dSStefan Hajnoczi }
189cdbcc18dSStefan Hajnoczi 
190cdbcc18dSStefan Hajnoczi static void test_stream_server_close_server(const struct test_opts *opts)
191cdbcc18dSStefan Hajnoczi {
192cdbcc18dSStefan Hajnoczi 	int fd;
193cdbcc18dSStefan Hajnoczi 
194cdbcc18dSStefan Hajnoczi 	fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
195cdbcc18dSStefan Hajnoczi 	if (fd < 0) {
196cdbcc18dSStefan Hajnoczi 		perror("accept");
197cdbcc18dSStefan Hajnoczi 		exit(EXIT_FAILURE);
198cdbcc18dSStefan Hajnoczi 	}
199cdbcc18dSStefan Hajnoczi 
200cdbcc18dSStefan Hajnoczi 	send_byte(fd, 1, 0);
201cdbcc18dSStefan Hajnoczi 	close(fd);
202cdbcc18dSStefan Hajnoczi }
203cdbcc18dSStefan Hajnoczi 
204cdbcc18dSStefan Hajnoczi /* With the standard socket sizes, VMCI is able to support about 100
205cdbcc18dSStefan Hajnoczi  * concurrent stream connections.
206cdbcc18dSStefan Hajnoczi  */
207cdbcc18dSStefan Hajnoczi #define MULTICONN_NFDS 100
208cdbcc18dSStefan Hajnoczi 
209cdbcc18dSStefan Hajnoczi static void test_stream_multiconn_client(const struct test_opts *opts)
210cdbcc18dSStefan Hajnoczi {
211cdbcc18dSStefan Hajnoczi 	int fds[MULTICONN_NFDS];
212cdbcc18dSStefan Hajnoczi 	int i;
213cdbcc18dSStefan Hajnoczi 
214cdbcc18dSStefan Hajnoczi 	for (i = 0; i < MULTICONN_NFDS; i++) {
215cdbcc18dSStefan Hajnoczi 		fds[i] = vsock_stream_connect(opts->peer_cid, 1234);
216cdbcc18dSStefan Hajnoczi 		if (fds[i] < 0) {
217cdbcc18dSStefan Hajnoczi 			perror("connect");
218cdbcc18dSStefan Hajnoczi 			exit(EXIT_FAILURE);
219cdbcc18dSStefan Hajnoczi 		}
220cdbcc18dSStefan Hajnoczi 	}
221cdbcc18dSStefan Hajnoczi 
222cdbcc18dSStefan Hajnoczi 	for (i = 0; i < MULTICONN_NFDS; i++) {
223cdbcc18dSStefan Hajnoczi 		if (i % 2)
224cdbcc18dSStefan Hajnoczi 			recv_byte(fds[i], 1, 0);
225cdbcc18dSStefan Hajnoczi 		else
226cdbcc18dSStefan Hajnoczi 			send_byte(fds[i], 1, 0);
227cdbcc18dSStefan Hajnoczi 	}
228cdbcc18dSStefan Hajnoczi 
229cdbcc18dSStefan Hajnoczi 	for (i = 0; i < MULTICONN_NFDS; i++)
230cdbcc18dSStefan Hajnoczi 		close(fds[i]);
231cdbcc18dSStefan Hajnoczi }
232cdbcc18dSStefan Hajnoczi 
233cdbcc18dSStefan Hajnoczi static void test_stream_multiconn_server(const struct test_opts *opts)
234cdbcc18dSStefan Hajnoczi {
235cdbcc18dSStefan Hajnoczi 	int fds[MULTICONN_NFDS];
236cdbcc18dSStefan Hajnoczi 	int i;
237cdbcc18dSStefan Hajnoczi 
238cdbcc18dSStefan Hajnoczi 	for (i = 0; i < MULTICONN_NFDS; i++) {
239cdbcc18dSStefan Hajnoczi 		fds[i] = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
240cdbcc18dSStefan Hajnoczi 		if (fds[i] < 0) {
241cdbcc18dSStefan Hajnoczi 			perror("accept");
242cdbcc18dSStefan Hajnoczi 			exit(EXIT_FAILURE);
243cdbcc18dSStefan Hajnoczi 		}
244cdbcc18dSStefan Hajnoczi 	}
245cdbcc18dSStefan Hajnoczi 
246cdbcc18dSStefan Hajnoczi 	for (i = 0; i < MULTICONN_NFDS; i++) {
247cdbcc18dSStefan Hajnoczi 		if (i % 2)
248cdbcc18dSStefan Hajnoczi 			send_byte(fds[i], 1, 0);
249cdbcc18dSStefan Hajnoczi 		else
250cdbcc18dSStefan Hajnoczi 			recv_byte(fds[i], 1, 0);
251cdbcc18dSStefan Hajnoczi 	}
252cdbcc18dSStefan Hajnoczi 
253cdbcc18dSStefan Hajnoczi 	for (i = 0; i < MULTICONN_NFDS; i++)
254cdbcc18dSStefan Hajnoczi 		close(fds[i]);
255cdbcc18dSStefan Hajnoczi }
256cdbcc18dSStefan Hajnoczi 
257d6269a93SStefano Garzarella static void test_stream_msg_peek_client(const struct test_opts *opts)
258d6269a93SStefano Garzarella {
259d6269a93SStefano Garzarella 	int fd;
260d6269a93SStefano Garzarella 
261d6269a93SStefano Garzarella 	fd = vsock_stream_connect(opts->peer_cid, 1234);
262d6269a93SStefano Garzarella 	if (fd < 0) {
263d6269a93SStefano Garzarella 		perror("connect");
264d6269a93SStefano Garzarella 		exit(EXIT_FAILURE);
265d6269a93SStefano Garzarella 	}
266d6269a93SStefano Garzarella 
267d6269a93SStefano Garzarella 	send_byte(fd, 1, 0);
268d6269a93SStefano Garzarella 	close(fd);
269d6269a93SStefano Garzarella }
270d6269a93SStefano Garzarella 
271d6269a93SStefano Garzarella static void test_stream_msg_peek_server(const struct test_opts *opts)
272d6269a93SStefano Garzarella {
273d6269a93SStefano Garzarella 	int fd;
274d6269a93SStefano Garzarella 
275d6269a93SStefano Garzarella 	fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
276d6269a93SStefano Garzarella 	if (fd < 0) {
277d6269a93SStefano Garzarella 		perror("accept");
278d6269a93SStefano Garzarella 		exit(EXIT_FAILURE);
279d6269a93SStefano Garzarella 	}
280d6269a93SStefano Garzarella 
281d6269a93SStefano Garzarella 	recv_byte(fd, 1, MSG_PEEK);
282d6269a93SStefano Garzarella 	recv_byte(fd, 1, 0);
283d6269a93SStefano Garzarella 	close(fd);
284d6269a93SStefano Garzarella }
285d6269a93SStefano Garzarella 
28641b792d7SArseny Krasnov #define MESSAGES_CNT 7
2870e115c45SArseny Krasnov #define MSG_EOR_IDX (MESSAGES_CNT / 2)
28841b792d7SArseny Krasnov static void test_seqpacket_msg_bounds_client(const struct test_opts *opts)
28941b792d7SArseny Krasnov {
29041b792d7SArseny Krasnov 	int fd;
29141b792d7SArseny Krasnov 
29241b792d7SArseny Krasnov 	fd = vsock_seqpacket_connect(opts->peer_cid, 1234);
29341b792d7SArseny Krasnov 	if (fd < 0) {
29441b792d7SArseny Krasnov 		perror("connect");
29541b792d7SArseny Krasnov 		exit(EXIT_FAILURE);
29641b792d7SArseny Krasnov 	}
29741b792d7SArseny Krasnov 
29841b792d7SArseny Krasnov 	/* Send several messages, one with MSG_EOR flag */
29941b792d7SArseny Krasnov 	for (int i = 0; i < MESSAGES_CNT; i++)
3000e115c45SArseny Krasnov 		send_byte(fd, 1, (i == MSG_EOR_IDX) ? MSG_EOR : 0);
30141b792d7SArseny Krasnov 
30241b792d7SArseny Krasnov 	control_writeln("SENDDONE");
30341b792d7SArseny Krasnov 	close(fd);
30441b792d7SArseny Krasnov }
30541b792d7SArseny Krasnov 
30641b792d7SArseny Krasnov static void test_seqpacket_msg_bounds_server(const struct test_opts *opts)
30741b792d7SArseny Krasnov {
30841b792d7SArseny Krasnov 	int fd;
30941b792d7SArseny Krasnov 	char buf[16];
31041b792d7SArseny Krasnov 	struct msghdr msg = {0};
31141b792d7SArseny Krasnov 	struct iovec iov = {0};
31241b792d7SArseny Krasnov 
31341b792d7SArseny Krasnov 	fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL);
31441b792d7SArseny Krasnov 	if (fd < 0) {
31541b792d7SArseny Krasnov 		perror("accept");
31641b792d7SArseny Krasnov 		exit(EXIT_FAILURE);
31741b792d7SArseny Krasnov 	}
31841b792d7SArseny Krasnov 
31941b792d7SArseny Krasnov 	control_expectln("SENDDONE");
32041b792d7SArseny Krasnov 	iov.iov_base = buf;
32141b792d7SArseny Krasnov 	iov.iov_len = sizeof(buf);
32241b792d7SArseny Krasnov 	msg.msg_iov = &iov;
32341b792d7SArseny Krasnov 	msg.msg_iovlen = 1;
32441b792d7SArseny Krasnov 
32541b792d7SArseny Krasnov 	for (int i = 0; i < MESSAGES_CNT; i++) {
32641b792d7SArseny Krasnov 		if (recvmsg(fd, &msg, 0) != 1) {
32741b792d7SArseny Krasnov 			perror("message bound violated");
32841b792d7SArseny Krasnov 			exit(EXIT_FAILURE);
32941b792d7SArseny Krasnov 		}
3300e115c45SArseny Krasnov 
3310e115c45SArseny Krasnov 		if ((i == MSG_EOR_IDX) ^ !!(msg.msg_flags & MSG_EOR)) {
3320e115c45SArseny Krasnov 			perror("MSG_EOR");
3330e115c45SArseny Krasnov 			exit(EXIT_FAILURE);
3340e115c45SArseny Krasnov 		}
33541b792d7SArseny Krasnov 	}
33641b792d7SArseny Krasnov 
33741b792d7SArseny Krasnov 	close(fd);
33841b792d7SArseny Krasnov }
33941b792d7SArseny Krasnov 
34041b792d7SArseny Krasnov #define MESSAGE_TRUNC_SZ 32
34141b792d7SArseny Krasnov static void test_seqpacket_msg_trunc_client(const struct test_opts *opts)
34241b792d7SArseny Krasnov {
34341b792d7SArseny Krasnov 	int fd;
34441b792d7SArseny Krasnov 	char buf[MESSAGE_TRUNC_SZ];
34541b792d7SArseny Krasnov 
34641b792d7SArseny Krasnov 	fd = vsock_seqpacket_connect(opts->peer_cid, 1234);
34741b792d7SArseny Krasnov 	if (fd < 0) {
34841b792d7SArseny Krasnov 		perror("connect");
34941b792d7SArseny Krasnov 		exit(EXIT_FAILURE);
35041b792d7SArseny Krasnov 	}
35141b792d7SArseny Krasnov 
35241b792d7SArseny Krasnov 	if (send(fd, buf, sizeof(buf), 0) != sizeof(buf)) {
35341b792d7SArseny Krasnov 		perror("send failed");
35441b792d7SArseny Krasnov 		exit(EXIT_FAILURE);
35541b792d7SArseny Krasnov 	}
35641b792d7SArseny Krasnov 
35741b792d7SArseny Krasnov 	control_writeln("SENDDONE");
35841b792d7SArseny Krasnov 	close(fd);
35941b792d7SArseny Krasnov }
36041b792d7SArseny Krasnov 
36141b792d7SArseny Krasnov static void test_seqpacket_msg_trunc_server(const struct test_opts *opts)
36241b792d7SArseny Krasnov {
36341b792d7SArseny Krasnov 	int fd;
36441b792d7SArseny Krasnov 	char buf[MESSAGE_TRUNC_SZ / 2];
36541b792d7SArseny Krasnov 	struct msghdr msg = {0};
36641b792d7SArseny Krasnov 	struct iovec iov = {0};
36741b792d7SArseny Krasnov 
36841b792d7SArseny Krasnov 	fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL);
36941b792d7SArseny Krasnov 	if (fd < 0) {
37041b792d7SArseny Krasnov 		perror("accept");
37141b792d7SArseny Krasnov 		exit(EXIT_FAILURE);
37241b792d7SArseny Krasnov 	}
37341b792d7SArseny Krasnov 
37441b792d7SArseny Krasnov 	control_expectln("SENDDONE");
37541b792d7SArseny Krasnov 	iov.iov_base = buf;
37641b792d7SArseny Krasnov 	iov.iov_len = sizeof(buf);
37741b792d7SArseny Krasnov 	msg.msg_iov = &iov;
37841b792d7SArseny Krasnov 	msg.msg_iovlen = 1;
37941b792d7SArseny Krasnov 
38041b792d7SArseny Krasnov 	ssize_t ret = recvmsg(fd, &msg, MSG_TRUNC);
38141b792d7SArseny Krasnov 
38241b792d7SArseny Krasnov 	if (ret != MESSAGE_TRUNC_SZ) {
38341b792d7SArseny Krasnov 		printf("%zi\n", ret);
38441b792d7SArseny Krasnov 		perror("MSG_TRUNC doesn't work");
38541b792d7SArseny Krasnov 		exit(EXIT_FAILURE);
38641b792d7SArseny Krasnov 	}
38741b792d7SArseny Krasnov 
38841b792d7SArseny Krasnov 	if (!(msg.msg_flags & MSG_TRUNC)) {
38941b792d7SArseny Krasnov 		fprintf(stderr, "MSG_TRUNC expected\n");
39041b792d7SArseny Krasnov 		exit(EXIT_FAILURE);
39141b792d7SArseny Krasnov 	}
39241b792d7SArseny Krasnov 
39341b792d7SArseny Krasnov 	close(fd);
39441b792d7SArseny Krasnov }
39541b792d7SArseny Krasnov 
396efb3719fSKrasnov Arseniy Vladimirovich static time_t current_nsec(void)
397efb3719fSKrasnov Arseniy Vladimirovich {
398efb3719fSKrasnov Arseniy Vladimirovich 	struct timespec ts;
399efb3719fSKrasnov Arseniy Vladimirovich 
400efb3719fSKrasnov Arseniy Vladimirovich 	if (clock_gettime(CLOCK_REALTIME, &ts)) {
401efb3719fSKrasnov Arseniy Vladimirovich 		perror("clock_gettime(3) failed");
402efb3719fSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
403efb3719fSKrasnov Arseniy Vladimirovich 	}
404efb3719fSKrasnov Arseniy Vladimirovich 
405efb3719fSKrasnov Arseniy Vladimirovich 	return (ts.tv_sec * 1000000000ULL) + ts.tv_nsec;
406efb3719fSKrasnov Arseniy Vladimirovich }
407efb3719fSKrasnov Arseniy Vladimirovich 
408efb3719fSKrasnov Arseniy Vladimirovich #define RCVTIMEO_TIMEOUT_SEC 1
409efb3719fSKrasnov Arseniy Vladimirovich #define READ_OVERHEAD_NSEC 250000000 /* 0.25 sec */
410efb3719fSKrasnov Arseniy Vladimirovich 
411efb3719fSKrasnov Arseniy Vladimirovich static void test_seqpacket_timeout_client(const struct test_opts *opts)
412efb3719fSKrasnov Arseniy Vladimirovich {
413efb3719fSKrasnov Arseniy Vladimirovich 	int fd;
414efb3719fSKrasnov Arseniy Vladimirovich 	struct timeval tv;
415efb3719fSKrasnov Arseniy Vladimirovich 	char dummy;
416efb3719fSKrasnov Arseniy Vladimirovich 	time_t read_enter_ns;
417efb3719fSKrasnov Arseniy Vladimirovich 	time_t read_overhead_ns;
418efb3719fSKrasnov Arseniy Vladimirovich 
419efb3719fSKrasnov Arseniy Vladimirovich 	fd = vsock_seqpacket_connect(opts->peer_cid, 1234);
420efb3719fSKrasnov Arseniy Vladimirovich 	if (fd < 0) {
421efb3719fSKrasnov Arseniy Vladimirovich 		perror("connect");
422efb3719fSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
423efb3719fSKrasnov Arseniy Vladimirovich 	}
424efb3719fSKrasnov Arseniy Vladimirovich 
425efb3719fSKrasnov Arseniy Vladimirovich 	tv.tv_sec = RCVTIMEO_TIMEOUT_SEC;
426efb3719fSKrasnov Arseniy Vladimirovich 	tv.tv_usec = 0;
427efb3719fSKrasnov Arseniy Vladimirovich 
428efb3719fSKrasnov Arseniy Vladimirovich 	if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (void *)&tv, sizeof(tv)) == -1) {
429efb3719fSKrasnov Arseniy Vladimirovich 		perror("setsockopt 'SO_RCVTIMEO'");
430efb3719fSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
431efb3719fSKrasnov Arseniy Vladimirovich 	}
432efb3719fSKrasnov Arseniy Vladimirovich 
433efb3719fSKrasnov Arseniy Vladimirovich 	read_enter_ns = current_nsec();
434efb3719fSKrasnov Arseniy Vladimirovich 
435efb3719fSKrasnov Arseniy Vladimirovich 	if (read(fd, &dummy, sizeof(dummy)) != -1) {
436efb3719fSKrasnov Arseniy Vladimirovich 		fprintf(stderr,
437efb3719fSKrasnov Arseniy Vladimirovich 			"expected 'dummy' read(2) failure\n");
438efb3719fSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
439efb3719fSKrasnov Arseniy Vladimirovich 	}
440efb3719fSKrasnov Arseniy Vladimirovich 
441efb3719fSKrasnov Arseniy Vladimirovich 	if (errno != EAGAIN) {
442efb3719fSKrasnov Arseniy Vladimirovich 		perror("EAGAIN expected");
443efb3719fSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
444efb3719fSKrasnov Arseniy Vladimirovich 	}
445efb3719fSKrasnov Arseniy Vladimirovich 
446efb3719fSKrasnov Arseniy Vladimirovich 	read_overhead_ns = current_nsec() - read_enter_ns -
447efb3719fSKrasnov Arseniy Vladimirovich 			1000000000ULL * RCVTIMEO_TIMEOUT_SEC;
448efb3719fSKrasnov Arseniy Vladimirovich 
449efb3719fSKrasnov Arseniy Vladimirovich 	if (read_overhead_ns > READ_OVERHEAD_NSEC) {
450efb3719fSKrasnov Arseniy Vladimirovich 		fprintf(stderr,
451efb3719fSKrasnov Arseniy Vladimirovich 			"too much time in read(2), %lu > %i ns\n",
452efb3719fSKrasnov Arseniy Vladimirovich 			read_overhead_ns, READ_OVERHEAD_NSEC);
453efb3719fSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
454efb3719fSKrasnov Arseniy Vladimirovich 	}
455efb3719fSKrasnov Arseniy Vladimirovich 
456efb3719fSKrasnov Arseniy Vladimirovich 	control_writeln("WAITDONE");
457efb3719fSKrasnov Arseniy Vladimirovich 	close(fd);
458efb3719fSKrasnov Arseniy Vladimirovich }
459efb3719fSKrasnov Arseniy Vladimirovich 
460efb3719fSKrasnov Arseniy Vladimirovich static void test_seqpacket_timeout_server(const struct test_opts *opts)
461efb3719fSKrasnov Arseniy Vladimirovich {
462efb3719fSKrasnov Arseniy Vladimirovich 	int fd;
463efb3719fSKrasnov Arseniy Vladimirovich 
464efb3719fSKrasnov Arseniy Vladimirovich 	fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL);
465efb3719fSKrasnov Arseniy Vladimirovich 	if (fd < 0) {
466efb3719fSKrasnov Arseniy Vladimirovich 		perror("accept");
467efb3719fSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
468efb3719fSKrasnov Arseniy Vladimirovich 	}
469efb3719fSKrasnov Arseniy Vladimirovich 
470efb3719fSKrasnov Arseniy Vladimirovich 	control_expectln("WAITDONE");
471efb3719fSKrasnov Arseniy Vladimirovich 	close(fd);
472efb3719fSKrasnov Arseniy Vladimirovich }
473efb3719fSKrasnov Arseniy Vladimirovich 
474*e89600ebSKrasnov Arseniy Vladimirovich #define BUF_PATTERN_1 'a'
475*e89600ebSKrasnov Arseniy Vladimirovich #define BUF_PATTERN_2 'b'
476*e89600ebSKrasnov Arseniy Vladimirovich 
477*e89600ebSKrasnov Arseniy Vladimirovich static void test_seqpacket_invalid_rec_buffer_client(const struct test_opts *opts)
478*e89600ebSKrasnov Arseniy Vladimirovich {
479*e89600ebSKrasnov Arseniy Vladimirovich 	int fd;
480*e89600ebSKrasnov Arseniy Vladimirovich 	unsigned char *buf1;
481*e89600ebSKrasnov Arseniy Vladimirovich 	unsigned char *buf2;
482*e89600ebSKrasnov Arseniy Vladimirovich 	int buf_size = getpagesize() * 3;
483*e89600ebSKrasnov Arseniy Vladimirovich 
484*e89600ebSKrasnov Arseniy Vladimirovich 	fd = vsock_seqpacket_connect(opts->peer_cid, 1234);
485*e89600ebSKrasnov Arseniy Vladimirovich 	if (fd < 0) {
486*e89600ebSKrasnov Arseniy Vladimirovich 		perror("connect");
487*e89600ebSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
488*e89600ebSKrasnov Arseniy Vladimirovich 	}
489*e89600ebSKrasnov Arseniy Vladimirovich 
490*e89600ebSKrasnov Arseniy Vladimirovich 	buf1 = malloc(buf_size);
491*e89600ebSKrasnov Arseniy Vladimirovich 	if (!buf1) {
492*e89600ebSKrasnov Arseniy Vladimirovich 		perror("'malloc()' for 'buf1'");
493*e89600ebSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
494*e89600ebSKrasnov Arseniy Vladimirovich 	}
495*e89600ebSKrasnov Arseniy Vladimirovich 
496*e89600ebSKrasnov Arseniy Vladimirovich 	buf2 = malloc(buf_size);
497*e89600ebSKrasnov Arseniy Vladimirovich 	if (!buf2) {
498*e89600ebSKrasnov Arseniy Vladimirovich 		perror("'malloc()' for 'buf2'");
499*e89600ebSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
500*e89600ebSKrasnov Arseniy Vladimirovich 	}
501*e89600ebSKrasnov Arseniy Vladimirovich 
502*e89600ebSKrasnov Arseniy Vladimirovich 	memset(buf1, BUF_PATTERN_1, buf_size);
503*e89600ebSKrasnov Arseniy Vladimirovich 	memset(buf2, BUF_PATTERN_2, buf_size);
504*e89600ebSKrasnov Arseniy Vladimirovich 
505*e89600ebSKrasnov Arseniy Vladimirovich 	if (send(fd, buf1, buf_size, 0) != buf_size) {
506*e89600ebSKrasnov Arseniy Vladimirovich 		perror("send failed");
507*e89600ebSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
508*e89600ebSKrasnov Arseniy Vladimirovich 	}
509*e89600ebSKrasnov Arseniy Vladimirovich 
510*e89600ebSKrasnov Arseniy Vladimirovich 	if (send(fd, buf2, buf_size, 0) != buf_size) {
511*e89600ebSKrasnov Arseniy Vladimirovich 		perror("send failed");
512*e89600ebSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
513*e89600ebSKrasnov Arseniy Vladimirovich 	}
514*e89600ebSKrasnov Arseniy Vladimirovich 
515*e89600ebSKrasnov Arseniy Vladimirovich 	close(fd);
516*e89600ebSKrasnov Arseniy Vladimirovich }
517*e89600ebSKrasnov Arseniy Vladimirovich 
518*e89600ebSKrasnov Arseniy Vladimirovich static void test_seqpacket_invalid_rec_buffer_server(const struct test_opts *opts)
519*e89600ebSKrasnov Arseniy Vladimirovich {
520*e89600ebSKrasnov Arseniy Vladimirovich 	int fd;
521*e89600ebSKrasnov Arseniy Vladimirovich 	unsigned char *broken_buf;
522*e89600ebSKrasnov Arseniy Vladimirovich 	unsigned char *valid_buf;
523*e89600ebSKrasnov Arseniy Vladimirovich 	int page_size = getpagesize();
524*e89600ebSKrasnov Arseniy Vladimirovich 	int buf_size = page_size * 3;
525*e89600ebSKrasnov Arseniy Vladimirovich 	ssize_t res;
526*e89600ebSKrasnov Arseniy Vladimirovich 	int prot = PROT_READ | PROT_WRITE;
527*e89600ebSKrasnov Arseniy Vladimirovich 	int flags = MAP_PRIVATE | MAP_ANONYMOUS;
528*e89600ebSKrasnov Arseniy Vladimirovich 	int i;
529*e89600ebSKrasnov Arseniy Vladimirovich 
530*e89600ebSKrasnov Arseniy Vladimirovich 	fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL);
531*e89600ebSKrasnov Arseniy Vladimirovich 	if (fd < 0) {
532*e89600ebSKrasnov Arseniy Vladimirovich 		perror("accept");
533*e89600ebSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
534*e89600ebSKrasnov Arseniy Vladimirovich 	}
535*e89600ebSKrasnov Arseniy Vladimirovich 
536*e89600ebSKrasnov Arseniy Vladimirovich 	/* Setup first buffer. */
537*e89600ebSKrasnov Arseniy Vladimirovich 	broken_buf = mmap(NULL, buf_size, prot, flags, -1, 0);
538*e89600ebSKrasnov Arseniy Vladimirovich 	if (broken_buf == MAP_FAILED) {
539*e89600ebSKrasnov Arseniy Vladimirovich 		perror("mmap for 'broken_buf'");
540*e89600ebSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
541*e89600ebSKrasnov Arseniy Vladimirovich 	}
542*e89600ebSKrasnov Arseniy Vladimirovich 
543*e89600ebSKrasnov Arseniy Vladimirovich 	/* Unmap "hole" in buffer. */
544*e89600ebSKrasnov Arseniy Vladimirovich 	if (munmap(broken_buf + page_size, page_size)) {
545*e89600ebSKrasnov Arseniy Vladimirovich 		perror("'broken_buf' setup");
546*e89600ebSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
547*e89600ebSKrasnov Arseniy Vladimirovich 	}
548*e89600ebSKrasnov Arseniy Vladimirovich 
549*e89600ebSKrasnov Arseniy Vladimirovich 	valid_buf = mmap(NULL, buf_size, prot, flags, -1, 0);
550*e89600ebSKrasnov Arseniy Vladimirovich 	if (valid_buf == MAP_FAILED) {
551*e89600ebSKrasnov Arseniy Vladimirovich 		perror("mmap for 'valid_buf'");
552*e89600ebSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
553*e89600ebSKrasnov Arseniy Vladimirovich 	}
554*e89600ebSKrasnov Arseniy Vladimirovich 
555*e89600ebSKrasnov Arseniy Vladimirovich 	/* Try to fill buffer with unmapped middle. */
556*e89600ebSKrasnov Arseniy Vladimirovich 	res = read(fd, broken_buf, buf_size);
557*e89600ebSKrasnov Arseniy Vladimirovich 	if (res != -1) {
558*e89600ebSKrasnov Arseniy Vladimirovich 		fprintf(stderr,
559*e89600ebSKrasnov Arseniy Vladimirovich 			"expected 'broken_buf' read(2) failure, got %zi\n",
560*e89600ebSKrasnov Arseniy Vladimirovich 			res);
561*e89600ebSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
562*e89600ebSKrasnov Arseniy Vladimirovich 	}
563*e89600ebSKrasnov Arseniy Vladimirovich 
564*e89600ebSKrasnov Arseniy Vladimirovich 	if (errno != ENOMEM) {
565*e89600ebSKrasnov Arseniy Vladimirovich 		perror("unexpected errno of 'broken_buf'");
566*e89600ebSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
567*e89600ebSKrasnov Arseniy Vladimirovich 	}
568*e89600ebSKrasnov Arseniy Vladimirovich 
569*e89600ebSKrasnov Arseniy Vladimirovich 	/* Try to fill valid buffer. */
570*e89600ebSKrasnov Arseniy Vladimirovich 	res = read(fd, valid_buf, buf_size);
571*e89600ebSKrasnov Arseniy Vladimirovich 	if (res < 0) {
572*e89600ebSKrasnov Arseniy Vladimirovich 		perror("unexpected 'valid_buf' read(2) failure");
573*e89600ebSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
574*e89600ebSKrasnov Arseniy Vladimirovich 	}
575*e89600ebSKrasnov Arseniy Vladimirovich 
576*e89600ebSKrasnov Arseniy Vladimirovich 	if (res != buf_size) {
577*e89600ebSKrasnov Arseniy Vladimirovich 		fprintf(stderr,
578*e89600ebSKrasnov Arseniy Vladimirovich 			"invalid 'valid_buf' read(2), expected %i, got %zi\n",
579*e89600ebSKrasnov Arseniy Vladimirovich 			buf_size, res);
580*e89600ebSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
581*e89600ebSKrasnov Arseniy Vladimirovich 	}
582*e89600ebSKrasnov Arseniy Vladimirovich 
583*e89600ebSKrasnov Arseniy Vladimirovich 	for (i = 0; i < buf_size; i++) {
584*e89600ebSKrasnov Arseniy Vladimirovich 		if (valid_buf[i] != BUF_PATTERN_2) {
585*e89600ebSKrasnov Arseniy Vladimirovich 			fprintf(stderr,
586*e89600ebSKrasnov Arseniy Vladimirovich 				"invalid pattern for 'valid_buf' at %i, expected %hhX, got %hhX\n",
587*e89600ebSKrasnov Arseniy Vladimirovich 				i, BUF_PATTERN_2, valid_buf[i]);
588*e89600ebSKrasnov Arseniy Vladimirovich 			exit(EXIT_FAILURE);
589*e89600ebSKrasnov Arseniy Vladimirovich 		}
590*e89600ebSKrasnov Arseniy Vladimirovich 	}
591*e89600ebSKrasnov Arseniy Vladimirovich 
592*e89600ebSKrasnov Arseniy Vladimirovich 	/* Unmap buffers. */
593*e89600ebSKrasnov Arseniy Vladimirovich 	munmap(broken_buf, page_size);
594*e89600ebSKrasnov Arseniy Vladimirovich 	munmap(broken_buf + page_size * 2, page_size);
595*e89600ebSKrasnov Arseniy Vladimirovich 	munmap(valid_buf, buf_size);
596*e89600ebSKrasnov Arseniy Vladimirovich 	close(fd);
597*e89600ebSKrasnov Arseniy Vladimirovich }
598*e89600ebSKrasnov Arseniy Vladimirovich 
599cdbcc18dSStefan Hajnoczi static struct test_case test_cases[] = {
600cdbcc18dSStefan Hajnoczi 	{
601cdbcc18dSStefan Hajnoczi 		.name = "SOCK_STREAM connection reset",
602cdbcc18dSStefan Hajnoczi 		.run_client = test_stream_connection_reset,
603cdbcc18dSStefan Hajnoczi 	},
604cdbcc18dSStefan Hajnoczi 	{
6059de9f7d1SSebastien Boeuf 		.name = "SOCK_STREAM bind only",
6069de9f7d1SSebastien Boeuf 		.run_client = test_stream_bind_only_client,
6079de9f7d1SSebastien Boeuf 		.run_server = test_stream_bind_only_server,
6089de9f7d1SSebastien Boeuf 	},
6099de9f7d1SSebastien Boeuf 	{
610cdbcc18dSStefan Hajnoczi 		.name = "SOCK_STREAM client close",
611cdbcc18dSStefan Hajnoczi 		.run_client = test_stream_client_close_client,
612cdbcc18dSStefan Hajnoczi 		.run_server = test_stream_client_close_server,
613cdbcc18dSStefan Hajnoczi 	},
614cdbcc18dSStefan Hajnoczi 	{
615cdbcc18dSStefan Hajnoczi 		.name = "SOCK_STREAM server close",
616cdbcc18dSStefan Hajnoczi 		.run_client = test_stream_server_close_client,
617cdbcc18dSStefan Hajnoczi 		.run_server = test_stream_server_close_server,
618cdbcc18dSStefan Hajnoczi 	},
619cdbcc18dSStefan Hajnoczi 	{
620cdbcc18dSStefan Hajnoczi 		.name = "SOCK_STREAM multiple connections",
621cdbcc18dSStefan Hajnoczi 		.run_client = test_stream_multiconn_client,
622cdbcc18dSStefan Hajnoczi 		.run_server = test_stream_multiconn_server,
623cdbcc18dSStefan Hajnoczi 	},
624d6269a93SStefano Garzarella 	{
625d6269a93SStefano Garzarella 		.name = "SOCK_STREAM MSG_PEEK",
626d6269a93SStefano Garzarella 		.run_client = test_stream_msg_peek_client,
627d6269a93SStefano Garzarella 		.run_server = test_stream_msg_peek_server,
628d6269a93SStefano Garzarella 	},
62941b792d7SArseny Krasnov 	{
63041b792d7SArseny Krasnov 		.name = "SOCK_SEQPACKET msg bounds",
63141b792d7SArseny Krasnov 		.run_client = test_seqpacket_msg_bounds_client,
63241b792d7SArseny Krasnov 		.run_server = test_seqpacket_msg_bounds_server,
63341b792d7SArseny Krasnov 	},
63441b792d7SArseny Krasnov 	{
63541b792d7SArseny Krasnov 		.name = "SOCK_SEQPACKET MSG_TRUNC flag",
63641b792d7SArseny Krasnov 		.run_client = test_seqpacket_msg_trunc_client,
63741b792d7SArseny Krasnov 		.run_server = test_seqpacket_msg_trunc_server,
63841b792d7SArseny Krasnov 	},
639efb3719fSKrasnov Arseniy Vladimirovich 	{
640efb3719fSKrasnov Arseniy Vladimirovich 		.name = "SOCK_SEQPACKET timeout",
641efb3719fSKrasnov Arseniy Vladimirovich 		.run_client = test_seqpacket_timeout_client,
642efb3719fSKrasnov Arseniy Vladimirovich 		.run_server = test_seqpacket_timeout_server,
643efb3719fSKrasnov Arseniy Vladimirovich 	},
644*e89600ebSKrasnov Arseniy Vladimirovich 	{
645*e89600ebSKrasnov Arseniy Vladimirovich 		.name = "SOCK_SEQPACKET invalid receive buffer",
646*e89600ebSKrasnov Arseniy Vladimirovich 		.run_client = test_seqpacket_invalid_rec_buffer_client,
647*e89600ebSKrasnov Arseniy Vladimirovich 		.run_server = test_seqpacket_invalid_rec_buffer_server,
648*e89600ebSKrasnov Arseniy Vladimirovich 	},
649cdbcc18dSStefan Hajnoczi 	{},
650cdbcc18dSStefan Hajnoczi };
651cdbcc18dSStefan Hajnoczi 
652cdbcc18dSStefan Hajnoczi static const char optstring[] = "";
653cdbcc18dSStefan Hajnoczi static const struct option longopts[] = {
654cdbcc18dSStefan Hajnoczi 	{
655cdbcc18dSStefan Hajnoczi 		.name = "control-host",
656cdbcc18dSStefan Hajnoczi 		.has_arg = required_argument,
657cdbcc18dSStefan Hajnoczi 		.val = 'H',
658cdbcc18dSStefan Hajnoczi 	},
659cdbcc18dSStefan Hajnoczi 	{
660cdbcc18dSStefan Hajnoczi 		.name = "control-port",
661cdbcc18dSStefan Hajnoczi 		.has_arg = required_argument,
662cdbcc18dSStefan Hajnoczi 		.val = 'P',
663cdbcc18dSStefan Hajnoczi 	},
664cdbcc18dSStefan Hajnoczi 	{
665cdbcc18dSStefan Hajnoczi 		.name = "mode",
666cdbcc18dSStefan Hajnoczi 		.has_arg = required_argument,
667cdbcc18dSStefan Hajnoczi 		.val = 'm',
668cdbcc18dSStefan Hajnoczi 	},
669cdbcc18dSStefan Hajnoczi 	{
670cdbcc18dSStefan Hajnoczi 		.name = "peer-cid",
671cdbcc18dSStefan Hajnoczi 		.has_arg = required_argument,
672cdbcc18dSStefan Hajnoczi 		.val = 'p',
673cdbcc18dSStefan Hajnoczi 	},
674cdbcc18dSStefan Hajnoczi 	{
6755a2b2425SStefano Garzarella 		.name = "list",
6765a2b2425SStefano Garzarella 		.has_arg = no_argument,
6775a2b2425SStefano Garzarella 		.val = 'l',
6785a2b2425SStefano Garzarella 	},
6795a2b2425SStefano Garzarella 	{
6805a2b2425SStefano Garzarella 		.name = "skip",
6815a2b2425SStefano Garzarella 		.has_arg = required_argument,
6825a2b2425SStefano Garzarella 		.val = 's',
6835a2b2425SStefano Garzarella 	},
6845a2b2425SStefano Garzarella 	{
685cdbcc18dSStefan Hajnoczi 		.name = "help",
686cdbcc18dSStefan Hajnoczi 		.has_arg = no_argument,
687cdbcc18dSStefan Hajnoczi 		.val = '?',
688cdbcc18dSStefan Hajnoczi 	},
689cdbcc18dSStefan Hajnoczi 	{},
690cdbcc18dSStefan Hajnoczi };
691cdbcc18dSStefan Hajnoczi 
692cdbcc18dSStefan Hajnoczi static void usage(void)
693cdbcc18dSStefan Hajnoczi {
6945a2b2425SStefano Garzarella 	fprintf(stderr, "Usage: vsock_test [--help] [--control-host=<host>] --control-port=<port> --mode=client|server --peer-cid=<cid> [--list] [--skip=<test_id>]\n"
695cdbcc18dSStefan Hajnoczi 		"\n"
696cdbcc18dSStefan Hajnoczi 		"  Server: vsock_test --control-port=1234 --mode=server --peer-cid=3\n"
697cdbcc18dSStefan Hajnoczi 		"  Client: vsock_test --control-host=192.168.0.1 --control-port=1234 --mode=client --peer-cid=2\n"
698cdbcc18dSStefan Hajnoczi 		"\n"
699cdbcc18dSStefan Hajnoczi 		"Run vsock.ko tests.  Must be launched in both guest\n"
700cdbcc18dSStefan Hajnoczi 		"and host.  One side must use --mode=client and\n"
701cdbcc18dSStefan Hajnoczi 		"the other side must use --mode=server.\n"
702cdbcc18dSStefan Hajnoczi 		"\n"
703cdbcc18dSStefan Hajnoczi 		"A TCP control socket connection is used to coordinate tests\n"
704cdbcc18dSStefan Hajnoczi 		"between the client and the server.  The server requires a\n"
705cdbcc18dSStefan Hajnoczi 		"listen address and the client requires an address to\n"
706cdbcc18dSStefan Hajnoczi 		"connect to.\n"
707cdbcc18dSStefan Hajnoczi 		"\n"
7088d00b93fSStefano Garzarella 		"The CID of the other side must be given with --peer-cid=<cid>.\n"
7098d00b93fSStefano Garzarella 		"\n"
7108d00b93fSStefano Garzarella 		"Options:\n"
7118d00b93fSStefano Garzarella 		"  --help                 This help message\n"
7128d00b93fSStefano Garzarella 		"  --control-host <host>  Server IP address to connect to\n"
7138d00b93fSStefano Garzarella 		"  --control-port <port>  Server port to listen on/connect to\n"
7148d00b93fSStefano Garzarella 		"  --mode client|server   Server or client mode\n"
7158d00b93fSStefano Garzarella 		"  --peer-cid <cid>       CID of the other side\n"
7168d00b93fSStefano Garzarella 		"  --list                 List of tests that will be executed\n"
7178d00b93fSStefano Garzarella 		"  --skip <test_id>       Test ID to skip;\n"
7188d00b93fSStefano Garzarella 		"                         use multiple --skip options to skip more tests\n"
7198d00b93fSStefano Garzarella 		);
720cdbcc18dSStefan Hajnoczi 	exit(EXIT_FAILURE);
721cdbcc18dSStefan Hajnoczi }
722cdbcc18dSStefan Hajnoczi 
723cdbcc18dSStefan Hajnoczi int main(int argc, char **argv)
724cdbcc18dSStefan Hajnoczi {
725cdbcc18dSStefan Hajnoczi 	const char *control_host = NULL;
726cdbcc18dSStefan Hajnoczi 	const char *control_port = NULL;
727cdbcc18dSStefan Hajnoczi 	struct test_opts opts = {
728cdbcc18dSStefan Hajnoczi 		.mode = TEST_MODE_UNSET,
729cdbcc18dSStefan Hajnoczi 		.peer_cid = VMADDR_CID_ANY,
730cdbcc18dSStefan Hajnoczi 	};
731cdbcc18dSStefan Hajnoczi 
732cdbcc18dSStefan Hajnoczi 	init_signals();
733cdbcc18dSStefan Hajnoczi 
734cdbcc18dSStefan Hajnoczi 	for (;;) {
735cdbcc18dSStefan Hajnoczi 		int opt = getopt_long(argc, argv, optstring, longopts, NULL);
736cdbcc18dSStefan Hajnoczi 
737cdbcc18dSStefan Hajnoczi 		if (opt == -1)
738cdbcc18dSStefan Hajnoczi 			break;
739cdbcc18dSStefan Hajnoczi 
740cdbcc18dSStefan Hajnoczi 		switch (opt) {
741cdbcc18dSStefan Hajnoczi 		case 'H':
742cdbcc18dSStefan Hajnoczi 			control_host = optarg;
743cdbcc18dSStefan Hajnoczi 			break;
744cdbcc18dSStefan Hajnoczi 		case 'm':
745cdbcc18dSStefan Hajnoczi 			if (strcmp(optarg, "client") == 0)
746cdbcc18dSStefan Hajnoczi 				opts.mode = TEST_MODE_CLIENT;
747cdbcc18dSStefan Hajnoczi 			else if (strcmp(optarg, "server") == 0)
748cdbcc18dSStefan Hajnoczi 				opts.mode = TEST_MODE_SERVER;
749cdbcc18dSStefan Hajnoczi 			else {
750cdbcc18dSStefan Hajnoczi 				fprintf(stderr, "--mode must be \"client\" or \"server\"\n");
751cdbcc18dSStefan Hajnoczi 				return EXIT_FAILURE;
752cdbcc18dSStefan Hajnoczi 			}
753cdbcc18dSStefan Hajnoczi 			break;
754cdbcc18dSStefan Hajnoczi 		case 'p':
755cdbcc18dSStefan Hajnoczi 			opts.peer_cid = parse_cid(optarg);
756cdbcc18dSStefan Hajnoczi 			break;
757cdbcc18dSStefan Hajnoczi 		case 'P':
758cdbcc18dSStefan Hajnoczi 			control_port = optarg;
759cdbcc18dSStefan Hajnoczi 			break;
7605a2b2425SStefano Garzarella 		case 'l':
7615a2b2425SStefano Garzarella 			list_tests(test_cases);
7625a2b2425SStefano Garzarella 			break;
7635a2b2425SStefano Garzarella 		case 's':
7645a2b2425SStefano Garzarella 			skip_test(test_cases, ARRAY_SIZE(test_cases) - 1,
7655a2b2425SStefano Garzarella 				  optarg);
7665a2b2425SStefano Garzarella 			break;
767cdbcc18dSStefan Hajnoczi 		case '?':
768cdbcc18dSStefan Hajnoczi 		default:
769cdbcc18dSStefan Hajnoczi 			usage();
770cdbcc18dSStefan Hajnoczi 		}
771cdbcc18dSStefan Hajnoczi 	}
772cdbcc18dSStefan Hajnoczi 
773cdbcc18dSStefan Hajnoczi 	if (!control_port)
774cdbcc18dSStefan Hajnoczi 		usage();
775cdbcc18dSStefan Hajnoczi 	if (opts.mode == TEST_MODE_UNSET)
776cdbcc18dSStefan Hajnoczi 		usage();
777cdbcc18dSStefan Hajnoczi 	if (opts.peer_cid == VMADDR_CID_ANY)
778cdbcc18dSStefan Hajnoczi 		usage();
779cdbcc18dSStefan Hajnoczi 
780cdbcc18dSStefan Hajnoczi 	if (!control_host) {
781cdbcc18dSStefan Hajnoczi 		if (opts.mode != TEST_MODE_SERVER)
782cdbcc18dSStefan Hajnoczi 			usage();
783cdbcc18dSStefan Hajnoczi 		control_host = "0.0.0.0";
784cdbcc18dSStefan Hajnoczi 	}
785cdbcc18dSStefan Hajnoczi 
786cdbcc18dSStefan Hajnoczi 	control_init(control_host, control_port,
787cdbcc18dSStefan Hajnoczi 		     opts.mode == TEST_MODE_SERVER);
788cdbcc18dSStefan Hajnoczi 
789cdbcc18dSStefan Hajnoczi 	run_tests(test_cases, &opts);
790cdbcc18dSStefan Hajnoczi 
791cdbcc18dSStefan Hajnoczi 	control_cleanup();
792cdbcc18dSStefan Hajnoczi 	return EXIT_SUCCESS;
793cdbcc18dSStefan Hajnoczi }
794