xref: /openbmc/linux/tools/testing/vsock/vsock_test.c (revision 78c06141)
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>
20e89600ebSKrasnov Arseniy Vladimirovich #include <sys/mman.h>
21b1346338SArseniy Krasnov #include <poll.h>
22cdbcc18dSStefan Hajnoczi 
23cdbcc18dSStefan Hajnoczi #include "timeout.h"
24cdbcc18dSStefan Hajnoczi #include "control.h"
25cdbcc18dSStefan Hajnoczi #include "util.h"
26cdbcc18dSStefan Hajnoczi 
test_stream_connection_reset(const struct test_opts * opts)27cdbcc18dSStefan Hajnoczi static void test_stream_connection_reset(const struct test_opts *opts)
28cdbcc18dSStefan Hajnoczi {
29cdbcc18dSStefan Hajnoczi 	union {
30cdbcc18dSStefan Hajnoczi 		struct sockaddr sa;
31cdbcc18dSStefan Hajnoczi 		struct sockaddr_vm svm;
32cdbcc18dSStefan Hajnoczi 	} addr = {
33cdbcc18dSStefan Hajnoczi 		.svm = {
34cdbcc18dSStefan Hajnoczi 			.svm_family = AF_VSOCK,
35cdbcc18dSStefan Hajnoczi 			.svm_port = 1234,
36cdbcc18dSStefan Hajnoczi 			.svm_cid = opts->peer_cid,
37cdbcc18dSStefan Hajnoczi 		},
38cdbcc18dSStefan Hajnoczi 	};
39cdbcc18dSStefan Hajnoczi 	int ret;
40cdbcc18dSStefan Hajnoczi 	int fd;
41cdbcc18dSStefan Hajnoczi 
42cdbcc18dSStefan Hajnoczi 	fd = socket(AF_VSOCK, SOCK_STREAM, 0);
43cdbcc18dSStefan Hajnoczi 
44cdbcc18dSStefan Hajnoczi 	timeout_begin(TIMEOUT);
45cdbcc18dSStefan Hajnoczi 	do {
46cdbcc18dSStefan Hajnoczi 		ret = connect(fd, &addr.sa, sizeof(addr.svm));
47cdbcc18dSStefan Hajnoczi 		timeout_check("connect");
48cdbcc18dSStefan Hajnoczi 	} while (ret < 0 && errno == EINTR);
49cdbcc18dSStefan Hajnoczi 	timeout_end();
50cdbcc18dSStefan Hajnoczi 
51cdbcc18dSStefan Hajnoczi 	if (ret != -1) {
52cdbcc18dSStefan Hajnoczi 		fprintf(stderr, "expected connect(2) failure, got %d\n", ret);
53cdbcc18dSStefan Hajnoczi 		exit(EXIT_FAILURE);
54cdbcc18dSStefan Hajnoczi 	}
55cdbcc18dSStefan Hajnoczi 	if (errno != ECONNRESET) {
56cdbcc18dSStefan Hajnoczi 		fprintf(stderr, "unexpected connect(2) errno %d\n", errno);
57cdbcc18dSStefan Hajnoczi 		exit(EXIT_FAILURE);
58cdbcc18dSStefan Hajnoczi 	}
59cdbcc18dSStefan Hajnoczi 
60cdbcc18dSStefan Hajnoczi 	close(fd);
61cdbcc18dSStefan Hajnoczi }
62cdbcc18dSStefan Hajnoczi 
test_stream_bind_only_client(const struct test_opts * opts)639de9f7d1SSebastien Boeuf static void test_stream_bind_only_client(const struct test_opts *opts)
649de9f7d1SSebastien Boeuf {
659de9f7d1SSebastien Boeuf 	union {
669de9f7d1SSebastien Boeuf 		struct sockaddr sa;
679de9f7d1SSebastien Boeuf 		struct sockaddr_vm svm;
689de9f7d1SSebastien Boeuf 	} addr = {
699de9f7d1SSebastien Boeuf 		.svm = {
709de9f7d1SSebastien Boeuf 			.svm_family = AF_VSOCK,
719de9f7d1SSebastien Boeuf 			.svm_port = 1234,
729de9f7d1SSebastien Boeuf 			.svm_cid = opts->peer_cid,
739de9f7d1SSebastien Boeuf 		},
749de9f7d1SSebastien Boeuf 	};
759de9f7d1SSebastien Boeuf 	int ret;
769de9f7d1SSebastien Boeuf 	int fd;
779de9f7d1SSebastien Boeuf 
789de9f7d1SSebastien Boeuf 	/* Wait for the server to be ready */
799de9f7d1SSebastien Boeuf 	control_expectln("BIND");
809de9f7d1SSebastien Boeuf 
819de9f7d1SSebastien Boeuf 	fd = socket(AF_VSOCK, SOCK_STREAM, 0);
829de9f7d1SSebastien Boeuf 
839de9f7d1SSebastien Boeuf 	timeout_begin(TIMEOUT);
849de9f7d1SSebastien Boeuf 	do {
859de9f7d1SSebastien Boeuf 		ret = connect(fd, &addr.sa, sizeof(addr.svm));
869de9f7d1SSebastien Boeuf 		timeout_check("connect");
879de9f7d1SSebastien Boeuf 	} while (ret < 0 && errno == EINTR);
889de9f7d1SSebastien Boeuf 	timeout_end();
899de9f7d1SSebastien Boeuf 
909de9f7d1SSebastien Boeuf 	if (ret != -1) {
919de9f7d1SSebastien Boeuf 		fprintf(stderr, "expected connect(2) failure, got %d\n", ret);
929de9f7d1SSebastien Boeuf 		exit(EXIT_FAILURE);
939de9f7d1SSebastien Boeuf 	}
949de9f7d1SSebastien Boeuf 	if (errno != ECONNRESET) {
959de9f7d1SSebastien Boeuf 		fprintf(stderr, "unexpected connect(2) errno %d\n", errno);
969de9f7d1SSebastien Boeuf 		exit(EXIT_FAILURE);
979de9f7d1SSebastien Boeuf 	}
989de9f7d1SSebastien Boeuf 
999de9f7d1SSebastien Boeuf 	/* Notify the server that the client has finished */
1009de9f7d1SSebastien Boeuf 	control_writeln("DONE");
1019de9f7d1SSebastien Boeuf 
1029de9f7d1SSebastien Boeuf 	close(fd);
1039de9f7d1SSebastien Boeuf }
1049de9f7d1SSebastien Boeuf 
test_stream_bind_only_server(const struct test_opts * opts)1059de9f7d1SSebastien Boeuf static void test_stream_bind_only_server(const struct test_opts *opts)
1069de9f7d1SSebastien Boeuf {
1079de9f7d1SSebastien Boeuf 	union {
1089de9f7d1SSebastien Boeuf 		struct sockaddr sa;
1099de9f7d1SSebastien Boeuf 		struct sockaddr_vm svm;
1109de9f7d1SSebastien Boeuf 	} addr = {
1119de9f7d1SSebastien Boeuf 		.svm = {
1129de9f7d1SSebastien Boeuf 			.svm_family = AF_VSOCK,
1139de9f7d1SSebastien Boeuf 			.svm_port = 1234,
1149de9f7d1SSebastien Boeuf 			.svm_cid = VMADDR_CID_ANY,
1159de9f7d1SSebastien Boeuf 		},
1169de9f7d1SSebastien Boeuf 	};
1179de9f7d1SSebastien Boeuf 	int fd;
1189de9f7d1SSebastien Boeuf 
1199de9f7d1SSebastien Boeuf 	fd = socket(AF_VSOCK, SOCK_STREAM, 0);
1209de9f7d1SSebastien Boeuf 
1219de9f7d1SSebastien Boeuf 	if (bind(fd, &addr.sa, sizeof(addr.svm)) < 0) {
1229de9f7d1SSebastien Boeuf 		perror("bind");
1239de9f7d1SSebastien Boeuf 		exit(EXIT_FAILURE);
1249de9f7d1SSebastien Boeuf 	}
1259de9f7d1SSebastien Boeuf 
1269de9f7d1SSebastien Boeuf 	/* Notify the client that the server is ready */
1279de9f7d1SSebastien Boeuf 	control_writeln("BIND");
1289de9f7d1SSebastien Boeuf 
1299de9f7d1SSebastien Boeuf 	/* Wait for the client to finish */
1309de9f7d1SSebastien Boeuf 	control_expectln("DONE");
1319de9f7d1SSebastien Boeuf 
1329de9f7d1SSebastien Boeuf 	close(fd);
1339de9f7d1SSebastien Boeuf }
1349de9f7d1SSebastien Boeuf 
test_stream_client_close_client(const struct test_opts * opts)135cdbcc18dSStefan Hajnoczi static void test_stream_client_close_client(const struct test_opts *opts)
136cdbcc18dSStefan Hajnoczi {
137cdbcc18dSStefan Hajnoczi 	int fd;
138cdbcc18dSStefan Hajnoczi 
139cdbcc18dSStefan Hajnoczi 	fd = vsock_stream_connect(opts->peer_cid, 1234);
140cdbcc18dSStefan Hajnoczi 	if (fd < 0) {
141cdbcc18dSStefan Hajnoczi 		perror("connect");
142cdbcc18dSStefan Hajnoczi 		exit(EXIT_FAILURE);
143cdbcc18dSStefan Hajnoczi 	}
144cdbcc18dSStefan Hajnoczi 
145cdbcc18dSStefan Hajnoczi 	send_byte(fd, 1, 0);
146cdbcc18dSStefan Hajnoczi 	close(fd);
147cdbcc18dSStefan Hajnoczi }
148cdbcc18dSStefan Hajnoczi 
test_stream_client_close_server(const struct test_opts * opts)149cdbcc18dSStefan Hajnoczi static void test_stream_client_close_server(const struct test_opts *opts)
150cdbcc18dSStefan Hajnoczi {
151cdbcc18dSStefan Hajnoczi 	int fd;
152cdbcc18dSStefan Hajnoczi 
153cdbcc18dSStefan Hajnoczi 	fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
154cdbcc18dSStefan Hajnoczi 	if (fd < 0) {
155cdbcc18dSStefan Hajnoczi 		perror("accept");
156cdbcc18dSStefan Hajnoczi 		exit(EXIT_FAILURE);
157cdbcc18dSStefan Hajnoczi 	}
158cdbcc18dSStefan Hajnoczi 
159770ce007SStefano Garzarella 	/* Wait for the remote to close the connection, before check
160770ce007SStefano Garzarella 	 * -EPIPE error on send.
161770ce007SStefano Garzarella 	 */
162770ce007SStefano Garzarella 	vsock_wait_remote_close(fd);
163cdbcc18dSStefan Hajnoczi 
164cdbcc18dSStefan Hajnoczi 	send_byte(fd, -EPIPE, 0);
165cdbcc18dSStefan Hajnoczi 	recv_byte(fd, 1, 0);
166cdbcc18dSStefan Hajnoczi 	recv_byte(fd, 0, 0);
167cdbcc18dSStefan Hajnoczi 	close(fd);
168cdbcc18dSStefan Hajnoczi }
169cdbcc18dSStefan Hajnoczi 
test_stream_server_close_client(const struct test_opts * opts)170cdbcc18dSStefan Hajnoczi static void test_stream_server_close_client(const struct test_opts *opts)
171cdbcc18dSStefan Hajnoczi {
172cdbcc18dSStefan Hajnoczi 	int fd;
173cdbcc18dSStefan Hajnoczi 
174cdbcc18dSStefan Hajnoczi 	fd = vsock_stream_connect(opts->peer_cid, 1234);
175cdbcc18dSStefan Hajnoczi 	if (fd < 0) {
176cdbcc18dSStefan Hajnoczi 		perror("connect");
177cdbcc18dSStefan Hajnoczi 		exit(EXIT_FAILURE);
178cdbcc18dSStefan Hajnoczi 	}
179cdbcc18dSStefan Hajnoczi 
180770ce007SStefano Garzarella 	/* Wait for the remote to close the connection, before check
181770ce007SStefano Garzarella 	 * -EPIPE error on send.
182770ce007SStefano Garzarella 	 */
183770ce007SStefano Garzarella 	vsock_wait_remote_close(fd);
184cdbcc18dSStefan Hajnoczi 
185cdbcc18dSStefan Hajnoczi 	send_byte(fd, -EPIPE, 0);
186cdbcc18dSStefan Hajnoczi 	recv_byte(fd, 1, 0);
187cdbcc18dSStefan Hajnoczi 	recv_byte(fd, 0, 0);
188cdbcc18dSStefan Hajnoczi 	close(fd);
189cdbcc18dSStefan Hajnoczi }
190cdbcc18dSStefan Hajnoczi 
test_stream_server_close_server(const struct test_opts * opts)191cdbcc18dSStefan Hajnoczi static void test_stream_server_close_server(const struct test_opts *opts)
192cdbcc18dSStefan Hajnoczi {
193cdbcc18dSStefan Hajnoczi 	int fd;
194cdbcc18dSStefan Hajnoczi 
195cdbcc18dSStefan Hajnoczi 	fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
196cdbcc18dSStefan Hajnoczi 	if (fd < 0) {
197cdbcc18dSStefan Hajnoczi 		perror("accept");
198cdbcc18dSStefan Hajnoczi 		exit(EXIT_FAILURE);
199cdbcc18dSStefan Hajnoczi 	}
200cdbcc18dSStefan Hajnoczi 
201cdbcc18dSStefan Hajnoczi 	send_byte(fd, 1, 0);
202cdbcc18dSStefan Hajnoczi 	close(fd);
203cdbcc18dSStefan Hajnoczi }
204cdbcc18dSStefan Hajnoczi 
205cdbcc18dSStefan Hajnoczi /* With the standard socket sizes, VMCI is able to support about 100
206cdbcc18dSStefan Hajnoczi  * concurrent stream connections.
207cdbcc18dSStefan Hajnoczi  */
208cdbcc18dSStefan Hajnoczi #define MULTICONN_NFDS 100
209cdbcc18dSStefan Hajnoczi 
test_stream_multiconn_client(const struct test_opts * opts)210cdbcc18dSStefan Hajnoczi static void test_stream_multiconn_client(const struct test_opts *opts)
211cdbcc18dSStefan Hajnoczi {
212cdbcc18dSStefan Hajnoczi 	int fds[MULTICONN_NFDS];
213cdbcc18dSStefan Hajnoczi 	int i;
214cdbcc18dSStefan Hajnoczi 
215cdbcc18dSStefan Hajnoczi 	for (i = 0; i < MULTICONN_NFDS; i++) {
216cdbcc18dSStefan Hajnoczi 		fds[i] = vsock_stream_connect(opts->peer_cid, 1234);
217cdbcc18dSStefan Hajnoczi 		if (fds[i] < 0) {
218cdbcc18dSStefan Hajnoczi 			perror("connect");
219cdbcc18dSStefan Hajnoczi 			exit(EXIT_FAILURE);
220cdbcc18dSStefan Hajnoczi 		}
221cdbcc18dSStefan Hajnoczi 	}
222cdbcc18dSStefan Hajnoczi 
223cdbcc18dSStefan Hajnoczi 	for (i = 0; i < MULTICONN_NFDS; i++) {
224cdbcc18dSStefan Hajnoczi 		if (i % 2)
225cdbcc18dSStefan Hajnoczi 			recv_byte(fds[i], 1, 0);
226cdbcc18dSStefan Hajnoczi 		else
227cdbcc18dSStefan Hajnoczi 			send_byte(fds[i], 1, 0);
228cdbcc18dSStefan Hajnoczi 	}
229cdbcc18dSStefan Hajnoczi 
230cdbcc18dSStefan Hajnoczi 	for (i = 0; i < MULTICONN_NFDS; i++)
231cdbcc18dSStefan Hajnoczi 		close(fds[i]);
232cdbcc18dSStefan Hajnoczi }
233cdbcc18dSStefan Hajnoczi 
test_stream_multiconn_server(const struct test_opts * opts)234cdbcc18dSStefan Hajnoczi static void test_stream_multiconn_server(const struct test_opts *opts)
235cdbcc18dSStefan Hajnoczi {
236cdbcc18dSStefan Hajnoczi 	int fds[MULTICONN_NFDS];
237cdbcc18dSStefan Hajnoczi 	int i;
238cdbcc18dSStefan Hajnoczi 
239cdbcc18dSStefan Hajnoczi 	for (i = 0; i < MULTICONN_NFDS; i++) {
240cdbcc18dSStefan Hajnoczi 		fds[i] = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
241cdbcc18dSStefan Hajnoczi 		if (fds[i] < 0) {
242cdbcc18dSStefan Hajnoczi 			perror("accept");
243cdbcc18dSStefan Hajnoczi 			exit(EXIT_FAILURE);
244cdbcc18dSStefan Hajnoczi 		}
245cdbcc18dSStefan Hajnoczi 	}
246cdbcc18dSStefan Hajnoczi 
247cdbcc18dSStefan Hajnoczi 	for (i = 0; i < MULTICONN_NFDS; i++) {
248cdbcc18dSStefan Hajnoczi 		if (i % 2)
249cdbcc18dSStefan Hajnoczi 			send_byte(fds[i], 1, 0);
250cdbcc18dSStefan Hajnoczi 		else
251cdbcc18dSStefan Hajnoczi 			recv_byte(fds[i], 1, 0);
252cdbcc18dSStefan Hajnoczi 	}
253cdbcc18dSStefan Hajnoczi 
254cdbcc18dSStefan Hajnoczi 	for (i = 0; i < MULTICONN_NFDS; i++)
255cdbcc18dSStefan Hajnoczi 		close(fds[i]);
256cdbcc18dSStefan Hajnoczi }
257cdbcc18dSStefan Hajnoczi 
258587ed79fSArseniy Krasnov #define MSG_PEEK_BUF_LEN 64
259587ed79fSArseniy Krasnov 
test_msg_peek_client(const struct test_opts * opts,bool seqpacket)2608a0697f2SArseniy Krasnov static void test_msg_peek_client(const struct test_opts *opts,
2618a0697f2SArseniy Krasnov 				 bool seqpacket)
262d6269a93SStefano Garzarella {
263587ed79fSArseniy Krasnov 	unsigned char buf[MSG_PEEK_BUF_LEN];
264587ed79fSArseniy Krasnov 	ssize_t send_size;
265d6269a93SStefano Garzarella 	int fd;
266587ed79fSArseniy Krasnov 	int i;
267d6269a93SStefano Garzarella 
2688a0697f2SArseniy Krasnov 	if (seqpacket)
2698a0697f2SArseniy Krasnov 		fd = vsock_seqpacket_connect(opts->peer_cid, 1234);
2708a0697f2SArseniy Krasnov 	else
271d6269a93SStefano Garzarella 		fd = vsock_stream_connect(opts->peer_cid, 1234);
2728a0697f2SArseniy Krasnov 
273d6269a93SStefano Garzarella 	if (fd < 0) {
274d6269a93SStefano Garzarella 		perror("connect");
275d6269a93SStefano Garzarella 		exit(EXIT_FAILURE);
276d6269a93SStefano Garzarella 	}
277d6269a93SStefano Garzarella 
278587ed79fSArseniy Krasnov 	for (i = 0; i < sizeof(buf); i++)
279587ed79fSArseniy Krasnov 		buf[i] = rand() & 0xFF;
280587ed79fSArseniy Krasnov 
281587ed79fSArseniy Krasnov 	control_expectln("SRVREADY");
282587ed79fSArseniy Krasnov 
283587ed79fSArseniy Krasnov 	send_size = send(fd, buf, sizeof(buf), 0);
284587ed79fSArseniy Krasnov 
285587ed79fSArseniy Krasnov 	if (send_size < 0) {
286587ed79fSArseniy Krasnov 		perror("send");
287587ed79fSArseniy Krasnov 		exit(EXIT_FAILURE);
288587ed79fSArseniy Krasnov 	}
289587ed79fSArseniy Krasnov 
290587ed79fSArseniy Krasnov 	if (send_size != sizeof(buf)) {
291587ed79fSArseniy Krasnov 		fprintf(stderr, "Invalid send size %zi\n", send_size);
292587ed79fSArseniy Krasnov 		exit(EXIT_FAILURE);
293587ed79fSArseniy Krasnov 	}
294587ed79fSArseniy Krasnov 
295d6269a93SStefano Garzarella 	close(fd);
296d6269a93SStefano Garzarella }
297d6269a93SStefano Garzarella 
test_msg_peek_server(const struct test_opts * opts,bool seqpacket)2988a0697f2SArseniy Krasnov static void test_msg_peek_server(const struct test_opts *opts,
2998a0697f2SArseniy Krasnov 				 bool seqpacket)
300d6269a93SStefano Garzarella {
301587ed79fSArseniy Krasnov 	unsigned char buf_half[MSG_PEEK_BUF_LEN / 2];
302587ed79fSArseniy Krasnov 	unsigned char buf_normal[MSG_PEEK_BUF_LEN];
303587ed79fSArseniy Krasnov 	unsigned char buf_peek[MSG_PEEK_BUF_LEN];
304587ed79fSArseniy Krasnov 	ssize_t res;
305d6269a93SStefano Garzarella 	int fd;
306d6269a93SStefano Garzarella 
3078a0697f2SArseniy Krasnov 	if (seqpacket)
3088a0697f2SArseniy Krasnov 		fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL);
3098a0697f2SArseniy Krasnov 	else
310d6269a93SStefano Garzarella 		fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
3118a0697f2SArseniy Krasnov 
312d6269a93SStefano Garzarella 	if (fd < 0) {
313d6269a93SStefano Garzarella 		perror("accept");
314d6269a93SStefano Garzarella 		exit(EXIT_FAILURE);
315d6269a93SStefano Garzarella 	}
316d6269a93SStefano Garzarella 
317587ed79fSArseniy Krasnov 	/* Peek from empty socket. */
318587ed79fSArseniy Krasnov 	res = recv(fd, buf_peek, sizeof(buf_peek), MSG_PEEK | MSG_DONTWAIT);
319587ed79fSArseniy Krasnov 	if (res != -1) {
320587ed79fSArseniy Krasnov 		fprintf(stderr, "expected recv(2) failure, got %zi\n", res);
321587ed79fSArseniy Krasnov 		exit(EXIT_FAILURE);
322587ed79fSArseniy Krasnov 	}
323587ed79fSArseniy Krasnov 
324587ed79fSArseniy Krasnov 	if (errno != EAGAIN) {
325587ed79fSArseniy Krasnov 		perror("EAGAIN expected");
326587ed79fSArseniy Krasnov 		exit(EXIT_FAILURE);
327587ed79fSArseniy Krasnov 	}
328587ed79fSArseniy Krasnov 
329587ed79fSArseniy Krasnov 	control_writeln("SRVREADY");
330587ed79fSArseniy Krasnov 
331587ed79fSArseniy Krasnov 	/* Peek part of data. */
332587ed79fSArseniy Krasnov 	res = recv(fd, buf_half, sizeof(buf_half), MSG_PEEK);
333587ed79fSArseniy Krasnov 	if (res != sizeof(buf_half)) {
334587ed79fSArseniy Krasnov 		fprintf(stderr, "recv(2) + MSG_PEEK, expected %zu, got %zi\n",
335587ed79fSArseniy Krasnov 			sizeof(buf_half), res);
336587ed79fSArseniy Krasnov 		exit(EXIT_FAILURE);
337587ed79fSArseniy Krasnov 	}
338587ed79fSArseniy Krasnov 
339587ed79fSArseniy Krasnov 	/* Peek whole data. */
340587ed79fSArseniy Krasnov 	res = recv(fd, buf_peek, sizeof(buf_peek), MSG_PEEK);
341587ed79fSArseniy Krasnov 	if (res != sizeof(buf_peek)) {
342587ed79fSArseniy Krasnov 		fprintf(stderr, "recv(2) + MSG_PEEK, expected %zu, got %zi\n",
343587ed79fSArseniy Krasnov 			sizeof(buf_peek), res);
344587ed79fSArseniy Krasnov 		exit(EXIT_FAILURE);
345587ed79fSArseniy Krasnov 	}
346587ed79fSArseniy Krasnov 
347587ed79fSArseniy Krasnov 	/* Compare partial and full peek. */
348587ed79fSArseniy Krasnov 	if (memcmp(buf_half, buf_peek, sizeof(buf_half))) {
349587ed79fSArseniy Krasnov 		fprintf(stderr, "Partial peek data mismatch\n");
350587ed79fSArseniy Krasnov 		exit(EXIT_FAILURE);
351587ed79fSArseniy Krasnov 	}
352587ed79fSArseniy Krasnov 
3538a0697f2SArseniy Krasnov 	if (seqpacket) {
3548a0697f2SArseniy Krasnov 		/* This type of socket supports MSG_TRUNC flag,
3558a0697f2SArseniy Krasnov 		 * so check it with MSG_PEEK. We must get length
3568a0697f2SArseniy Krasnov 		 * of the message.
3578a0697f2SArseniy Krasnov 		 */
3588a0697f2SArseniy Krasnov 		res = recv(fd, buf_half, sizeof(buf_half), MSG_PEEK |
3598a0697f2SArseniy Krasnov 			   MSG_TRUNC);
3608a0697f2SArseniy Krasnov 		if (res != sizeof(buf_peek)) {
3618a0697f2SArseniy Krasnov 			fprintf(stderr,
3628a0697f2SArseniy Krasnov 				"recv(2) + MSG_PEEK | MSG_TRUNC, exp %zu, got %zi\n",
3638a0697f2SArseniy Krasnov 				sizeof(buf_half), res);
3648a0697f2SArseniy Krasnov 			exit(EXIT_FAILURE);
3658a0697f2SArseniy Krasnov 		}
3668a0697f2SArseniy Krasnov 	}
3678a0697f2SArseniy Krasnov 
368587ed79fSArseniy Krasnov 	res = recv(fd, buf_normal, sizeof(buf_normal), 0);
369587ed79fSArseniy Krasnov 	if (res != sizeof(buf_normal)) {
370587ed79fSArseniy Krasnov 		fprintf(stderr, "recv(2), expected %zu, got %zi\n",
371587ed79fSArseniy Krasnov 			sizeof(buf_normal), res);
372587ed79fSArseniy Krasnov 		exit(EXIT_FAILURE);
373587ed79fSArseniy Krasnov 	}
374587ed79fSArseniy Krasnov 
375587ed79fSArseniy Krasnov 	/* Compare full peek and normal read. */
376587ed79fSArseniy Krasnov 	if (memcmp(buf_peek, buf_normal, sizeof(buf_peek))) {
377587ed79fSArseniy Krasnov 		fprintf(stderr, "Full peek data mismatch\n");
378587ed79fSArseniy Krasnov 		exit(EXIT_FAILURE);
379587ed79fSArseniy Krasnov 	}
380587ed79fSArseniy Krasnov 
381d6269a93SStefano Garzarella 	close(fd);
382d6269a93SStefano Garzarella }
383d6269a93SStefano Garzarella 
test_stream_msg_peek_client(const struct test_opts * opts)3848a0697f2SArseniy Krasnov static void test_stream_msg_peek_client(const struct test_opts *opts)
3858a0697f2SArseniy Krasnov {
3868a0697f2SArseniy Krasnov 	return test_msg_peek_client(opts, false);
3878a0697f2SArseniy Krasnov }
3888a0697f2SArseniy Krasnov 
test_stream_msg_peek_server(const struct test_opts * opts)3898a0697f2SArseniy Krasnov static void test_stream_msg_peek_server(const struct test_opts *opts)
3908a0697f2SArseniy Krasnov {
3918a0697f2SArseniy Krasnov 	return test_msg_peek_server(opts, false);
3928a0697f2SArseniy Krasnov }
3938a0697f2SArseniy Krasnov 
3945c338112SArseniy Krasnov #define SOCK_BUF_SIZE (2 * 1024 * 1024)
395*78c06141SArseniy Krasnov #define MAX_MSG_PAGES 4
3965c338112SArseniy Krasnov 
test_seqpacket_msg_bounds_client(const struct test_opts * opts)39741b792d7SArseny Krasnov static void test_seqpacket_msg_bounds_client(const struct test_opts *opts)
39841b792d7SArseny Krasnov {
3995c338112SArseniy Krasnov 	unsigned long curr_hash;
400*78c06141SArseniy Krasnov 	size_t max_msg_size;
4015c338112SArseniy Krasnov 	int page_size;
4025c338112SArseniy Krasnov 	int msg_count;
40341b792d7SArseny Krasnov 	int fd;
40441b792d7SArseny Krasnov 
40541b792d7SArseny Krasnov 	fd = vsock_seqpacket_connect(opts->peer_cid, 1234);
40641b792d7SArseny Krasnov 	if (fd < 0) {
40741b792d7SArseny Krasnov 		perror("connect");
40841b792d7SArseny Krasnov 		exit(EXIT_FAILURE);
40941b792d7SArseny Krasnov 	}
41041b792d7SArseny Krasnov 
4115c338112SArseniy Krasnov 	/* Wait, until receiver sets buffer size. */
4125c338112SArseniy Krasnov 	control_expectln("SRVREADY");
4135c338112SArseniy Krasnov 
4145c338112SArseniy Krasnov 	curr_hash = 0;
4155c338112SArseniy Krasnov 	page_size = getpagesize();
416*78c06141SArseniy Krasnov 	max_msg_size = MAX_MSG_PAGES * page_size;
417*78c06141SArseniy Krasnov 	msg_count = SOCK_BUF_SIZE / max_msg_size;
4185c338112SArseniy Krasnov 
4195c338112SArseniy Krasnov 	for (int i = 0; i < msg_count; i++) {
4205c338112SArseniy Krasnov 		ssize_t send_size;
4215c338112SArseniy Krasnov 		size_t buf_size;
4225c338112SArseniy Krasnov 		int flags;
4235c338112SArseniy Krasnov 		void *buf;
4245c338112SArseniy Krasnov 
4255c338112SArseniy Krasnov 		/* Use "small" buffers and "big" buffers. */
4265c338112SArseniy Krasnov 		if (i & 1)
4275c338112SArseniy Krasnov 			buf_size = page_size +
428*78c06141SArseniy Krasnov 					(rand() % (max_msg_size - page_size));
4295c338112SArseniy Krasnov 		else
4305c338112SArseniy Krasnov 			buf_size = 1 + (rand() % page_size);
4315c338112SArseniy Krasnov 
4325c338112SArseniy Krasnov 		buf = malloc(buf_size);
4335c338112SArseniy Krasnov 
4345c338112SArseniy Krasnov 		if (!buf) {
4355c338112SArseniy Krasnov 			perror("malloc");
4365c338112SArseniy Krasnov 			exit(EXIT_FAILURE);
4375c338112SArseniy Krasnov 		}
4385c338112SArseniy Krasnov 
4395c338112SArseniy Krasnov 		memset(buf, rand() & 0xff, buf_size);
4405c338112SArseniy Krasnov 		/* Set at least one MSG_EOR + some random. */
4415c338112SArseniy Krasnov 		if (i == (msg_count / 2) || (rand() & 1)) {
4425c338112SArseniy Krasnov 			flags = MSG_EOR;
4435c338112SArseniy Krasnov 			curr_hash++;
4445c338112SArseniy Krasnov 		} else {
4455c338112SArseniy Krasnov 			flags = 0;
4465c338112SArseniy Krasnov 		}
4475c338112SArseniy Krasnov 
4485c338112SArseniy Krasnov 		send_size = send(fd, buf, buf_size, flags);
4495c338112SArseniy Krasnov 
4505c338112SArseniy Krasnov 		if (send_size < 0) {
4515c338112SArseniy Krasnov 			perror("send");
4525c338112SArseniy Krasnov 			exit(EXIT_FAILURE);
4535c338112SArseniy Krasnov 		}
4545c338112SArseniy Krasnov 
4555c338112SArseniy Krasnov 		if (send_size != buf_size) {
4565c338112SArseniy Krasnov 			fprintf(stderr, "Invalid send size\n");
4575c338112SArseniy Krasnov 			exit(EXIT_FAILURE);
4585c338112SArseniy Krasnov 		}
4595c338112SArseniy Krasnov 
4605c338112SArseniy Krasnov 		/*
4615c338112SArseniy Krasnov 		 * Hash sum is computed at both client and server in
4625c338112SArseniy Krasnov 		 * the same way:
4635c338112SArseniy Krasnov 		 * H += hash('message data')
4645c338112SArseniy Krasnov 		 * Such hash "controls" both data integrity and message
4655c338112SArseniy Krasnov 		 * bounds. After data exchange, both sums are compared
4665c338112SArseniy Krasnov 		 * using control socket, and if message bounds wasn't
4675c338112SArseniy Krasnov 		 * broken - two values must be equal.
4685c338112SArseniy Krasnov 		 */
4695c338112SArseniy Krasnov 		curr_hash += hash_djb2(buf, buf_size);
4705c338112SArseniy Krasnov 		free(buf);
4715c338112SArseniy Krasnov 	}
47241b792d7SArseny Krasnov 
47341b792d7SArseny Krasnov 	control_writeln("SENDDONE");
4745c338112SArseniy Krasnov 	control_writeulong(curr_hash);
47541b792d7SArseny Krasnov 	close(fd);
47641b792d7SArseny Krasnov }
47741b792d7SArseny Krasnov 
test_seqpacket_msg_bounds_server(const struct test_opts * opts)47841b792d7SArseny Krasnov static void test_seqpacket_msg_bounds_server(const struct test_opts *opts)
47941b792d7SArseny Krasnov {
4805c338112SArseniy Krasnov 	unsigned long sock_buf_size;
4815c338112SArseniy Krasnov 	unsigned long remote_hash;
4825c338112SArseniy Krasnov 	unsigned long curr_hash;
48341b792d7SArseny Krasnov 	int fd;
48441b792d7SArseny Krasnov 	struct msghdr msg = {0};
48541b792d7SArseny Krasnov 	struct iovec iov = {0};
48641b792d7SArseny Krasnov 
48741b792d7SArseny Krasnov 	fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL);
48841b792d7SArseny Krasnov 	if (fd < 0) {
48941b792d7SArseny Krasnov 		perror("accept");
49041b792d7SArseny Krasnov 		exit(EXIT_FAILURE);
49141b792d7SArseny Krasnov 	}
49241b792d7SArseny Krasnov 
4935c338112SArseniy Krasnov 	sock_buf_size = SOCK_BUF_SIZE;
4945c338112SArseniy Krasnov 
4955c338112SArseniy Krasnov 	if (setsockopt(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_MAX_SIZE,
4965c338112SArseniy Krasnov 		       &sock_buf_size, sizeof(sock_buf_size))) {
4975c338112SArseniy Krasnov 		perror("setsockopt(SO_VM_SOCKETS_BUFFER_MAX_SIZE)");
4985c338112SArseniy Krasnov 		exit(EXIT_FAILURE);
4995c338112SArseniy Krasnov 	}
5005c338112SArseniy Krasnov 
5015c338112SArseniy Krasnov 	if (setsockopt(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_SIZE,
5025c338112SArseniy Krasnov 		       &sock_buf_size, sizeof(sock_buf_size))) {
5035c338112SArseniy Krasnov 		perror("setsockopt(SO_VM_SOCKETS_BUFFER_SIZE)");
5045c338112SArseniy Krasnov 		exit(EXIT_FAILURE);
5055c338112SArseniy Krasnov 	}
5065c338112SArseniy Krasnov 
5075c338112SArseniy Krasnov 	/* Ready to receive data. */
5085c338112SArseniy Krasnov 	control_writeln("SRVREADY");
5095c338112SArseniy Krasnov 	/* Wait, until peer sends whole data. */
51041b792d7SArseny Krasnov 	control_expectln("SENDDONE");
511*78c06141SArseniy Krasnov 	iov.iov_len = MAX_MSG_PAGES * getpagesize();
512*78c06141SArseniy Krasnov 	iov.iov_base = malloc(iov.iov_len);
513*78c06141SArseniy Krasnov 	if (!iov.iov_base) {
514*78c06141SArseniy Krasnov 		perror("malloc");
515*78c06141SArseniy Krasnov 		exit(EXIT_FAILURE);
516*78c06141SArseniy Krasnov 	}
517*78c06141SArseniy Krasnov 
51841b792d7SArseny Krasnov 	msg.msg_iov = &iov;
51941b792d7SArseny Krasnov 	msg.msg_iovlen = 1;
52041b792d7SArseny Krasnov 
5215c338112SArseniy Krasnov 	curr_hash = 0;
5225c338112SArseniy Krasnov 
5235c338112SArseniy Krasnov 	while (1) {
5245c338112SArseniy Krasnov 		ssize_t recv_size;
5255c338112SArseniy Krasnov 
5265c338112SArseniy Krasnov 		recv_size = recvmsg(fd, &msg, 0);
5275c338112SArseniy Krasnov 
5285c338112SArseniy Krasnov 		if (!recv_size)
5295c338112SArseniy Krasnov 			break;
5305c338112SArseniy Krasnov 
5315c338112SArseniy Krasnov 		if (recv_size < 0) {
5325c338112SArseniy Krasnov 			perror("recvmsg");
53341b792d7SArseny Krasnov 			exit(EXIT_FAILURE);
53441b792d7SArseny Krasnov 		}
5350e115c45SArseny Krasnov 
5365c338112SArseniy Krasnov 		if (msg.msg_flags & MSG_EOR)
5375c338112SArseniy Krasnov 			curr_hash++;
5385c338112SArseniy Krasnov 
5395c338112SArseniy Krasnov 		curr_hash += hash_djb2(msg.msg_iov[0].iov_base, recv_size);
54041b792d7SArseny Krasnov 	}
54141b792d7SArseny Krasnov 
542*78c06141SArseniy Krasnov 	free(iov.iov_base);
54341b792d7SArseny Krasnov 	close(fd);
5445c338112SArseniy Krasnov 	remote_hash = control_readulong();
5455c338112SArseniy Krasnov 
5465c338112SArseniy Krasnov 	if (curr_hash != remote_hash) {
5475c338112SArseniy Krasnov 		fprintf(stderr, "Message bounds broken\n");
5485c338112SArseniy Krasnov 		exit(EXIT_FAILURE);
5495c338112SArseniy Krasnov 	}
55041b792d7SArseny Krasnov }
55141b792d7SArseny Krasnov 
55241b792d7SArseny Krasnov #define MESSAGE_TRUNC_SZ 32
test_seqpacket_msg_trunc_client(const struct test_opts * opts)55341b792d7SArseny Krasnov static void test_seqpacket_msg_trunc_client(const struct test_opts *opts)
55441b792d7SArseny Krasnov {
55541b792d7SArseny Krasnov 	int fd;
55641b792d7SArseny Krasnov 	char buf[MESSAGE_TRUNC_SZ];
55741b792d7SArseny Krasnov 
55841b792d7SArseny Krasnov 	fd = vsock_seqpacket_connect(opts->peer_cid, 1234);
55941b792d7SArseny Krasnov 	if (fd < 0) {
56041b792d7SArseny Krasnov 		perror("connect");
56141b792d7SArseny Krasnov 		exit(EXIT_FAILURE);
56241b792d7SArseny Krasnov 	}
56341b792d7SArseny Krasnov 
56441b792d7SArseny Krasnov 	if (send(fd, buf, sizeof(buf), 0) != sizeof(buf)) {
56541b792d7SArseny Krasnov 		perror("send failed");
56641b792d7SArseny Krasnov 		exit(EXIT_FAILURE);
56741b792d7SArseny Krasnov 	}
56841b792d7SArseny Krasnov 
56941b792d7SArseny Krasnov 	control_writeln("SENDDONE");
57041b792d7SArseny Krasnov 	close(fd);
57141b792d7SArseny Krasnov }
57241b792d7SArseny Krasnov 
test_seqpacket_msg_trunc_server(const struct test_opts * opts)57341b792d7SArseny Krasnov static void test_seqpacket_msg_trunc_server(const struct test_opts *opts)
57441b792d7SArseny Krasnov {
57541b792d7SArseny Krasnov 	int fd;
57641b792d7SArseny Krasnov 	char buf[MESSAGE_TRUNC_SZ / 2];
57741b792d7SArseny Krasnov 	struct msghdr msg = {0};
57841b792d7SArseny Krasnov 	struct iovec iov = {0};
57941b792d7SArseny Krasnov 
58041b792d7SArseny Krasnov 	fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL);
58141b792d7SArseny Krasnov 	if (fd < 0) {
58241b792d7SArseny Krasnov 		perror("accept");
58341b792d7SArseny Krasnov 		exit(EXIT_FAILURE);
58441b792d7SArseny Krasnov 	}
58541b792d7SArseny Krasnov 
58641b792d7SArseny Krasnov 	control_expectln("SENDDONE");
58741b792d7SArseny Krasnov 	iov.iov_base = buf;
58841b792d7SArseny Krasnov 	iov.iov_len = sizeof(buf);
58941b792d7SArseny Krasnov 	msg.msg_iov = &iov;
59041b792d7SArseny Krasnov 	msg.msg_iovlen = 1;
59141b792d7SArseny Krasnov 
59241b792d7SArseny Krasnov 	ssize_t ret = recvmsg(fd, &msg, MSG_TRUNC);
59341b792d7SArseny Krasnov 
59441b792d7SArseny Krasnov 	if (ret != MESSAGE_TRUNC_SZ) {
59541b792d7SArseny Krasnov 		printf("%zi\n", ret);
59641b792d7SArseny Krasnov 		perror("MSG_TRUNC doesn't work");
59741b792d7SArseny Krasnov 		exit(EXIT_FAILURE);
59841b792d7SArseny Krasnov 	}
59941b792d7SArseny Krasnov 
60041b792d7SArseny Krasnov 	if (!(msg.msg_flags & MSG_TRUNC)) {
60141b792d7SArseny Krasnov 		fprintf(stderr, "MSG_TRUNC expected\n");
60241b792d7SArseny Krasnov 		exit(EXIT_FAILURE);
60341b792d7SArseny Krasnov 	}
60441b792d7SArseny Krasnov 
60541b792d7SArseny Krasnov 	close(fd);
60641b792d7SArseny Krasnov }
60741b792d7SArseny Krasnov 
current_nsec(void)608efb3719fSKrasnov Arseniy Vladimirovich static time_t current_nsec(void)
609efb3719fSKrasnov Arseniy Vladimirovich {
610efb3719fSKrasnov Arseniy Vladimirovich 	struct timespec ts;
611efb3719fSKrasnov Arseniy Vladimirovich 
612efb3719fSKrasnov Arseniy Vladimirovich 	if (clock_gettime(CLOCK_REALTIME, &ts)) {
613efb3719fSKrasnov Arseniy Vladimirovich 		perror("clock_gettime(3) failed");
614efb3719fSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
615efb3719fSKrasnov Arseniy Vladimirovich 	}
616efb3719fSKrasnov Arseniy Vladimirovich 
617efb3719fSKrasnov Arseniy Vladimirovich 	return (ts.tv_sec * 1000000000ULL) + ts.tv_nsec;
618efb3719fSKrasnov Arseniy Vladimirovich }
619efb3719fSKrasnov Arseniy Vladimirovich 
620efb3719fSKrasnov Arseniy Vladimirovich #define RCVTIMEO_TIMEOUT_SEC 1
621efb3719fSKrasnov Arseniy Vladimirovich #define READ_OVERHEAD_NSEC 250000000 /* 0.25 sec */
622efb3719fSKrasnov Arseniy Vladimirovich 
test_seqpacket_timeout_client(const struct test_opts * opts)623efb3719fSKrasnov Arseniy Vladimirovich static void test_seqpacket_timeout_client(const struct test_opts *opts)
624efb3719fSKrasnov Arseniy Vladimirovich {
625efb3719fSKrasnov Arseniy Vladimirovich 	int fd;
626efb3719fSKrasnov Arseniy Vladimirovich 	struct timeval tv;
627efb3719fSKrasnov Arseniy Vladimirovich 	char dummy;
628efb3719fSKrasnov Arseniy Vladimirovich 	time_t read_enter_ns;
629efb3719fSKrasnov Arseniy Vladimirovich 	time_t read_overhead_ns;
630efb3719fSKrasnov Arseniy Vladimirovich 
631efb3719fSKrasnov Arseniy Vladimirovich 	fd = vsock_seqpacket_connect(opts->peer_cid, 1234);
632efb3719fSKrasnov Arseniy Vladimirovich 	if (fd < 0) {
633efb3719fSKrasnov Arseniy Vladimirovich 		perror("connect");
634efb3719fSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
635efb3719fSKrasnov Arseniy Vladimirovich 	}
636efb3719fSKrasnov Arseniy Vladimirovich 
637efb3719fSKrasnov Arseniy Vladimirovich 	tv.tv_sec = RCVTIMEO_TIMEOUT_SEC;
638efb3719fSKrasnov Arseniy Vladimirovich 	tv.tv_usec = 0;
639efb3719fSKrasnov Arseniy Vladimirovich 
640efb3719fSKrasnov Arseniy Vladimirovich 	if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (void *)&tv, sizeof(tv)) == -1) {
6415c338112SArseniy Krasnov 		perror("setsockopt(SO_RCVTIMEO)");
642efb3719fSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
643efb3719fSKrasnov Arseniy Vladimirovich 	}
644efb3719fSKrasnov Arseniy Vladimirovich 
645efb3719fSKrasnov Arseniy Vladimirovich 	read_enter_ns = current_nsec();
646efb3719fSKrasnov Arseniy Vladimirovich 
647efb3719fSKrasnov Arseniy Vladimirovich 	if (read(fd, &dummy, sizeof(dummy)) != -1) {
648efb3719fSKrasnov Arseniy Vladimirovich 		fprintf(stderr,
649efb3719fSKrasnov Arseniy Vladimirovich 			"expected 'dummy' read(2) failure\n");
650efb3719fSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
651efb3719fSKrasnov Arseniy Vladimirovich 	}
652efb3719fSKrasnov Arseniy Vladimirovich 
653efb3719fSKrasnov Arseniy Vladimirovich 	if (errno != EAGAIN) {
654efb3719fSKrasnov Arseniy Vladimirovich 		perror("EAGAIN expected");
655efb3719fSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
656efb3719fSKrasnov Arseniy Vladimirovich 	}
657efb3719fSKrasnov Arseniy Vladimirovich 
658efb3719fSKrasnov Arseniy Vladimirovich 	read_overhead_ns = current_nsec() - read_enter_ns -
659efb3719fSKrasnov Arseniy Vladimirovich 			1000000000ULL * RCVTIMEO_TIMEOUT_SEC;
660efb3719fSKrasnov Arseniy Vladimirovich 
661efb3719fSKrasnov Arseniy Vladimirovich 	if (read_overhead_ns > READ_OVERHEAD_NSEC) {
662efb3719fSKrasnov Arseniy Vladimirovich 		fprintf(stderr,
663efb3719fSKrasnov Arseniy Vladimirovich 			"too much time in read(2), %lu > %i ns\n",
664efb3719fSKrasnov Arseniy Vladimirovich 			read_overhead_ns, READ_OVERHEAD_NSEC);
665efb3719fSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
666efb3719fSKrasnov Arseniy Vladimirovich 	}
667efb3719fSKrasnov Arseniy Vladimirovich 
668efb3719fSKrasnov Arseniy Vladimirovich 	control_writeln("WAITDONE");
669efb3719fSKrasnov Arseniy Vladimirovich 	close(fd);
670efb3719fSKrasnov Arseniy Vladimirovich }
671efb3719fSKrasnov Arseniy Vladimirovich 
test_seqpacket_timeout_server(const struct test_opts * opts)672efb3719fSKrasnov Arseniy Vladimirovich static void test_seqpacket_timeout_server(const struct test_opts *opts)
673efb3719fSKrasnov Arseniy Vladimirovich {
674efb3719fSKrasnov Arseniy Vladimirovich 	int fd;
675efb3719fSKrasnov Arseniy Vladimirovich 
676efb3719fSKrasnov Arseniy Vladimirovich 	fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL);
677efb3719fSKrasnov Arseniy Vladimirovich 	if (fd < 0) {
678efb3719fSKrasnov Arseniy Vladimirovich 		perror("accept");
679efb3719fSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
680efb3719fSKrasnov Arseniy Vladimirovich 	}
681efb3719fSKrasnov Arseniy Vladimirovich 
682efb3719fSKrasnov Arseniy Vladimirovich 	control_expectln("WAITDONE");
683efb3719fSKrasnov Arseniy Vladimirovich 	close(fd);
684efb3719fSKrasnov Arseniy Vladimirovich }
685efb3719fSKrasnov Arseniy Vladimirovich 
test_seqpacket_bigmsg_client(const struct test_opts * opts)686685a21c3SArseniy Krasnov static void test_seqpacket_bigmsg_client(const struct test_opts *opts)
687685a21c3SArseniy Krasnov {
688685a21c3SArseniy Krasnov 	unsigned long sock_buf_size;
689685a21c3SArseniy Krasnov 	ssize_t send_size;
690685a21c3SArseniy Krasnov 	socklen_t len;
691685a21c3SArseniy Krasnov 	void *data;
692685a21c3SArseniy Krasnov 	int fd;
693685a21c3SArseniy Krasnov 
694685a21c3SArseniy Krasnov 	len = sizeof(sock_buf_size);
695685a21c3SArseniy Krasnov 
696685a21c3SArseniy Krasnov 	fd = vsock_seqpacket_connect(opts->peer_cid, 1234);
697685a21c3SArseniy Krasnov 	if (fd < 0) {
698685a21c3SArseniy Krasnov 		perror("connect");
699685a21c3SArseniy Krasnov 		exit(EXIT_FAILURE);
700685a21c3SArseniy Krasnov 	}
701685a21c3SArseniy Krasnov 
702685a21c3SArseniy Krasnov 	if (getsockopt(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_SIZE,
703685a21c3SArseniy Krasnov 		       &sock_buf_size, &len)) {
704685a21c3SArseniy Krasnov 		perror("getsockopt");
705685a21c3SArseniy Krasnov 		exit(EXIT_FAILURE);
706685a21c3SArseniy Krasnov 	}
707685a21c3SArseniy Krasnov 
708685a21c3SArseniy Krasnov 	sock_buf_size++;
709685a21c3SArseniy Krasnov 
710685a21c3SArseniy Krasnov 	data = malloc(sock_buf_size);
711685a21c3SArseniy Krasnov 	if (!data) {
712685a21c3SArseniy Krasnov 		perror("malloc");
713685a21c3SArseniy Krasnov 		exit(EXIT_FAILURE);
714685a21c3SArseniy Krasnov 	}
715685a21c3SArseniy Krasnov 
716685a21c3SArseniy Krasnov 	send_size = send(fd, data, sock_buf_size, 0);
717685a21c3SArseniy Krasnov 	if (send_size != -1) {
718685a21c3SArseniy Krasnov 		fprintf(stderr, "expected 'send(2)' failure, got %zi\n",
719685a21c3SArseniy Krasnov 			send_size);
720685a21c3SArseniy Krasnov 		exit(EXIT_FAILURE);
721685a21c3SArseniy Krasnov 	}
722685a21c3SArseniy Krasnov 
723685a21c3SArseniy Krasnov 	if (errno != EMSGSIZE) {
724685a21c3SArseniy Krasnov 		fprintf(stderr, "expected EMSGSIZE in 'errno', got %i\n",
725685a21c3SArseniy Krasnov 			errno);
726685a21c3SArseniy Krasnov 		exit(EXIT_FAILURE);
727685a21c3SArseniy Krasnov 	}
728685a21c3SArseniy Krasnov 
729685a21c3SArseniy Krasnov 	control_writeln("CLISENT");
730685a21c3SArseniy Krasnov 
731685a21c3SArseniy Krasnov 	free(data);
732685a21c3SArseniy Krasnov 	close(fd);
733685a21c3SArseniy Krasnov }
734685a21c3SArseniy Krasnov 
test_seqpacket_bigmsg_server(const struct test_opts * opts)735685a21c3SArseniy Krasnov static void test_seqpacket_bigmsg_server(const struct test_opts *opts)
736685a21c3SArseniy Krasnov {
737685a21c3SArseniy Krasnov 	int fd;
738685a21c3SArseniy Krasnov 
739685a21c3SArseniy Krasnov 	fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL);
740685a21c3SArseniy Krasnov 	if (fd < 0) {
741685a21c3SArseniy Krasnov 		perror("accept");
742685a21c3SArseniy Krasnov 		exit(EXIT_FAILURE);
743685a21c3SArseniy Krasnov 	}
744685a21c3SArseniy Krasnov 
745685a21c3SArseniy Krasnov 	control_expectln("CLISENT");
746685a21c3SArseniy Krasnov 
747685a21c3SArseniy Krasnov 	close(fd);
748685a21c3SArseniy Krasnov }
749685a21c3SArseniy Krasnov 
750e89600ebSKrasnov Arseniy Vladimirovich #define BUF_PATTERN_1 'a'
751e89600ebSKrasnov Arseniy Vladimirovich #define BUF_PATTERN_2 'b'
752e89600ebSKrasnov Arseniy Vladimirovich 
test_seqpacket_invalid_rec_buffer_client(const struct test_opts * opts)753e89600ebSKrasnov Arseniy Vladimirovich static void test_seqpacket_invalid_rec_buffer_client(const struct test_opts *opts)
754e89600ebSKrasnov Arseniy Vladimirovich {
755e89600ebSKrasnov Arseniy Vladimirovich 	int fd;
756e89600ebSKrasnov Arseniy Vladimirovich 	unsigned char *buf1;
757e89600ebSKrasnov Arseniy Vladimirovich 	unsigned char *buf2;
758e89600ebSKrasnov Arseniy Vladimirovich 	int buf_size = getpagesize() * 3;
759e89600ebSKrasnov Arseniy Vladimirovich 
760e89600ebSKrasnov Arseniy Vladimirovich 	fd = vsock_seqpacket_connect(opts->peer_cid, 1234);
761e89600ebSKrasnov Arseniy Vladimirovich 	if (fd < 0) {
762e89600ebSKrasnov Arseniy Vladimirovich 		perror("connect");
763e89600ebSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
764e89600ebSKrasnov Arseniy Vladimirovich 	}
765e89600ebSKrasnov Arseniy Vladimirovich 
766e89600ebSKrasnov Arseniy Vladimirovich 	buf1 = malloc(buf_size);
767e89600ebSKrasnov Arseniy Vladimirovich 	if (!buf1) {
768e89600ebSKrasnov Arseniy Vladimirovich 		perror("'malloc()' for 'buf1'");
769e89600ebSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
770e89600ebSKrasnov Arseniy Vladimirovich 	}
771e89600ebSKrasnov Arseniy Vladimirovich 
772e89600ebSKrasnov Arseniy Vladimirovich 	buf2 = malloc(buf_size);
773e89600ebSKrasnov Arseniy Vladimirovich 	if (!buf2) {
774e89600ebSKrasnov Arseniy Vladimirovich 		perror("'malloc()' for 'buf2'");
775e89600ebSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
776e89600ebSKrasnov Arseniy Vladimirovich 	}
777e89600ebSKrasnov Arseniy Vladimirovich 
778e89600ebSKrasnov Arseniy Vladimirovich 	memset(buf1, BUF_PATTERN_1, buf_size);
779e89600ebSKrasnov Arseniy Vladimirovich 	memset(buf2, BUF_PATTERN_2, buf_size);
780e89600ebSKrasnov Arseniy Vladimirovich 
781e89600ebSKrasnov Arseniy Vladimirovich 	if (send(fd, buf1, buf_size, 0) != buf_size) {
782e89600ebSKrasnov Arseniy Vladimirovich 		perror("send failed");
783e89600ebSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
784e89600ebSKrasnov Arseniy Vladimirovich 	}
785e89600ebSKrasnov Arseniy Vladimirovich 
786e89600ebSKrasnov Arseniy Vladimirovich 	if (send(fd, buf2, buf_size, 0) != buf_size) {
787e89600ebSKrasnov Arseniy Vladimirovich 		perror("send failed");
788e89600ebSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
789e89600ebSKrasnov Arseniy Vladimirovich 	}
790e89600ebSKrasnov Arseniy Vladimirovich 
791e89600ebSKrasnov Arseniy Vladimirovich 	close(fd);
792e89600ebSKrasnov Arseniy Vladimirovich }
793e89600ebSKrasnov Arseniy Vladimirovich 
test_seqpacket_invalid_rec_buffer_server(const struct test_opts * opts)794e89600ebSKrasnov Arseniy Vladimirovich static void test_seqpacket_invalid_rec_buffer_server(const struct test_opts *opts)
795e89600ebSKrasnov Arseniy Vladimirovich {
796e89600ebSKrasnov Arseniy Vladimirovich 	int fd;
797e89600ebSKrasnov Arseniy Vladimirovich 	unsigned char *broken_buf;
798e89600ebSKrasnov Arseniy Vladimirovich 	unsigned char *valid_buf;
799e89600ebSKrasnov Arseniy Vladimirovich 	int page_size = getpagesize();
800e89600ebSKrasnov Arseniy Vladimirovich 	int buf_size = page_size * 3;
801e89600ebSKrasnov Arseniy Vladimirovich 	ssize_t res;
802e89600ebSKrasnov Arseniy Vladimirovich 	int prot = PROT_READ | PROT_WRITE;
803e89600ebSKrasnov Arseniy Vladimirovich 	int flags = MAP_PRIVATE | MAP_ANONYMOUS;
804e89600ebSKrasnov Arseniy Vladimirovich 	int i;
805e89600ebSKrasnov Arseniy Vladimirovich 
806e89600ebSKrasnov Arseniy Vladimirovich 	fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL);
807e89600ebSKrasnov Arseniy Vladimirovich 	if (fd < 0) {
808e89600ebSKrasnov Arseniy Vladimirovich 		perror("accept");
809e89600ebSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
810e89600ebSKrasnov Arseniy Vladimirovich 	}
811e89600ebSKrasnov Arseniy Vladimirovich 
812e89600ebSKrasnov Arseniy Vladimirovich 	/* Setup first buffer. */
813e89600ebSKrasnov Arseniy Vladimirovich 	broken_buf = mmap(NULL, buf_size, prot, flags, -1, 0);
814e89600ebSKrasnov Arseniy Vladimirovich 	if (broken_buf == MAP_FAILED) {
815e89600ebSKrasnov Arseniy Vladimirovich 		perror("mmap for 'broken_buf'");
816e89600ebSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
817e89600ebSKrasnov Arseniy Vladimirovich 	}
818e89600ebSKrasnov Arseniy Vladimirovich 
819e89600ebSKrasnov Arseniy Vladimirovich 	/* Unmap "hole" in buffer. */
820e89600ebSKrasnov Arseniy Vladimirovich 	if (munmap(broken_buf + page_size, page_size)) {
821e89600ebSKrasnov Arseniy Vladimirovich 		perror("'broken_buf' setup");
822e89600ebSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
823e89600ebSKrasnov Arseniy Vladimirovich 	}
824e89600ebSKrasnov Arseniy Vladimirovich 
825e89600ebSKrasnov Arseniy Vladimirovich 	valid_buf = mmap(NULL, buf_size, prot, flags, -1, 0);
826e89600ebSKrasnov Arseniy Vladimirovich 	if (valid_buf == MAP_FAILED) {
827e89600ebSKrasnov Arseniy Vladimirovich 		perror("mmap for 'valid_buf'");
828e89600ebSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
829e89600ebSKrasnov Arseniy Vladimirovich 	}
830e89600ebSKrasnov Arseniy Vladimirovich 
831e89600ebSKrasnov Arseniy Vladimirovich 	/* Try to fill buffer with unmapped middle. */
832e89600ebSKrasnov Arseniy Vladimirovich 	res = read(fd, broken_buf, buf_size);
833e89600ebSKrasnov Arseniy Vladimirovich 	if (res != -1) {
834e89600ebSKrasnov Arseniy Vladimirovich 		fprintf(stderr,
835e89600ebSKrasnov Arseniy Vladimirovich 			"expected 'broken_buf' read(2) failure, got %zi\n",
836e89600ebSKrasnov Arseniy Vladimirovich 			res);
837e89600ebSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
838e89600ebSKrasnov Arseniy Vladimirovich 	}
839e89600ebSKrasnov Arseniy Vladimirovich 
840b5d54eb5SArseniy Krasnov 	if (errno != EFAULT) {
841e89600ebSKrasnov Arseniy Vladimirovich 		perror("unexpected errno of 'broken_buf'");
842e89600ebSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
843e89600ebSKrasnov Arseniy Vladimirovich 	}
844e89600ebSKrasnov Arseniy Vladimirovich 
845e89600ebSKrasnov Arseniy Vladimirovich 	/* Try to fill valid buffer. */
846e89600ebSKrasnov Arseniy Vladimirovich 	res = read(fd, valid_buf, buf_size);
847e89600ebSKrasnov Arseniy Vladimirovich 	if (res < 0) {
848e89600ebSKrasnov Arseniy Vladimirovich 		perror("unexpected 'valid_buf' read(2) failure");
849e89600ebSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
850e89600ebSKrasnov Arseniy Vladimirovich 	}
851e89600ebSKrasnov Arseniy Vladimirovich 
852e89600ebSKrasnov Arseniy Vladimirovich 	if (res != buf_size) {
853e89600ebSKrasnov Arseniy Vladimirovich 		fprintf(stderr,
854e89600ebSKrasnov Arseniy Vladimirovich 			"invalid 'valid_buf' read(2), expected %i, got %zi\n",
855e89600ebSKrasnov Arseniy Vladimirovich 			buf_size, res);
856e89600ebSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
857e89600ebSKrasnov Arseniy Vladimirovich 	}
858e89600ebSKrasnov Arseniy Vladimirovich 
859e89600ebSKrasnov Arseniy Vladimirovich 	for (i = 0; i < buf_size; i++) {
860e89600ebSKrasnov Arseniy Vladimirovich 		if (valid_buf[i] != BUF_PATTERN_2) {
861e89600ebSKrasnov Arseniy Vladimirovich 			fprintf(stderr,
862e89600ebSKrasnov Arseniy Vladimirovich 				"invalid pattern for 'valid_buf' at %i, expected %hhX, got %hhX\n",
863e89600ebSKrasnov Arseniy Vladimirovich 				i, BUF_PATTERN_2, valid_buf[i]);
864e89600ebSKrasnov Arseniy Vladimirovich 			exit(EXIT_FAILURE);
865e89600ebSKrasnov Arseniy Vladimirovich 		}
866e89600ebSKrasnov Arseniy Vladimirovich 	}
867e89600ebSKrasnov Arseniy Vladimirovich 
868e89600ebSKrasnov Arseniy Vladimirovich 	/* Unmap buffers. */
869e89600ebSKrasnov Arseniy Vladimirovich 	munmap(broken_buf, page_size);
870e89600ebSKrasnov Arseniy Vladimirovich 	munmap(broken_buf + page_size * 2, page_size);
871e89600ebSKrasnov Arseniy Vladimirovich 	munmap(valid_buf, buf_size);
872e89600ebSKrasnov Arseniy Vladimirovich 	close(fd);
873e89600ebSKrasnov Arseniy Vladimirovich }
874e89600ebSKrasnov Arseniy Vladimirovich 
875b1346338SArseniy Krasnov #define RCVLOWAT_BUF_SIZE 128
876b1346338SArseniy Krasnov 
test_stream_poll_rcvlowat_server(const struct test_opts * opts)877b1346338SArseniy Krasnov static void test_stream_poll_rcvlowat_server(const struct test_opts *opts)
878b1346338SArseniy Krasnov {
879b1346338SArseniy Krasnov 	int fd;
880b1346338SArseniy Krasnov 	int i;
881b1346338SArseniy Krasnov 
882b1346338SArseniy Krasnov 	fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
883b1346338SArseniy Krasnov 	if (fd < 0) {
884b1346338SArseniy Krasnov 		perror("accept");
885b1346338SArseniy Krasnov 		exit(EXIT_FAILURE);
886b1346338SArseniy Krasnov 	}
887b1346338SArseniy Krasnov 
888b1346338SArseniy Krasnov 	/* Send 1 byte. */
889b1346338SArseniy Krasnov 	send_byte(fd, 1, 0);
890b1346338SArseniy Krasnov 
891b1346338SArseniy Krasnov 	control_writeln("SRVSENT");
892b1346338SArseniy Krasnov 
893b1346338SArseniy Krasnov 	/* Wait until client is ready to receive rest of data. */
894b1346338SArseniy Krasnov 	control_expectln("CLNSENT");
895b1346338SArseniy Krasnov 
896b1346338SArseniy Krasnov 	for (i = 0; i < RCVLOWAT_BUF_SIZE - 1; i++)
897b1346338SArseniy Krasnov 		send_byte(fd, 1, 0);
898b1346338SArseniy Krasnov 
899b1346338SArseniy Krasnov 	/* Keep socket in active state. */
900b1346338SArseniy Krasnov 	control_expectln("POLLDONE");
901b1346338SArseniy Krasnov 
902b1346338SArseniy Krasnov 	close(fd);
903b1346338SArseniy Krasnov }
904b1346338SArseniy Krasnov 
test_stream_poll_rcvlowat_client(const struct test_opts * opts)905b1346338SArseniy Krasnov static void test_stream_poll_rcvlowat_client(const struct test_opts *opts)
906b1346338SArseniy Krasnov {
907b1346338SArseniy Krasnov 	unsigned long lowat_val = RCVLOWAT_BUF_SIZE;
908b1346338SArseniy Krasnov 	char buf[RCVLOWAT_BUF_SIZE];
909b1346338SArseniy Krasnov 	struct pollfd fds;
910b1346338SArseniy Krasnov 	ssize_t read_res;
911b1346338SArseniy Krasnov 	short poll_flags;
912b1346338SArseniy Krasnov 	int fd;
913b1346338SArseniy Krasnov 
914b1346338SArseniy Krasnov 	fd = vsock_stream_connect(opts->peer_cid, 1234);
915b1346338SArseniy Krasnov 	if (fd < 0) {
916b1346338SArseniy Krasnov 		perror("connect");
917b1346338SArseniy Krasnov 		exit(EXIT_FAILURE);
918b1346338SArseniy Krasnov 	}
919b1346338SArseniy Krasnov 
920b1346338SArseniy Krasnov 	if (setsockopt(fd, SOL_SOCKET, SO_RCVLOWAT,
921b1346338SArseniy Krasnov 		       &lowat_val, sizeof(lowat_val))) {
9225c338112SArseniy Krasnov 		perror("setsockopt(SO_RCVLOWAT)");
923b1346338SArseniy Krasnov 		exit(EXIT_FAILURE);
924b1346338SArseniy Krasnov 	}
925b1346338SArseniy Krasnov 
926b1346338SArseniy Krasnov 	control_expectln("SRVSENT");
927b1346338SArseniy Krasnov 
928b1346338SArseniy Krasnov 	/* At this point, server sent 1 byte. */
929b1346338SArseniy Krasnov 	fds.fd = fd;
930b1346338SArseniy Krasnov 	poll_flags = POLLIN | POLLRDNORM;
931b1346338SArseniy Krasnov 	fds.events = poll_flags;
932b1346338SArseniy Krasnov 
933b1346338SArseniy Krasnov 	/* Try to wait for 1 sec. */
934b1346338SArseniy Krasnov 	if (poll(&fds, 1, 1000) < 0) {
935b1346338SArseniy Krasnov 		perror("poll");
936b1346338SArseniy Krasnov 		exit(EXIT_FAILURE);
937b1346338SArseniy Krasnov 	}
938b1346338SArseniy Krasnov 
939b1346338SArseniy Krasnov 	/* poll() must return nothing. */
940b1346338SArseniy Krasnov 	if (fds.revents) {
941b1346338SArseniy Krasnov 		fprintf(stderr, "Unexpected poll result %hx\n",
942b1346338SArseniy Krasnov 			fds.revents);
943b1346338SArseniy Krasnov 		exit(EXIT_FAILURE);
944b1346338SArseniy Krasnov 	}
945b1346338SArseniy Krasnov 
946b1346338SArseniy Krasnov 	/* Tell server to send rest of data. */
947b1346338SArseniy Krasnov 	control_writeln("CLNSENT");
948b1346338SArseniy Krasnov 
949b1346338SArseniy Krasnov 	/* Poll for data. */
950b1346338SArseniy Krasnov 	if (poll(&fds, 1, 10000) < 0) {
951b1346338SArseniy Krasnov 		perror("poll");
952b1346338SArseniy Krasnov 		exit(EXIT_FAILURE);
953b1346338SArseniy Krasnov 	}
954b1346338SArseniy Krasnov 
955b1346338SArseniy Krasnov 	/* Only these two bits are expected. */
956b1346338SArseniy Krasnov 	if (fds.revents != poll_flags) {
957b1346338SArseniy Krasnov 		fprintf(stderr, "Unexpected poll result %hx\n",
958b1346338SArseniy Krasnov 			fds.revents);
959b1346338SArseniy Krasnov 		exit(EXIT_FAILURE);
960b1346338SArseniy Krasnov 	}
961b1346338SArseniy Krasnov 
962b1346338SArseniy Krasnov 	/* Use MSG_DONTWAIT, if call is going to wait, EAGAIN
963b1346338SArseniy Krasnov 	 * will be returned.
964b1346338SArseniy Krasnov 	 */
965b1346338SArseniy Krasnov 	read_res = recv(fd, buf, sizeof(buf), MSG_DONTWAIT);
966b1346338SArseniy Krasnov 	if (read_res != RCVLOWAT_BUF_SIZE) {
967b1346338SArseniy Krasnov 		fprintf(stderr, "Unexpected recv result %zi\n",
968b1346338SArseniy Krasnov 			read_res);
969b1346338SArseniy Krasnov 		exit(EXIT_FAILURE);
970b1346338SArseniy Krasnov 	}
971b1346338SArseniy Krasnov 
972b1346338SArseniy Krasnov 	control_writeln("POLLDONE");
973b1346338SArseniy Krasnov 
974b1346338SArseniy Krasnov 	close(fd);
975b1346338SArseniy Krasnov }
976b1346338SArseniy Krasnov 
9777e699d2aSArseniy Krasnov #define INV_BUF_TEST_DATA_LEN 512
9787e699d2aSArseniy Krasnov 
test_inv_buf_client(const struct test_opts * opts,bool stream)9797e699d2aSArseniy Krasnov static void test_inv_buf_client(const struct test_opts *opts, bool stream)
9807e699d2aSArseniy Krasnov {
9817e699d2aSArseniy Krasnov 	unsigned char data[INV_BUF_TEST_DATA_LEN] = {0};
9827e699d2aSArseniy Krasnov 	ssize_t ret;
9837e699d2aSArseniy Krasnov 	int fd;
9847e699d2aSArseniy Krasnov 
9857e699d2aSArseniy Krasnov 	if (stream)
9867e699d2aSArseniy Krasnov 		fd = vsock_stream_connect(opts->peer_cid, 1234);
9877e699d2aSArseniy Krasnov 	else
9887e699d2aSArseniy Krasnov 		fd = vsock_seqpacket_connect(opts->peer_cid, 1234);
9897e699d2aSArseniy Krasnov 
9907e699d2aSArseniy Krasnov 	if (fd < 0) {
9917e699d2aSArseniy Krasnov 		perror("connect");
9927e699d2aSArseniy Krasnov 		exit(EXIT_FAILURE);
9937e699d2aSArseniy Krasnov 	}
9947e699d2aSArseniy Krasnov 
9957e699d2aSArseniy Krasnov 	control_expectln("SENDDONE");
9967e699d2aSArseniy Krasnov 
9977e699d2aSArseniy Krasnov 	/* Use invalid buffer here. */
9987e699d2aSArseniy Krasnov 	ret = recv(fd, NULL, sizeof(data), 0);
9997e699d2aSArseniy Krasnov 	if (ret != -1) {
10007e699d2aSArseniy Krasnov 		fprintf(stderr, "expected recv(2) failure, got %zi\n", ret);
10017e699d2aSArseniy Krasnov 		exit(EXIT_FAILURE);
10027e699d2aSArseniy Krasnov 	}
10037e699d2aSArseniy Krasnov 
1004b5d54eb5SArseniy Krasnov 	if (errno != EFAULT) {
10057e699d2aSArseniy Krasnov 		fprintf(stderr, "unexpected recv(2) errno %d\n", errno);
10067e699d2aSArseniy Krasnov 		exit(EXIT_FAILURE);
10077e699d2aSArseniy Krasnov 	}
10087e699d2aSArseniy Krasnov 
10097e699d2aSArseniy Krasnov 	ret = recv(fd, data, sizeof(data), MSG_DONTWAIT);
10107e699d2aSArseniy Krasnov 
10117e699d2aSArseniy Krasnov 	if (stream) {
10127e699d2aSArseniy Krasnov 		/* For SOCK_STREAM we must continue reading. */
10137e699d2aSArseniy Krasnov 		if (ret != sizeof(data)) {
10147e699d2aSArseniy Krasnov 			fprintf(stderr, "expected recv(2) success, got %zi\n", ret);
10157e699d2aSArseniy Krasnov 			exit(EXIT_FAILURE);
10167e699d2aSArseniy Krasnov 		}
10177e699d2aSArseniy Krasnov 		/* Don't check errno in case of success. */
10187e699d2aSArseniy Krasnov 	} else {
10197e699d2aSArseniy Krasnov 		/* For SOCK_SEQPACKET socket's queue must be empty. */
10207e699d2aSArseniy Krasnov 		if (ret != -1) {
10217e699d2aSArseniy Krasnov 			fprintf(stderr, "expected recv(2) failure, got %zi\n", ret);
10227e699d2aSArseniy Krasnov 			exit(EXIT_FAILURE);
10237e699d2aSArseniy Krasnov 		}
10247e699d2aSArseniy Krasnov 
10257e699d2aSArseniy Krasnov 		if (errno != EAGAIN) {
10267e699d2aSArseniy Krasnov 			fprintf(stderr, "unexpected recv(2) errno %d\n", errno);
10277e699d2aSArseniy Krasnov 			exit(EXIT_FAILURE);
10287e699d2aSArseniy Krasnov 		}
10297e699d2aSArseniy Krasnov 	}
10307e699d2aSArseniy Krasnov 
10317e699d2aSArseniy Krasnov 	control_writeln("DONE");
10327e699d2aSArseniy Krasnov 
10337e699d2aSArseniy Krasnov 	close(fd);
10347e699d2aSArseniy Krasnov }
10357e699d2aSArseniy Krasnov 
test_inv_buf_server(const struct test_opts * opts,bool stream)10367e699d2aSArseniy Krasnov static void test_inv_buf_server(const struct test_opts *opts, bool stream)
10377e699d2aSArseniy Krasnov {
10387e699d2aSArseniy Krasnov 	unsigned char data[INV_BUF_TEST_DATA_LEN] = {0};
10397e699d2aSArseniy Krasnov 	ssize_t res;
10407e699d2aSArseniy Krasnov 	int fd;
10417e699d2aSArseniy Krasnov 
10427e699d2aSArseniy Krasnov 	if (stream)
10437e699d2aSArseniy Krasnov 		fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
10447e699d2aSArseniy Krasnov 	else
10457e699d2aSArseniy Krasnov 		fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL);
10467e699d2aSArseniy Krasnov 
10477e699d2aSArseniy Krasnov 	if (fd < 0) {
10487e699d2aSArseniy Krasnov 		perror("accept");
10497e699d2aSArseniy Krasnov 		exit(EXIT_FAILURE);
10507e699d2aSArseniy Krasnov 	}
10517e699d2aSArseniy Krasnov 
10527e699d2aSArseniy Krasnov 	res = send(fd, data, sizeof(data), 0);
10537e699d2aSArseniy Krasnov 	if (res != sizeof(data)) {
10547e699d2aSArseniy Krasnov 		fprintf(stderr, "unexpected send(2) result %zi\n", res);
10557e699d2aSArseniy Krasnov 		exit(EXIT_FAILURE);
10567e699d2aSArseniy Krasnov 	}
10577e699d2aSArseniy Krasnov 
10587e699d2aSArseniy Krasnov 	control_writeln("SENDDONE");
10597e699d2aSArseniy Krasnov 
10607e699d2aSArseniy Krasnov 	control_expectln("DONE");
10617e699d2aSArseniy Krasnov 
10627e699d2aSArseniy Krasnov 	close(fd);
10637e699d2aSArseniy Krasnov }
10647e699d2aSArseniy Krasnov 
test_stream_inv_buf_client(const struct test_opts * opts)10657e699d2aSArseniy Krasnov static void test_stream_inv_buf_client(const struct test_opts *opts)
10667e699d2aSArseniy Krasnov {
10677e699d2aSArseniy Krasnov 	test_inv_buf_client(opts, true);
10687e699d2aSArseniy Krasnov }
10697e699d2aSArseniy Krasnov 
test_stream_inv_buf_server(const struct test_opts * opts)10707e699d2aSArseniy Krasnov static void test_stream_inv_buf_server(const struct test_opts *opts)
10717e699d2aSArseniy Krasnov {
10727e699d2aSArseniy Krasnov 	test_inv_buf_server(opts, true);
10737e699d2aSArseniy Krasnov }
10747e699d2aSArseniy Krasnov 
test_seqpacket_inv_buf_client(const struct test_opts * opts)10757e699d2aSArseniy Krasnov static void test_seqpacket_inv_buf_client(const struct test_opts *opts)
10767e699d2aSArseniy Krasnov {
10777e699d2aSArseniy Krasnov 	test_inv_buf_client(opts, false);
10787e699d2aSArseniy Krasnov }
10797e699d2aSArseniy Krasnov 
test_seqpacket_inv_buf_server(const struct test_opts * opts)10807e699d2aSArseniy Krasnov static void test_seqpacket_inv_buf_server(const struct test_opts *opts)
10817e699d2aSArseniy Krasnov {
10827e699d2aSArseniy Krasnov 	test_inv_buf_server(opts, false);
10837e699d2aSArseniy Krasnov }
10847e699d2aSArseniy Krasnov 
108525209a32SArseniy Krasnov #define HELLO_STR "HELLO"
108625209a32SArseniy Krasnov #define WORLD_STR "WORLD"
108725209a32SArseniy Krasnov 
test_stream_virtio_skb_merge_client(const struct test_opts * opts)108825209a32SArseniy Krasnov static void test_stream_virtio_skb_merge_client(const struct test_opts *opts)
108925209a32SArseniy Krasnov {
109025209a32SArseniy Krasnov 	ssize_t res;
109125209a32SArseniy Krasnov 	int fd;
109225209a32SArseniy Krasnov 
109325209a32SArseniy Krasnov 	fd = vsock_stream_connect(opts->peer_cid, 1234);
109425209a32SArseniy Krasnov 	if (fd < 0) {
109525209a32SArseniy Krasnov 		perror("connect");
109625209a32SArseniy Krasnov 		exit(EXIT_FAILURE);
109725209a32SArseniy Krasnov 	}
109825209a32SArseniy Krasnov 
109925209a32SArseniy Krasnov 	/* Send first skbuff. */
110025209a32SArseniy Krasnov 	res = send(fd, HELLO_STR, strlen(HELLO_STR), 0);
110125209a32SArseniy Krasnov 	if (res != strlen(HELLO_STR)) {
110225209a32SArseniy Krasnov 		fprintf(stderr, "unexpected send(2) result %zi\n", res);
110325209a32SArseniy Krasnov 		exit(EXIT_FAILURE);
110425209a32SArseniy Krasnov 	}
110525209a32SArseniy Krasnov 
110625209a32SArseniy Krasnov 	control_writeln("SEND0");
110725209a32SArseniy Krasnov 	/* Peer reads part of first skbuff. */
110825209a32SArseniy Krasnov 	control_expectln("REPLY0");
110925209a32SArseniy Krasnov 
111025209a32SArseniy Krasnov 	/* Send second skbuff, it will be appended to the first. */
111125209a32SArseniy Krasnov 	res = send(fd, WORLD_STR, strlen(WORLD_STR), 0);
111225209a32SArseniy Krasnov 	if (res != strlen(WORLD_STR)) {
111325209a32SArseniy Krasnov 		fprintf(stderr, "unexpected send(2) result %zi\n", res);
111425209a32SArseniy Krasnov 		exit(EXIT_FAILURE);
111525209a32SArseniy Krasnov 	}
111625209a32SArseniy Krasnov 
111725209a32SArseniy Krasnov 	control_writeln("SEND1");
111825209a32SArseniy Krasnov 	/* Peer reads merged skbuff packet. */
111925209a32SArseniy Krasnov 	control_expectln("REPLY1");
112025209a32SArseniy Krasnov 
112125209a32SArseniy Krasnov 	close(fd);
112225209a32SArseniy Krasnov }
112325209a32SArseniy Krasnov 
test_stream_virtio_skb_merge_server(const struct test_opts * opts)112425209a32SArseniy Krasnov static void test_stream_virtio_skb_merge_server(const struct test_opts *opts)
112525209a32SArseniy Krasnov {
112625209a32SArseniy Krasnov 	unsigned char buf[64];
112725209a32SArseniy Krasnov 	ssize_t res;
112825209a32SArseniy Krasnov 	int fd;
112925209a32SArseniy Krasnov 
113025209a32SArseniy Krasnov 	fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
113125209a32SArseniy Krasnov 	if (fd < 0) {
113225209a32SArseniy Krasnov 		perror("accept");
113325209a32SArseniy Krasnov 		exit(EXIT_FAILURE);
113425209a32SArseniy Krasnov 	}
113525209a32SArseniy Krasnov 
113625209a32SArseniy Krasnov 	control_expectln("SEND0");
113725209a32SArseniy Krasnov 
113825209a32SArseniy Krasnov 	/* Read skbuff partially. */
113925209a32SArseniy Krasnov 	res = recv(fd, buf, 2, 0);
114025209a32SArseniy Krasnov 	if (res != 2) {
114125209a32SArseniy Krasnov 		fprintf(stderr, "expected recv(2) returns 2 bytes, got %zi\n", res);
114225209a32SArseniy Krasnov 		exit(EXIT_FAILURE);
114325209a32SArseniy Krasnov 	}
114425209a32SArseniy Krasnov 
114525209a32SArseniy Krasnov 	control_writeln("REPLY0");
114625209a32SArseniy Krasnov 	control_expectln("SEND1");
114725209a32SArseniy Krasnov 
114825209a32SArseniy Krasnov 	res = recv(fd, buf + 2, sizeof(buf) - 2, 0);
114925209a32SArseniy Krasnov 	if (res != 8) {
115025209a32SArseniy Krasnov 		fprintf(stderr, "expected recv(2) returns 8 bytes, got %zi\n", res);
115125209a32SArseniy Krasnov 		exit(EXIT_FAILURE);
115225209a32SArseniy Krasnov 	}
115325209a32SArseniy Krasnov 
115425209a32SArseniy Krasnov 	res = recv(fd, buf, sizeof(buf) - 8 - 2, MSG_DONTWAIT);
115525209a32SArseniy Krasnov 	if (res != -1) {
115625209a32SArseniy Krasnov 		fprintf(stderr, "expected recv(2) failure, got %zi\n", res);
115725209a32SArseniy Krasnov 		exit(EXIT_FAILURE);
115825209a32SArseniy Krasnov 	}
115925209a32SArseniy Krasnov 
116025209a32SArseniy Krasnov 	if (memcmp(buf, HELLO_STR WORLD_STR, strlen(HELLO_STR WORLD_STR))) {
116125209a32SArseniy Krasnov 		fprintf(stderr, "pattern mismatch\n");
116225209a32SArseniy Krasnov 		exit(EXIT_FAILURE);
116325209a32SArseniy Krasnov 	}
116425209a32SArseniy Krasnov 
116525209a32SArseniy Krasnov 	control_writeln("REPLY1");
116625209a32SArseniy Krasnov 
116725209a32SArseniy Krasnov 	close(fd);
116825209a32SArseniy Krasnov }
116925209a32SArseniy Krasnov 
test_seqpacket_msg_peek_client(const struct test_opts * opts)11708a0697f2SArseniy Krasnov static void test_seqpacket_msg_peek_client(const struct test_opts *opts)
11718a0697f2SArseniy Krasnov {
11728a0697f2SArseniy Krasnov 	return test_msg_peek_client(opts, true);
11738a0697f2SArseniy Krasnov }
11748a0697f2SArseniy Krasnov 
test_seqpacket_msg_peek_server(const struct test_opts * opts)11758a0697f2SArseniy Krasnov static void test_seqpacket_msg_peek_server(const struct test_opts *opts)
11768a0697f2SArseniy Krasnov {
11778a0697f2SArseniy Krasnov 	return test_msg_peek_server(opts, true);
11788a0697f2SArseniy Krasnov }
11798a0697f2SArseniy Krasnov 
1180cdbcc18dSStefan Hajnoczi static struct test_case test_cases[] = {
1181cdbcc18dSStefan Hajnoczi 	{
1182cdbcc18dSStefan Hajnoczi 		.name = "SOCK_STREAM connection reset",
1183cdbcc18dSStefan Hajnoczi 		.run_client = test_stream_connection_reset,
1184cdbcc18dSStefan Hajnoczi 	},
1185cdbcc18dSStefan Hajnoczi 	{
11869de9f7d1SSebastien Boeuf 		.name = "SOCK_STREAM bind only",
11879de9f7d1SSebastien Boeuf 		.run_client = test_stream_bind_only_client,
11889de9f7d1SSebastien Boeuf 		.run_server = test_stream_bind_only_server,
11899de9f7d1SSebastien Boeuf 	},
11909de9f7d1SSebastien Boeuf 	{
1191cdbcc18dSStefan Hajnoczi 		.name = "SOCK_STREAM client close",
1192cdbcc18dSStefan Hajnoczi 		.run_client = test_stream_client_close_client,
1193cdbcc18dSStefan Hajnoczi 		.run_server = test_stream_client_close_server,
1194cdbcc18dSStefan Hajnoczi 	},
1195cdbcc18dSStefan Hajnoczi 	{
1196cdbcc18dSStefan Hajnoczi 		.name = "SOCK_STREAM server close",
1197cdbcc18dSStefan Hajnoczi 		.run_client = test_stream_server_close_client,
1198cdbcc18dSStefan Hajnoczi 		.run_server = test_stream_server_close_server,
1199cdbcc18dSStefan Hajnoczi 	},
1200cdbcc18dSStefan Hajnoczi 	{
1201cdbcc18dSStefan Hajnoczi 		.name = "SOCK_STREAM multiple connections",
1202cdbcc18dSStefan Hajnoczi 		.run_client = test_stream_multiconn_client,
1203cdbcc18dSStefan Hajnoczi 		.run_server = test_stream_multiconn_server,
1204cdbcc18dSStefan Hajnoczi 	},
1205d6269a93SStefano Garzarella 	{
1206d6269a93SStefano Garzarella 		.name = "SOCK_STREAM MSG_PEEK",
1207d6269a93SStefano Garzarella 		.run_client = test_stream_msg_peek_client,
1208d6269a93SStefano Garzarella 		.run_server = test_stream_msg_peek_server,
1209d6269a93SStefano Garzarella 	},
121041b792d7SArseny Krasnov 	{
121141b792d7SArseny Krasnov 		.name = "SOCK_SEQPACKET msg bounds",
121241b792d7SArseny Krasnov 		.run_client = test_seqpacket_msg_bounds_client,
121341b792d7SArseny Krasnov 		.run_server = test_seqpacket_msg_bounds_server,
121441b792d7SArseny Krasnov 	},
121541b792d7SArseny Krasnov 	{
121641b792d7SArseny Krasnov 		.name = "SOCK_SEQPACKET MSG_TRUNC flag",
121741b792d7SArseny Krasnov 		.run_client = test_seqpacket_msg_trunc_client,
121841b792d7SArseny Krasnov 		.run_server = test_seqpacket_msg_trunc_server,
121941b792d7SArseny Krasnov 	},
1220efb3719fSKrasnov Arseniy Vladimirovich 	{
1221efb3719fSKrasnov Arseniy Vladimirovich 		.name = "SOCK_SEQPACKET timeout",
1222efb3719fSKrasnov Arseniy Vladimirovich 		.run_client = test_seqpacket_timeout_client,
1223efb3719fSKrasnov Arseniy Vladimirovich 		.run_server = test_seqpacket_timeout_server,
1224efb3719fSKrasnov Arseniy Vladimirovich 	},
1225e89600ebSKrasnov Arseniy Vladimirovich 	{
1226e89600ebSKrasnov Arseniy Vladimirovich 		.name = "SOCK_SEQPACKET invalid receive buffer",
1227e89600ebSKrasnov Arseniy Vladimirovich 		.run_client = test_seqpacket_invalid_rec_buffer_client,
1228e89600ebSKrasnov Arseniy Vladimirovich 		.run_server = test_seqpacket_invalid_rec_buffer_server,
1229e89600ebSKrasnov Arseniy Vladimirovich 	},
1230b1346338SArseniy Krasnov 	{
1231b1346338SArseniy Krasnov 		.name = "SOCK_STREAM poll() + SO_RCVLOWAT",
1232b1346338SArseniy Krasnov 		.run_client = test_stream_poll_rcvlowat_client,
1233b1346338SArseniy Krasnov 		.run_server = test_stream_poll_rcvlowat_server,
1234b1346338SArseniy Krasnov 	},
1235685a21c3SArseniy Krasnov 	{
1236685a21c3SArseniy Krasnov 		.name = "SOCK_SEQPACKET big message",
1237685a21c3SArseniy Krasnov 		.run_client = test_seqpacket_bigmsg_client,
1238685a21c3SArseniy Krasnov 		.run_server = test_seqpacket_bigmsg_server,
1239685a21c3SArseniy Krasnov 	},
12407e699d2aSArseniy Krasnov 	{
12417e699d2aSArseniy Krasnov 		.name = "SOCK_STREAM test invalid buffer",
12427e699d2aSArseniy Krasnov 		.run_client = test_stream_inv_buf_client,
12437e699d2aSArseniy Krasnov 		.run_server = test_stream_inv_buf_server,
12447e699d2aSArseniy Krasnov 	},
12457e699d2aSArseniy Krasnov 	{
12467e699d2aSArseniy Krasnov 		.name = "SOCK_SEQPACKET test invalid buffer",
12477e699d2aSArseniy Krasnov 		.run_client = test_seqpacket_inv_buf_client,
12487e699d2aSArseniy Krasnov 		.run_server = test_seqpacket_inv_buf_server,
12497e699d2aSArseniy Krasnov 	},
125025209a32SArseniy Krasnov 	{
125125209a32SArseniy Krasnov 		.name = "SOCK_STREAM virtio skb merge",
125225209a32SArseniy Krasnov 		.run_client = test_stream_virtio_skb_merge_client,
125325209a32SArseniy Krasnov 		.run_server = test_stream_virtio_skb_merge_server,
125425209a32SArseniy Krasnov 	},
12558a0697f2SArseniy Krasnov 	{
12568a0697f2SArseniy Krasnov 		.name = "SOCK_SEQPACKET MSG_PEEK",
12578a0697f2SArseniy Krasnov 		.run_client = test_seqpacket_msg_peek_client,
12588a0697f2SArseniy Krasnov 		.run_server = test_seqpacket_msg_peek_server,
12598a0697f2SArseniy Krasnov 	},
1260cdbcc18dSStefan Hajnoczi 	{},
1261cdbcc18dSStefan Hajnoczi };
1262cdbcc18dSStefan Hajnoczi 
1263cdbcc18dSStefan Hajnoczi static const char optstring[] = "";
1264cdbcc18dSStefan Hajnoczi static const struct option longopts[] = {
1265cdbcc18dSStefan Hajnoczi 	{
1266cdbcc18dSStefan Hajnoczi 		.name = "control-host",
1267cdbcc18dSStefan Hajnoczi 		.has_arg = required_argument,
1268cdbcc18dSStefan Hajnoczi 		.val = 'H',
1269cdbcc18dSStefan Hajnoczi 	},
1270cdbcc18dSStefan Hajnoczi 	{
1271cdbcc18dSStefan Hajnoczi 		.name = "control-port",
1272cdbcc18dSStefan Hajnoczi 		.has_arg = required_argument,
1273cdbcc18dSStefan Hajnoczi 		.val = 'P',
1274cdbcc18dSStefan Hajnoczi 	},
1275cdbcc18dSStefan Hajnoczi 	{
1276cdbcc18dSStefan Hajnoczi 		.name = "mode",
1277cdbcc18dSStefan Hajnoczi 		.has_arg = required_argument,
1278cdbcc18dSStefan Hajnoczi 		.val = 'm',
1279cdbcc18dSStefan Hajnoczi 	},
1280cdbcc18dSStefan Hajnoczi 	{
1281cdbcc18dSStefan Hajnoczi 		.name = "peer-cid",
1282cdbcc18dSStefan Hajnoczi 		.has_arg = required_argument,
1283cdbcc18dSStefan Hajnoczi 		.val = 'p',
1284cdbcc18dSStefan Hajnoczi 	},
1285cdbcc18dSStefan Hajnoczi 	{
12865a2b2425SStefano Garzarella 		.name = "list",
12875a2b2425SStefano Garzarella 		.has_arg = no_argument,
12885a2b2425SStefano Garzarella 		.val = 'l',
12895a2b2425SStefano Garzarella 	},
12905a2b2425SStefano Garzarella 	{
12915a2b2425SStefano Garzarella 		.name = "skip",
12925a2b2425SStefano Garzarella 		.has_arg = required_argument,
12935a2b2425SStefano Garzarella 		.val = 's',
12945a2b2425SStefano Garzarella 	},
12955a2b2425SStefano Garzarella 	{
1296cdbcc18dSStefan Hajnoczi 		.name = "help",
1297cdbcc18dSStefan Hajnoczi 		.has_arg = no_argument,
1298cdbcc18dSStefan Hajnoczi 		.val = '?',
1299cdbcc18dSStefan Hajnoczi 	},
1300cdbcc18dSStefan Hajnoczi 	{},
1301cdbcc18dSStefan Hajnoczi };
1302cdbcc18dSStefan Hajnoczi 
usage(void)1303cdbcc18dSStefan Hajnoczi static void usage(void)
1304cdbcc18dSStefan Hajnoczi {
13055a2b2425SStefano Garzarella 	fprintf(stderr, "Usage: vsock_test [--help] [--control-host=<host>] --control-port=<port> --mode=client|server --peer-cid=<cid> [--list] [--skip=<test_id>]\n"
1306cdbcc18dSStefan Hajnoczi 		"\n"
1307cdbcc18dSStefan Hajnoczi 		"  Server: vsock_test --control-port=1234 --mode=server --peer-cid=3\n"
1308cdbcc18dSStefan Hajnoczi 		"  Client: vsock_test --control-host=192.168.0.1 --control-port=1234 --mode=client --peer-cid=2\n"
1309cdbcc18dSStefan Hajnoczi 		"\n"
1310cdbcc18dSStefan Hajnoczi 		"Run vsock.ko tests.  Must be launched in both guest\n"
1311cdbcc18dSStefan Hajnoczi 		"and host.  One side must use --mode=client and\n"
1312cdbcc18dSStefan Hajnoczi 		"the other side must use --mode=server.\n"
1313cdbcc18dSStefan Hajnoczi 		"\n"
1314cdbcc18dSStefan Hajnoczi 		"A TCP control socket connection is used to coordinate tests\n"
1315cdbcc18dSStefan Hajnoczi 		"between the client and the server.  The server requires a\n"
1316cdbcc18dSStefan Hajnoczi 		"listen address and the client requires an address to\n"
1317cdbcc18dSStefan Hajnoczi 		"connect to.\n"
1318cdbcc18dSStefan Hajnoczi 		"\n"
13198d00b93fSStefano Garzarella 		"The CID of the other side must be given with --peer-cid=<cid>.\n"
13208d00b93fSStefano Garzarella 		"\n"
13218d00b93fSStefano Garzarella 		"Options:\n"
13228d00b93fSStefano Garzarella 		"  --help                 This help message\n"
13238d00b93fSStefano Garzarella 		"  --control-host <host>  Server IP address to connect to\n"
13248d00b93fSStefano Garzarella 		"  --control-port <port>  Server port to listen on/connect to\n"
13258d00b93fSStefano Garzarella 		"  --mode client|server   Server or client mode\n"
13268d00b93fSStefano Garzarella 		"  --peer-cid <cid>       CID of the other side\n"
13278d00b93fSStefano Garzarella 		"  --list                 List of tests that will be executed\n"
13288d00b93fSStefano Garzarella 		"  --skip <test_id>       Test ID to skip;\n"
13298d00b93fSStefano Garzarella 		"                         use multiple --skip options to skip more tests\n"
13308d00b93fSStefano Garzarella 		);
1331cdbcc18dSStefan Hajnoczi 	exit(EXIT_FAILURE);
1332cdbcc18dSStefan Hajnoczi }
1333cdbcc18dSStefan Hajnoczi 
main(int argc,char ** argv)1334cdbcc18dSStefan Hajnoczi int main(int argc, char **argv)
1335cdbcc18dSStefan Hajnoczi {
1336cdbcc18dSStefan Hajnoczi 	const char *control_host = NULL;
1337cdbcc18dSStefan Hajnoczi 	const char *control_port = NULL;
1338cdbcc18dSStefan Hajnoczi 	struct test_opts opts = {
1339cdbcc18dSStefan Hajnoczi 		.mode = TEST_MODE_UNSET,
1340cdbcc18dSStefan Hajnoczi 		.peer_cid = VMADDR_CID_ANY,
1341cdbcc18dSStefan Hajnoczi 	};
1342cdbcc18dSStefan Hajnoczi 
13435c338112SArseniy Krasnov 	srand(time(NULL));
1344cdbcc18dSStefan Hajnoczi 	init_signals();
1345cdbcc18dSStefan Hajnoczi 
1346cdbcc18dSStefan Hajnoczi 	for (;;) {
1347cdbcc18dSStefan Hajnoczi 		int opt = getopt_long(argc, argv, optstring, longopts, NULL);
1348cdbcc18dSStefan Hajnoczi 
1349cdbcc18dSStefan Hajnoczi 		if (opt == -1)
1350cdbcc18dSStefan Hajnoczi 			break;
1351cdbcc18dSStefan Hajnoczi 
1352cdbcc18dSStefan Hajnoczi 		switch (opt) {
1353cdbcc18dSStefan Hajnoczi 		case 'H':
1354cdbcc18dSStefan Hajnoczi 			control_host = optarg;
1355cdbcc18dSStefan Hajnoczi 			break;
1356cdbcc18dSStefan Hajnoczi 		case 'm':
1357cdbcc18dSStefan Hajnoczi 			if (strcmp(optarg, "client") == 0)
1358cdbcc18dSStefan Hajnoczi 				opts.mode = TEST_MODE_CLIENT;
1359cdbcc18dSStefan Hajnoczi 			else if (strcmp(optarg, "server") == 0)
1360cdbcc18dSStefan Hajnoczi 				opts.mode = TEST_MODE_SERVER;
1361cdbcc18dSStefan Hajnoczi 			else {
1362cdbcc18dSStefan Hajnoczi 				fprintf(stderr, "--mode must be \"client\" or \"server\"\n");
1363cdbcc18dSStefan Hajnoczi 				return EXIT_FAILURE;
1364cdbcc18dSStefan Hajnoczi 			}
1365cdbcc18dSStefan Hajnoczi 			break;
1366cdbcc18dSStefan Hajnoczi 		case 'p':
1367cdbcc18dSStefan Hajnoczi 			opts.peer_cid = parse_cid(optarg);
1368cdbcc18dSStefan Hajnoczi 			break;
1369cdbcc18dSStefan Hajnoczi 		case 'P':
1370cdbcc18dSStefan Hajnoczi 			control_port = optarg;
1371cdbcc18dSStefan Hajnoczi 			break;
13725a2b2425SStefano Garzarella 		case 'l':
13735a2b2425SStefano Garzarella 			list_tests(test_cases);
13745a2b2425SStefano Garzarella 			break;
13755a2b2425SStefano Garzarella 		case 's':
13765a2b2425SStefano Garzarella 			skip_test(test_cases, ARRAY_SIZE(test_cases) - 1,
13775a2b2425SStefano Garzarella 				  optarg);
13785a2b2425SStefano Garzarella 			break;
1379cdbcc18dSStefan Hajnoczi 		case '?':
1380cdbcc18dSStefan Hajnoczi 		default:
1381cdbcc18dSStefan Hajnoczi 			usage();
1382cdbcc18dSStefan Hajnoczi 		}
1383cdbcc18dSStefan Hajnoczi 	}
1384cdbcc18dSStefan Hajnoczi 
1385cdbcc18dSStefan Hajnoczi 	if (!control_port)
1386cdbcc18dSStefan Hajnoczi 		usage();
1387cdbcc18dSStefan Hajnoczi 	if (opts.mode == TEST_MODE_UNSET)
1388cdbcc18dSStefan Hajnoczi 		usage();
1389cdbcc18dSStefan Hajnoczi 	if (opts.peer_cid == VMADDR_CID_ANY)
1390cdbcc18dSStefan Hajnoczi 		usage();
1391cdbcc18dSStefan Hajnoczi 
1392cdbcc18dSStefan Hajnoczi 	if (!control_host) {
1393cdbcc18dSStefan Hajnoczi 		if (opts.mode != TEST_MODE_SERVER)
1394cdbcc18dSStefan Hajnoczi 			usage();
1395cdbcc18dSStefan Hajnoczi 		control_host = "0.0.0.0";
1396cdbcc18dSStefan Hajnoczi 	}
1397cdbcc18dSStefan Hajnoczi 
1398cdbcc18dSStefan Hajnoczi 	control_init(control_host, control_port,
1399cdbcc18dSStefan Hajnoczi 		     opts.mode == TEST_MODE_SERVER);
1400cdbcc18dSStefan Hajnoczi 
1401cdbcc18dSStefan Hajnoczi 	run_tests(test_cases, &opts);
1402cdbcc18dSStefan Hajnoczi 
1403cdbcc18dSStefan Hajnoczi 	control_cleanup();
1404cdbcc18dSStefan Hajnoczi 	return EXIT_SUCCESS;
1405cdbcc18dSStefan Hajnoczi }
1406