xref: /linux/tools/testing/vsock/vsock_test.c (revision 9410645520e9b820069761f3450ef6661418e279)
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>
22b698bd97SArseniy Krasnov #include <signal.h>
23*18ee44ceSLuigi Leonardi #include <sys/ioctl.h>
24*18ee44ceSLuigi Leonardi #include <linux/sockios.h>
25cdbcc18dSStefan Hajnoczi 
26bc36442eSArseniy Krasnov #include "vsock_test_zerocopy.h"
27cdbcc18dSStefan Hajnoczi #include "timeout.h"
28cdbcc18dSStefan Hajnoczi #include "control.h"
29cdbcc18dSStefan Hajnoczi #include "util.h"
30cdbcc18dSStefan Hajnoczi 
test_stream_connection_reset(const struct test_opts * opts)31cdbcc18dSStefan Hajnoczi static void test_stream_connection_reset(const struct test_opts *opts)
32cdbcc18dSStefan Hajnoczi {
33cdbcc18dSStefan Hajnoczi 	union {
34cdbcc18dSStefan Hajnoczi 		struct sockaddr sa;
35cdbcc18dSStefan Hajnoczi 		struct sockaddr_vm svm;
36cdbcc18dSStefan Hajnoczi 	} addr = {
37cdbcc18dSStefan Hajnoczi 		.svm = {
38cdbcc18dSStefan Hajnoczi 			.svm_family = AF_VSOCK,
39e18c7092SArseniy Krasnov 			.svm_port = opts->peer_port,
40cdbcc18dSStefan Hajnoczi 			.svm_cid = opts->peer_cid,
41cdbcc18dSStefan Hajnoczi 		},
42cdbcc18dSStefan Hajnoczi 	};
43cdbcc18dSStefan Hajnoczi 	int ret;
44cdbcc18dSStefan Hajnoczi 	int fd;
45cdbcc18dSStefan Hajnoczi 
46cdbcc18dSStefan Hajnoczi 	fd = socket(AF_VSOCK, SOCK_STREAM, 0);
47cdbcc18dSStefan Hajnoczi 
48cdbcc18dSStefan Hajnoczi 	timeout_begin(TIMEOUT);
49cdbcc18dSStefan Hajnoczi 	do {
50cdbcc18dSStefan Hajnoczi 		ret = connect(fd, &addr.sa, sizeof(addr.svm));
51cdbcc18dSStefan Hajnoczi 		timeout_check("connect");
52cdbcc18dSStefan Hajnoczi 	} while (ret < 0 && errno == EINTR);
53cdbcc18dSStefan Hajnoczi 	timeout_end();
54cdbcc18dSStefan Hajnoczi 
55cdbcc18dSStefan Hajnoczi 	if (ret != -1) {
56cdbcc18dSStefan Hajnoczi 		fprintf(stderr, "expected connect(2) failure, got %d\n", ret);
57cdbcc18dSStefan Hajnoczi 		exit(EXIT_FAILURE);
58cdbcc18dSStefan Hajnoczi 	}
59cdbcc18dSStefan Hajnoczi 	if (errno != ECONNRESET) {
60cdbcc18dSStefan Hajnoczi 		fprintf(stderr, "unexpected connect(2) errno %d\n", errno);
61cdbcc18dSStefan Hajnoczi 		exit(EXIT_FAILURE);
62cdbcc18dSStefan Hajnoczi 	}
63cdbcc18dSStefan Hajnoczi 
64cdbcc18dSStefan Hajnoczi 	close(fd);
65cdbcc18dSStefan Hajnoczi }
66cdbcc18dSStefan Hajnoczi 
test_stream_bind_only_client(const struct test_opts * opts)679de9f7d1SSebastien Boeuf static void test_stream_bind_only_client(const struct test_opts *opts)
689de9f7d1SSebastien Boeuf {
699de9f7d1SSebastien Boeuf 	union {
709de9f7d1SSebastien Boeuf 		struct sockaddr sa;
719de9f7d1SSebastien Boeuf 		struct sockaddr_vm svm;
729de9f7d1SSebastien Boeuf 	} addr = {
739de9f7d1SSebastien Boeuf 		.svm = {
749de9f7d1SSebastien Boeuf 			.svm_family = AF_VSOCK,
75e18c7092SArseniy Krasnov 			.svm_port = opts->peer_port,
769de9f7d1SSebastien Boeuf 			.svm_cid = opts->peer_cid,
779de9f7d1SSebastien Boeuf 		},
789de9f7d1SSebastien Boeuf 	};
799de9f7d1SSebastien Boeuf 	int ret;
809de9f7d1SSebastien Boeuf 	int fd;
819de9f7d1SSebastien Boeuf 
829de9f7d1SSebastien Boeuf 	/* Wait for the server to be ready */
839de9f7d1SSebastien Boeuf 	control_expectln("BIND");
849de9f7d1SSebastien Boeuf 
859de9f7d1SSebastien Boeuf 	fd = socket(AF_VSOCK, SOCK_STREAM, 0);
869de9f7d1SSebastien Boeuf 
879de9f7d1SSebastien Boeuf 	timeout_begin(TIMEOUT);
889de9f7d1SSebastien Boeuf 	do {
899de9f7d1SSebastien Boeuf 		ret = connect(fd, &addr.sa, sizeof(addr.svm));
909de9f7d1SSebastien Boeuf 		timeout_check("connect");
919de9f7d1SSebastien Boeuf 	} while (ret < 0 && errno == EINTR);
929de9f7d1SSebastien Boeuf 	timeout_end();
939de9f7d1SSebastien Boeuf 
949de9f7d1SSebastien Boeuf 	if (ret != -1) {
959de9f7d1SSebastien Boeuf 		fprintf(stderr, "expected connect(2) failure, got %d\n", ret);
969de9f7d1SSebastien Boeuf 		exit(EXIT_FAILURE);
979de9f7d1SSebastien Boeuf 	}
989de9f7d1SSebastien Boeuf 	if (errno != ECONNRESET) {
999de9f7d1SSebastien Boeuf 		fprintf(stderr, "unexpected connect(2) errno %d\n", errno);
1009de9f7d1SSebastien Boeuf 		exit(EXIT_FAILURE);
1019de9f7d1SSebastien Boeuf 	}
1029de9f7d1SSebastien Boeuf 
1039de9f7d1SSebastien Boeuf 	/* Notify the server that the client has finished */
1049de9f7d1SSebastien Boeuf 	control_writeln("DONE");
1059de9f7d1SSebastien Boeuf 
1069de9f7d1SSebastien Boeuf 	close(fd);
1079de9f7d1SSebastien Boeuf }
1089de9f7d1SSebastien Boeuf 
test_stream_bind_only_server(const struct test_opts * opts)1099de9f7d1SSebastien Boeuf static void test_stream_bind_only_server(const struct test_opts *opts)
1109de9f7d1SSebastien Boeuf {
1119de9f7d1SSebastien Boeuf 	union {
1129de9f7d1SSebastien Boeuf 		struct sockaddr sa;
1139de9f7d1SSebastien Boeuf 		struct sockaddr_vm svm;
1149de9f7d1SSebastien Boeuf 	} addr = {
1159de9f7d1SSebastien Boeuf 		.svm = {
1169de9f7d1SSebastien Boeuf 			.svm_family = AF_VSOCK,
117e18c7092SArseniy Krasnov 			.svm_port = opts->peer_port,
1189de9f7d1SSebastien Boeuf 			.svm_cid = VMADDR_CID_ANY,
1199de9f7d1SSebastien Boeuf 		},
1209de9f7d1SSebastien Boeuf 	};
1219de9f7d1SSebastien Boeuf 	int fd;
1229de9f7d1SSebastien Boeuf 
1239de9f7d1SSebastien Boeuf 	fd = socket(AF_VSOCK, SOCK_STREAM, 0);
1249de9f7d1SSebastien Boeuf 
1259de9f7d1SSebastien Boeuf 	if (bind(fd, &addr.sa, sizeof(addr.svm)) < 0) {
1269de9f7d1SSebastien Boeuf 		perror("bind");
1279de9f7d1SSebastien Boeuf 		exit(EXIT_FAILURE);
1289de9f7d1SSebastien Boeuf 	}
1299de9f7d1SSebastien Boeuf 
1309de9f7d1SSebastien Boeuf 	/* Notify the client that the server is ready */
1319de9f7d1SSebastien Boeuf 	control_writeln("BIND");
1329de9f7d1SSebastien Boeuf 
1339de9f7d1SSebastien Boeuf 	/* Wait for the client to finish */
1349de9f7d1SSebastien Boeuf 	control_expectln("DONE");
1359de9f7d1SSebastien Boeuf 
1369de9f7d1SSebastien Boeuf 	close(fd);
1379de9f7d1SSebastien Boeuf }
1389de9f7d1SSebastien Boeuf 
test_stream_client_close_client(const struct test_opts * opts)139cdbcc18dSStefan Hajnoczi static void test_stream_client_close_client(const struct test_opts *opts)
140cdbcc18dSStefan Hajnoczi {
141cdbcc18dSStefan Hajnoczi 	int fd;
142cdbcc18dSStefan Hajnoczi 
143e18c7092SArseniy Krasnov 	fd = vsock_stream_connect(opts->peer_cid, opts->peer_port);
144cdbcc18dSStefan Hajnoczi 	if (fd < 0) {
145cdbcc18dSStefan Hajnoczi 		perror("connect");
146cdbcc18dSStefan Hajnoczi 		exit(EXIT_FAILURE);
147cdbcc18dSStefan Hajnoczi 	}
148cdbcc18dSStefan Hajnoczi 
149cdbcc18dSStefan Hajnoczi 	send_byte(fd, 1, 0);
150cdbcc18dSStefan Hajnoczi 	close(fd);
151cdbcc18dSStefan Hajnoczi }
152cdbcc18dSStefan Hajnoczi 
test_stream_client_close_server(const struct test_opts * opts)153cdbcc18dSStefan Hajnoczi static void test_stream_client_close_server(const struct test_opts *opts)
154cdbcc18dSStefan Hajnoczi {
155cdbcc18dSStefan Hajnoczi 	int fd;
156cdbcc18dSStefan Hajnoczi 
157e18c7092SArseniy Krasnov 	fd = vsock_stream_accept(VMADDR_CID_ANY, opts->peer_port, NULL);
158cdbcc18dSStefan Hajnoczi 	if (fd < 0) {
159cdbcc18dSStefan Hajnoczi 		perror("accept");
160cdbcc18dSStefan Hajnoczi 		exit(EXIT_FAILURE);
161cdbcc18dSStefan Hajnoczi 	}
162cdbcc18dSStefan Hajnoczi 
163770ce007SStefano Garzarella 	/* Wait for the remote to close the connection, before check
164770ce007SStefano Garzarella 	 * -EPIPE error on send.
165770ce007SStefano Garzarella 	 */
166770ce007SStefano Garzarella 	vsock_wait_remote_close(fd);
167cdbcc18dSStefan Hajnoczi 
168cdbcc18dSStefan Hajnoczi 	send_byte(fd, -EPIPE, 0);
169cdbcc18dSStefan Hajnoczi 	recv_byte(fd, 1, 0);
170cdbcc18dSStefan Hajnoczi 	recv_byte(fd, 0, 0);
171cdbcc18dSStefan Hajnoczi 	close(fd);
172cdbcc18dSStefan Hajnoczi }
173cdbcc18dSStefan Hajnoczi 
test_stream_server_close_client(const struct test_opts * opts)174cdbcc18dSStefan Hajnoczi static void test_stream_server_close_client(const struct test_opts *opts)
175cdbcc18dSStefan Hajnoczi {
176cdbcc18dSStefan Hajnoczi 	int fd;
177cdbcc18dSStefan Hajnoczi 
178e18c7092SArseniy Krasnov 	fd = vsock_stream_connect(opts->peer_cid, opts->peer_port);
179cdbcc18dSStefan Hajnoczi 	if (fd < 0) {
180cdbcc18dSStefan Hajnoczi 		perror("connect");
181cdbcc18dSStefan Hajnoczi 		exit(EXIT_FAILURE);
182cdbcc18dSStefan Hajnoczi 	}
183cdbcc18dSStefan Hajnoczi 
184770ce007SStefano Garzarella 	/* Wait for the remote to close the connection, before check
185770ce007SStefano Garzarella 	 * -EPIPE error on send.
186770ce007SStefano Garzarella 	 */
187770ce007SStefano Garzarella 	vsock_wait_remote_close(fd);
188cdbcc18dSStefan Hajnoczi 
189cdbcc18dSStefan Hajnoczi 	send_byte(fd, -EPIPE, 0);
190cdbcc18dSStefan Hajnoczi 	recv_byte(fd, 1, 0);
191cdbcc18dSStefan Hajnoczi 	recv_byte(fd, 0, 0);
192cdbcc18dSStefan Hajnoczi 	close(fd);
193cdbcc18dSStefan Hajnoczi }
194cdbcc18dSStefan Hajnoczi 
test_stream_server_close_server(const struct test_opts * opts)195cdbcc18dSStefan Hajnoczi static void test_stream_server_close_server(const struct test_opts *opts)
196cdbcc18dSStefan Hajnoczi {
197cdbcc18dSStefan Hajnoczi 	int fd;
198cdbcc18dSStefan Hajnoczi 
199e18c7092SArseniy Krasnov 	fd = vsock_stream_accept(VMADDR_CID_ANY, opts->peer_port, NULL);
200cdbcc18dSStefan Hajnoczi 	if (fd < 0) {
201cdbcc18dSStefan Hajnoczi 		perror("accept");
202cdbcc18dSStefan Hajnoczi 		exit(EXIT_FAILURE);
203cdbcc18dSStefan Hajnoczi 	}
204cdbcc18dSStefan Hajnoczi 
205cdbcc18dSStefan Hajnoczi 	send_byte(fd, 1, 0);
206cdbcc18dSStefan Hajnoczi 	close(fd);
207cdbcc18dSStefan Hajnoczi }
208cdbcc18dSStefan Hajnoczi 
209cdbcc18dSStefan Hajnoczi /* With the standard socket sizes, VMCI is able to support about 100
210cdbcc18dSStefan Hajnoczi  * concurrent stream connections.
211cdbcc18dSStefan Hajnoczi  */
212cdbcc18dSStefan Hajnoczi #define MULTICONN_NFDS 100
213cdbcc18dSStefan Hajnoczi 
test_stream_multiconn_client(const struct test_opts * opts)214cdbcc18dSStefan Hajnoczi static void test_stream_multiconn_client(const struct test_opts *opts)
215cdbcc18dSStefan Hajnoczi {
216cdbcc18dSStefan Hajnoczi 	int fds[MULTICONN_NFDS];
217cdbcc18dSStefan Hajnoczi 	int i;
218cdbcc18dSStefan Hajnoczi 
219cdbcc18dSStefan Hajnoczi 	for (i = 0; i < MULTICONN_NFDS; i++) {
220e18c7092SArseniy Krasnov 		fds[i] = vsock_stream_connect(opts->peer_cid, opts->peer_port);
221cdbcc18dSStefan Hajnoczi 		if (fds[i] < 0) {
222cdbcc18dSStefan Hajnoczi 			perror("connect");
223cdbcc18dSStefan Hajnoczi 			exit(EXIT_FAILURE);
224cdbcc18dSStefan Hajnoczi 		}
225cdbcc18dSStefan Hajnoczi 	}
226cdbcc18dSStefan Hajnoczi 
227cdbcc18dSStefan Hajnoczi 	for (i = 0; i < MULTICONN_NFDS; i++) {
228cdbcc18dSStefan Hajnoczi 		if (i % 2)
229cdbcc18dSStefan Hajnoczi 			recv_byte(fds[i], 1, 0);
230cdbcc18dSStefan Hajnoczi 		else
231cdbcc18dSStefan Hajnoczi 			send_byte(fds[i], 1, 0);
232cdbcc18dSStefan Hajnoczi 	}
233cdbcc18dSStefan Hajnoczi 
234cdbcc18dSStefan Hajnoczi 	for (i = 0; i < MULTICONN_NFDS; i++)
235cdbcc18dSStefan Hajnoczi 		close(fds[i]);
236cdbcc18dSStefan Hajnoczi }
237cdbcc18dSStefan Hajnoczi 
test_stream_multiconn_server(const struct test_opts * opts)238cdbcc18dSStefan Hajnoczi static void test_stream_multiconn_server(const struct test_opts *opts)
239cdbcc18dSStefan Hajnoczi {
240cdbcc18dSStefan Hajnoczi 	int fds[MULTICONN_NFDS];
241cdbcc18dSStefan Hajnoczi 	int i;
242cdbcc18dSStefan Hajnoczi 
243cdbcc18dSStefan Hajnoczi 	for (i = 0; i < MULTICONN_NFDS; i++) {
244e18c7092SArseniy Krasnov 		fds[i] = vsock_stream_accept(VMADDR_CID_ANY, opts->peer_port, NULL);
245cdbcc18dSStefan Hajnoczi 		if (fds[i] < 0) {
246cdbcc18dSStefan Hajnoczi 			perror("accept");
247cdbcc18dSStefan Hajnoczi 			exit(EXIT_FAILURE);
248cdbcc18dSStefan Hajnoczi 		}
249cdbcc18dSStefan Hajnoczi 	}
250cdbcc18dSStefan Hajnoczi 
251cdbcc18dSStefan Hajnoczi 	for (i = 0; i < MULTICONN_NFDS; i++) {
252cdbcc18dSStefan Hajnoczi 		if (i % 2)
253cdbcc18dSStefan Hajnoczi 			send_byte(fds[i], 1, 0);
254cdbcc18dSStefan Hajnoczi 		else
255cdbcc18dSStefan Hajnoczi 			recv_byte(fds[i], 1, 0);
256cdbcc18dSStefan Hajnoczi 	}
257cdbcc18dSStefan Hajnoczi 
258cdbcc18dSStefan Hajnoczi 	for (i = 0; i < MULTICONN_NFDS; i++)
259cdbcc18dSStefan Hajnoczi 		close(fds[i]);
260cdbcc18dSStefan Hajnoczi }
261cdbcc18dSStefan Hajnoczi 
262587ed79fSArseniy Krasnov #define MSG_PEEK_BUF_LEN 64
263587ed79fSArseniy Krasnov 
test_msg_peek_client(const struct test_opts * opts,bool seqpacket)2648a0697f2SArseniy Krasnov static void test_msg_peek_client(const struct test_opts *opts,
2658a0697f2SArseniy Krasnov 				 bool seqpacket)
266d6269a93SStefano Garzarella {
267587ed79fSArseniy Krasnov 	unsigned char buf[MSG_PEEK_BUF_LEN];
268d6269a93SStefano Garzarella 	int fd;
269587ed79fSArseniy Krasnov 	int i;
270d6269a93SStefano Garzarella 
2718a0697f2SArseniy Krasnov 	if (seqpacket)
272e18c7092SArseniy Krasnov 		fd = vsock_seqpacket_connect(opts->peer_cid, opts->peer_port);
2738a0697f2SArseniy Krasnov 	else
274e18c7092SArseniy Krasnov 		fd = vsock_stream_connect(opts->peer_cid, opts->peer_port);
2758a0697f2SArseniy Krasnov 
276d6269a93SStefano Garzarella 	if (fd < 0) {
277d6269a93SStefano Garzarella 		perror("connect");
278d6269a93SStefano Garzarella 		exit(EXIT_FAILURE);
279d6269a93SStefano Garzarella 	}
280d6269a93SStefano Garzarella 
281587ed79fSArseniy Krasnov 	for (i = 0; i < sizeof(buf); i++)
282587ed79fSArseniy Krasnov 		buf[i] = rand() & 0xFF;
283587ed79fSArseniy Krasnov 
284587ed79fSArseniy Krasnov 	control_expectln("SRVREADY");
285587ed79fSArseniy Krasnov 
2862a8548a9SStefano Garzarella 	send_buf(fd, buf, sizeof(buf), 0, sizeof(buf));
287587ed79fSArseniy Krasnov 
288d6269a93SStefano Garzarella 	close(fd);
289d6269a93SStefano Garzarella }
290d6269a93SStefano Garzarella 
test_msg_peek_server(const struct test_opts * opts,bool seqpacket)2918a0697f2SArseniy Krasnov static void test_msg_peek_server(const struct test_opts *opts,
2928a0697f2SArseniy Krasnov 				 bool seqpacket)
293d6269a93SStefano Garzarella {
294587ed79fSArseniy Krasnov 	unsigned char buf_half[MSG_PEEK_BUF_LEN / 2];
295587ed79fSArseniy Krasnov 	unsigned char buf_normal[MSG_PEEK_BUF_LEN];
296587ed79fSArseniy Krasnov 	unsigned char buf_peek[MSG_PEEK_BUF_LEN];
297d6269a93SStefano Garzarella 	int fd;
298d6269a93SStefano Garzarella 
2998a0697f2SArseniy Krasnov 	if (seqpacket)
300e18c7092SArseniy Krasnov 		fd = vsock_seqpacket_accept(VMADDR_CID_ANY, opts->peer_port, NULL);
3018a0697f2SArseniy Krasnov 	else
302e18c7092SArseniy Krasnov 		fd = vsock_stream_accept(VMADDR_CID_ANY, opts->peer_port, NULL);
3038a0697f2SArseniy Krasnov 
304d6269a93SStefano Garzarella 	if (fd < 0) {
305d6269a93SStefano Garzarella 		perror("accept");
306d6269a93SStefano Garzarella 		exit(EXIT_FAILURE);
307d6269a93SStefano Garzarella 	}
308d6269a93SStefano Garzarella 
309587ed79fSArseniy Krasnov 	/* Peek from empty socket. */
310a0bcb835SStefano Garzarella 	recv_buf(fd, buf_peek, sizeof(buf_peek), MSG_PEEK | MSG_DONTWAIT,
311a0bcb835SStefano Garzarella 		 -EAGAIN);
312587ed79fSArseniy Krasnov 
313587ed79fSArseniy Krasnov 	control_writeln("SRVREADY");
314587ed79fSArseniy Krasnov 
315587ed79fSArseniy Krasnov 	/* Peek part of data. */
316a0bcb835SStefano Garzarella 	recv_buf(fd, buf_half, sizeof(buf_half), MSG_PEEK, sizeof(buf_half));
317587ed79fSArseniy Krasnov 
318587ed79fSArseniy Krasnov 	/* Peek whole data. */
319a0bcb835SStefano Garzarella 	recv_buf(fd, buf_peek, sizeof(buf_peek), MSG_PEEK, sizeof(buf_peek));
320587ed79fSArseniy Krasnov 
321587ed79fSArseniy Krasnov 	/* Compare partial and full peek. */
322587ed79fSArseniy Krasnov 	if (memcmp(buf_half, buf_peek, sizeof(buf_half))) {
323587ed79fSArseniy Krasnov 		fprintf(stderr, "Partial peek data mismatch\n");
324587ed79fSArseniy Krasnov 		exit(EXIT_FAILURE);
325587ed79fSArseniy Krasnov 	}
326587ed79fSArseniy Krasnov 
3278a0697f2SArseniy Krasnov 	if (seqpacket) {
3288a0697f2SArseniy Krasnov 		/* This type of socket supports MSG_TRUNC flag,
3298a0697f2SArseniy Krasnov 		 * so check it with MSG_PEEK. We must get length
3308a0697f2SArseniy Krasnov 		 * of the message.
3318a0697f2SArseniy Krasnov 		 */
332a0bcb835SStefano Garzarella 		recv_buf(fd, buf_half, sizeof(buf_half), MSG_PEEK | MSG_TRUNC,
333a0bcb835SStefano Garzarella 			 sizeof(buf_peek));
3348a0697f2SArseniy Krasnov 	}
3358a0697f2SArseniy Krasnov 
336a0bcb835SStefano Garzarella 	recv_buf(fd, buf_normal, sizeof(buf_normal), 0, sizeof(buf_normal));
337587ed79fSArseniy Krasnov 
338587ed79fSArseniy Krasnov 	/* Compare full peek and normal read. */
339587ed79fSArseniy Krasnov 	if (memcmp(buf_peek, buf_normal, sizeof(buf_peek))) {
340587ed79fSArseniy Krasnov 		fprintf(stderr, "Full peek data mismatch\n");
341587ed79fSArseniy Krasnov 		exit(EXIT_FAILURE);
342587ed79fSArseniy Krasnov 	}
343587ed79fSArseniy Krasnov 
344d6269a93SStefano Garzarella 	close(fd);
345d6269a93SStefano Garzarella }
346d6269a93SStefano Garzarella 
test_stream_msg_peek_client(const struct test_opts * opts)3478a0697f2SArseniy Krasnov static void test_stream_msg_peek_client(const struct test_opts *opts)
3488a0697f2SArseniy Krasnov {
3498a0697f2SArseniy Krasnov 	return test_msg_peek_client(opts, false);
3508a0697f2SArseniy Krasnov }
3518a0697f2SArseniy Krasnov 
test_stream_msg_peek_server(const struct test_opts * opts)3528a0697f2SArseniy Krasnov static void test_stream_msg_peek_server(const struct test_opts *opts)
3538a0697f2SArseniy Krasnov {
3548a0697f2SArseniy Krasnov 	return test_msg_peek_server(opts, false);
3558a0697f2SArseniy Krasnov }
3568a0697f2SArseniy Krasnov 
3575c338112SArseniy Krasnov #define SOCK_BUF_SIZE (2 * 1024 * 1024)
358f0863888SArseniy Krasnov #define MAX_MSG_PAGES 4
3595c338112SArseniy Krasnov 
test_seqpacket_msg_bounds_client(const struct test_opts * opts)36041b792d7SArseny Krasnov static void test_seqpacket_msg_bounds_client(const struct test_opts *opts)
36141b792d7SArseny Krasnov {
3625c338112SArseniy Krasnov 	unsigned long curr_hash;
363f0863888SArseniy Krasnov 	size_t max_msg_size;
3645c338112SArseniy Krasnov 	int page_size;
3655c338112SArseniy Krasnov 	int msg_count;
36641b792d7SArseny Krasnov 	int fd;
36741b792d7SArseny Krasnov 
368e18c7092SArseniy Krasnov 	fd = vsock_seqpacket_connect(opts->peer_cid, opts->peer_port);
36941b792d7SArseny Krasnov 	if (fd < 0) {
37041b792d7SArseny Krasnov 		perror("connect");
37141b792d7SArseny Krasnov 		exit(EXIT_FAILURE);
37241b792d7SArseny Krasnov 	}
37341b792d7SArseny Krasnov 
3745c338112SArseniy Krasnov 	/* Wait, until receiver sets buffer size. */
3755c338112SArseniy Krasnov 	control_expectln("SRVREADY");
3765c338112SArseniy Krasnov 
3775c338112SArseniy Krasnov 	curr_hash = 0;
3785c338112SArseniy Krasnov 	page_size = getpagesize();
379f0863888SArseniy Krasnov 	max_msg_size = MAX_MSG_PAGES * page_size;
380f0863888SArseniy Krasnov 	msg_count = SOCK_BUF_SIZE / max_msg_size;
3815c338112SArseniy Krasnov 
3825c338112SArseniy Krasnov 	for (int i = 0; i < msg_count; i++) {
3835c338112SArseniy Krasnov 		size_t buf_size;
3845c338112SArseniy Krasnov 		int flags;
3855c338112SArseniy Krasnov 		void *buf;
3865c338112SArseniy Krasnov 
3875c338112SArseniy Krasnov 		/* Use "small" buffers and "big" buffers. */
3885c338112SArseniy Krasnov 		if (i & 1)
3895c338112SArseniy Krasnov 			buf_size = page_size +
390f0863888SArseniy Krasnov 					(rand() % (max_msg_size - page_size));
3915c338112SArseniy Krasnov 		else
3925c338112SArseniy Krasnov 			buf_size = 1 + (rand() % page_size);
3935c338112SArseniy Krasnov 
3945c338112SArseniy Krasnov 		buf = malloc(buf_size);
3955c338112SArseniy Krasnov 
3965c338112SArseniy Krasnov 		if (!buf) {
3975c338112SArseniy Krasnov 			perror("malloc");
3985c338112SArseniy Krasnov 			exit(EXIT_FAILURE);
3995c338112SArseniy Krasnov 		}
4005c338112SArseniy Krasnov 
4015c338112SArseniy Krasnov 		memset(buf, rand() & 0xff, buf_size);
4025c338112SArseniy Krasnov 		/* Set at least one MSG_EOR + some random. */
4035c338112SArseniy Krasnov 		if (i == (msg_count / 2) || (rand() & 1)) {
4045c338112SArseniy Krasnov 			flags = MSG_EOR;
4055c338112SArseniy Krasnov 			curr_hash++;
4065c338112SArseniy Krasnov 		} else {
4075c338112SArseniy Krasnov 			flags = 0;
4085c338112SArseniy Krasnov 		}
4095c338112SArseniy Krasnov 
4102a8548a9SStefano Garzarella 		send_buf(fd, buf, buf_size, flags, buf_size);
4115c338112SArseniy Krasnov 
4125c338112SArseniy Krasnov 		/*
4135c338112SArseniy Krasnov 		 * Hash sum is computed at both client and server in
4145c338112SArseniy Krasnov 		 * the same way:
4155c338112SArseniy Krasnov 		 * H += hash('message data')
4165c338112SArseniy Krasnov 		 * Such hash "controls" both data integrity and message
4175c338112SArseniy Krasnov 		 * bounds. After data exchange, both sums are compared
4185c338112SArseniy Krasnov 		 * using control socket, and if message bounds wasn't
4195c338112SArseniy Krasnov 		 * broken - two values must be equal.
4205c338112SArseniy Krasnov 		 */
4215c338112SArseniy Krasnov 		curr_hash += hash_djb2(buf, buf_size);
4225c338112SArseniy Krasnov 		free(buf);
4235c338112SArseniy Krasnov 	}
42441b792d7SArseny Krasnov 
42541b792d7SArseny Krasnov 	control_writeln("SENDDONE");
4265c338112SArseniy Krasnov 	control_writeulong(curr_hash);
42741b792d7SArseny Krasnov 	close(fd);
42841b792d7SArseny Krasnov }
42941b792d7SArseny Krasnov 
test_seqpacket_msg_bounds_server(const struct test_opts * opts)43041b792d7SArseny Krasnov static void test_seqpacket_msg_bounds_server(const struct test_opts *opts)
43141b792d7SArseny Krasnov {
4325c338112SArseniy Krasnov 	unsigned long sock_buf_size;
4335c338112SArseniy Krasnov 	unsigned long remote_hash;
4345c338112SArseniy Krasnov 	unsigned long curr_hash;
43541b792d7SArseny Krasnov 	int fd;
43641b792d7SArseny Krasnov 	struct msghdr msg = {0};
43741b792d7SArseny Krasnov 	struct iovec iov = {0};
43841b792d7SArseny Krasnov 
439e18c7092SArseniy Krasnov 	fd = vsock_seqpacket_accept(VMADDR_CID_ANY, opts->peer_port, NULL);
44041b792d7SArseny Krasnov 	if (fd < 0) {
44141b792d7SArseny Krasnov 		perror("accept");
44241b792d7SArseny Krasnov 		exit(EXIT_FAILURE);
44341b792d7SArseny Krasnov 	}
44441b792d7SArseny Krasnov 
4455c338112SArseniy Krasnov 	sock_buf_size = SOCK_BUF_SIZE;
4465c338112SArseniy Krasnov 
4475c338112SArseniy Krasnov 	if (setsockopt(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_MAX_SIZE,
4485c338112SArseniy Krasnov 		       &sock_buf_size, sizeof(sock_buf_size))) {
4495c338112SArseniy Krasnov 		perror("setsockopt(SO_VM_SOCKETS_BUFFER_MAX_SIZE)");
4505c338112SArseniy Krasnov 		exit(EXIT_FAILURE);
4515c338112SArseniy Krasnov 	}
4525c338112SArseniy Krasnov 
4535c338112SArseniy Krasnov 	if (setsockopt(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_SIZE,
4545c338112SArseniy Krasnov 		       &sock_buf_size, sizeof(sock_buf_size))) {
4555c338112SArseniy Krasnov 		perror("setsockopt(SO_VM_SOCKETS_BUFFER_SIZE)");
4565c338112SArseniy Krasnov 		exit(EXIT_FAILURE);
4575c338112SArseniy Krasnov 	}
4585c338112SArseniy Krasnov 
4595c338112SArseniy Krasnov 	/* Ready to receive data. */
4605c338112SArseniy Krasnov 	control_writeln("SRVREADY");
4615c338112SArseniy Krasnov 	/* Wait, until peer sends whole data. */
46241b792d7SArseny Krasnov 	control_expectln("SENDDONE");
463f0863888SArseniy Krasnov 	iov.iov_len = MAX_MSG_PAGES * getpagesize();
464f0863888SArseniy Krasnov 	iov.iov_base = malloc(iov.iov_len);
465f0863888SArseniy Krasnov 	if (!iov.iov_base) {
466f0863888SArseniy Krasnov 		perror("malloc");
467f0863888SArseniy Krasnov 		exit(EXIT_FAILURE);
468f0863888SArseniy Krasnov 	}
469f0863888SArseniy Krasnov 
47041b792d7SArseny Krasnov 	msg.msg_iov = &iov;
47141b792d7SArseny Krasnov 	msg.msg_iovlen = 1;
47241b792d7SArseny Krasnov 
4735c338112SArseniy Krasnov 	curr_hash = 0;
4745c338112SArseniy Krasnov 
4755c338112SArseniy Krasnov 	while (1) {
4765c338112SArseniy Krasnov 		ssize_t recv_size;
4775c338112SArseniy Krasnov 
4785c338112SArseniy Krasnov 		recv_size = recvmsg(fd, &msg, 0);
4795c338112SArseniy Krasnov 
4805c338112SArseniy Krasnov 		if (!recv_size)
4815c338112SArseniy Krasnov 			break;
4825c338112SArseniy Krasnov 
4835c338112SArseniy Krasnov 		if (recv_size < 0) {
4845c338112SArseniy Krasnov 			perror("recvmsg");
48541b792d7SArseny Krasnov 			exit(EXIT_FAILURE);
48641b792d7SArseny Krasnov 		}
4870e115c45SArseny Krasnov 
4885c338112SArseniy Krasnov 		if (msg.msg_flags & MSG_EOR)
4895c338112SArseniy Krasnov 			curr_hash++;
4905c338112SArseniy Krasnov 
4915c338112SArseniy Krasnov 		curr_hash += hash_djb2(msg.msg_iov[0].iov_base, recv_size);
49241b792d7SArseny Krasnov 	}
49341b792d7SArseny Krasnov 
494f0863888SArseniy Krasnov 	free(iov.iov_base);
49541b792d7SArseny Krasnov 	close(fd);
4965c338112SArseniy Krasnov 	remote_hash = control_readulong();
4975c338112SArseniy Krasnov 
4985c338112SArseniy Krasnov 	if (curr_hash != remote_hash) {
4995c338112SArseniy Krasnov 		fprintf(stderr, "Message bounds broken\n");
5005c338112SArseniy Krasnov 		exit(EXIT_FAILURE);
5015c338112SArseniy Krasnov 	}
50241b792d7SArseny Krasnov }
50341b792d7SArseny Krasnov 
50441b792d7SArseny Krasnov #define MESSAGE_TRUNC_SZ 32
test_seqpacket_msg_trunc_client(const struct test_opts * opts)50541b792d7SArseny Krasnov static void test_seqpacket_msg_trunc_client(const struct test_opts *opts)
50641b792d7SArseny Krasnov {
50741b792d7SArseny Krasnov 	int fd;
50841b792d7SArseny Krasnov 	char buf[MESSAGE_TRUNC_SZ];
50941b792d7SArseny Krasnov 
510e18c7092SArseniy Krasnov 	fd = vsock_seqpacket_connect(opts->peer_cid, opts->peer_port);
51141b792d7SArseny Krasnov 	if (fd < 0) {
51241b792d7SArseny Krasnov 		perror("connect");
51341b792d7SArseny Krasnov 		exit(EXIT_FAILURE);
51441b792d7SArseny Krasnov 	}
51541b792d7SArseny Krasnov 
5162a8548a9SStefano Garzarella 	send_buf(fd, buf, sizeof(buf), 0, sizeof(buf));
51741b792d7SArseny Krasnov 
51841b792d7SArseny Krasnov 	control_writeln("SENDDONE");
51941b792d7SArseny Krasnov 	close(fd);
52041b792d7SArseny Krasnov }
52141b792d7SArseny Krasnov 
test_seqpacket_msg_trunc_server(const struct test_opts * opts)52241b792d7SArseny Krasnov static void test_seqpacket_msg_trunc_server(const struct test_opts *opts)
52341b792d7SArseny Krasnov {
52441b792d7SArseny Krasnov 	int fd;
52541b792d7SArseny Krasnov 	char buf[MESSAGE_TRUNC_SZ / 2];
52641b792d7SArseny Krasnov 	struct msghdr msg = {0};
52741b792d7SArseny Krasnov 	struct iovec iov = {0};
52841b792d7SArseny Krasnov 
529e18c7092SArseniy Krasnov 	fd = vsock_seqpacket_accept(VMADDR_CID_ANY, opts->peer_port, NULL);
53041b792d7SArseny Krasnov 	if (fd < 0) {
53141b792d7SArseny Krasnov 		perror("accept");
53241b792d7SArseny Krasnov 		exit(EXIT_FAILURE);
53341b792d7SArseny Krasnov 	}
53441b792d7SArseny Krasnov 
53541b792d7SArseny Krasnov 	control_expectln("SENDDONE");
53641b792d7SArseny Krasnov 	iov.iov_base = buf;
53741b792d7SArseny Krasnov 	iov.iov_len = sizeof(buf);
53841b792d7SArseny Krasnov 	msg.msg_iov = &iov;
53941b792d7SArseny Krasnov 	msg.msg_iovlen = 1;
54041b792d7SArseny Krasnov 
54141b792d7SArseny Krasnov 	ssize_t ret = recvmsg(fd, &msg, MSG_TRUNC);
54241b792d7SArseny Krasnov 
54341b792d7SArseny Krasnov 	if (ret != MESSAGE_TRUNC_SZ) {
54441b792d7SArseny Krasnov 		printf("%zi\n", ret);
54541b792d7SArseny Krasnov 		perror("MSG_TRUNC doesn't work");
54641b792d7SArseny Krasnov 		exit(EXIT_FAILURE);
54741b792d7SArseny Krasnov 	}
54841b792d7SArseny Krasnov 
54941b792d7SArseny Krasnov 	if (!(msg.msg_flags & MSG_TRUNC)) {
55041b792d7SArseny Krasnov 		fprintf(stderr, "MSG_TRUNC expected\n");
55141b792d7SArseny Krasnov 		exit(EXIT_FAILURE);
55241b792d7SArseny Krasnov 	}
55341b792d7SArseny Krasnov 
55441b792d7SArseny Krasnov 	close(fd);
55541b792d7SArseny Krasnov }
55641b792d7SArseny Krasnov 
current_nsec(void)557efb3719fSKrasnov Arseniy Vladimirovich static time_t current_nsec(void)
558efb3719fSKrasnov Arseniy Vladimirovich {
559efb3719fSKrasnov Arseniy Vladimirovich 	struct timespec ts;
560efb3719fSKrasnov Arseniy Vladimirovich 
561efb3719fSKrasnov Arseniy Vladimirovich 	if (clock_gettime(CLOCK_REALTIME, &ts)) {
562efb3719fSKrasnov Arseniy Vladimirovich 		perror("clock_gettime(3) failed");
563efb3719fSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
564efb3719fSKrasnov Arseniy Vladimirovich 	}
565efb3719fSKrasnov Arseniy Vladimirovich 
566efb3719fSKrasnov Arseniy Vladimirovich 	return (ts.tv_sec * 1000000000ULL) + ts.tv_nsec;
567efb3719fSKrasnov Arseniy Vladimirovich }
568efb3719fSKrasnov Arseniy Vladimirovich 
569efb3719fSKrasnov Arseniy Vladimirovich #define RCVTIMEO_TIMEOUT_SEC 1
570efb3719fSKrasnov Arseniy Vladimirovich #define READ_OVERHEAD_NSEC 250000000 /* 0.25 sec */
571efb3719fSKrasnov Arseniy Vladimirovich 
test_seqpacket_timeout_client(const struct test_opts * opts)572efb3719fSKrasnov Arseniy Vladimirovich static void test_seqpacket_timeout_client(const struct test_opts *opts)
573efb3719fSKrasnov Arseniy Vladimirovich {
574efb3719fSKrasnov Arseniy Vladimirovich 	int fd;
575efb3719fSKrasnov Arseniy Vladimirovich 	struct timeval tv;
576efb3719fSKrasnov Arseniy Vladimirovich 	char dummy;
577efb3719fSKrasnov Arseniy Vladimirovich 	time_t read_enter_ns;
578efb3719fSKrasnov Arseniy Vladimirovich 	time_t read_overhead_ns;
579efb3719fSKrasnov Arseniy Vladimirovich 
580e18c7092SArseniy Krasnov 	fd = vsock_seqpacket_connect(opts->peer_cid, opts->peer_port);
581efb3719fSKrasnov Arseniy Vladimirovich 	if (fd < 0) {
582efb3719fSKrasnov Arseniy Vladimirovich 		perror("connect");
583efb3719fSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
584efb3719fSKrasnov Arseniy Vladimirovich 	}
585efb3719fSKrasnov Arseniy Vladimirovich 
586efb3719fSKrasnov Arseniy Vladimirovich 	tv.tv_sec = RCVTIMEO_TIMEOUT_SEC;
587efb3719fSKrasnov Arseniy Vladimirovich 	tv.tv_usec = 0;
588efb3719fSKrasnov Arseniy Vladimirovich 
589efb3719fSKrasnov Arseniy Vladimirovich 	if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (void *)&tv, sizeof(tv)) == -1) {
5905c338112SArseniy Krasnov 		perror("setsockopt(SO_RCVTIMEO)");
591efb3719fSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
592efb3719fSKrasnov Arseniy Vladimirovich 	}
593efb3719fSKrasnov Arseniy Vladimirovich 
594efb3719fSKrasnov Arseniy Vladimirovich 	read_enter_ns = current_nsec();
595efb3719fSKrasnov Arseniy Vladimirovich 
596efb3719fSKrasnov Arseniy Vladimirovich 	if (read(fd, &dummy, sizeof(dummy)) != -1) {
597efb3719fSKrasnov Arseniy Vladimirovich 		fprintf(stderr,
598efb3719fSKrasnov Arseniy Vladimirovich 			"expected 'dummy' read(2) failure\n");
599efb3719fSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
600efb3719fSKrasnov Arseniy Vladimirovich 	}
601efb3719fSKrasnov Arseniy Vladimirovich 
602efb3719fSKrasnov Arseniy Vladimirovich 	if (errno != EAGAIN) {
603efb3719fSKrasnov Arseniy Vladimirovich 		perror("EAGAIN expected");
604efb3719fSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
605efb3719fSKrasnov Arseniy Vladimirovich 	}
606efb3719fSKrasnov Arseniy Vladimirovich 
607efb3719fSKrasnov Arseniy Vladimirovich 	read_overhead_ns = current_nsec() - read_enter_ns -
608efb3719fSKrasnov Arseniy Vladimirovich 			1000000000ULL * RCVTIMEO_TIMEOUT_SEC;
609efb3719fSKrasnov Arseniy Vladimirovich 
610efb3719fSKrasnov Arseniy Vladimirovich 	if (read_overhead_ns > READ_OVERHEAD_NSEC) {
611efb3719fSKrasnov Arseniy Vladimirovich 		fprintf(stderr,
612efb3719fSKrasnov Arseniy Vladimirovich 			"too much time in read(2), %lu > %i ns\n",
613efb3719fSKrasnov Arseniy Vladimirovich 			read_overhead_ns, READ_OVERHEAD_NSEC);
614efb3719fSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
615efb3719fSKrasnov Arseniy Vladimirovich 	}
616efb3719fSKrasnov Arseniy Vladimirovich 
617efb3719fSKrasnov Arseniy Vladimirovich 	control_writeln("WAITDONE");
618efb3719fSKrasnov Arseniy Vladimirovich 	close(fd);
619efb3719fSKrasnov Arseniy Vladimirovich }
620efb3719fSKrasnov Arseniy Vladimirovich 
test_seqpacket_timeout_server(const struct test_opts * opts)621efb3719fSKrasnov Arseniy Vladimirovich static void test_seqpacket_timeout_server(const struct test_opts *opts)
622efb3719fSKrasnov Arseniy Vladimirovich {
623efb3719fSKrasnov Arseniy Vladimirovich 	int fd;
624efb3719fSKrasnov Arseniy Vladimirovich 
625e18c7092SArseniy Krasnov 	fd = vsock_seqpacket_accept(VMADDR_CID_ANY, opts->peer_port, NULL);
626efb3719fSKrasnov Arseniy Vladimirovich 	if (fd < 0) {
627efb3719fSKrasnov Arseniy Vladimirovich 		perror("accept");
628efb3719fSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
629efb3719fSKrasnov Arseniy Vladimirovich 	}
630efb3719fSKrasnov Arseniy Vladimirovich 
631efb3719fSKrasnov Arseniy Vladimirovich 	control_expectln("WAITDONE");
632efb3719fSKrasnov Arseniy Vladimirovich 	close(fd);
633efb3719fSKrasnov Arseniy Vladimirovich }
634efb3719fSKrasnov Arseniy Vladimirovich 
test_seqpacket_bigmsg_client(const struct test_opts * opts)635685a21c3SArseniy Krasnov static void test_seqpacket_bigmsg_client(const struct test_opts *opts)
636685a21c3SArseniy Krasnov {
637685a21c3SArseniy Krasnov 	unsigned long sock_buf_size;
638685a21c3SArseniy Krasnov 	socklen_t len;
639685a21c3SArseniy Krasnov 	void *data;
640685a21c3SArseniy Krasnov 	int fd;
641685a21c3SArseniy Krasnov 
642685a21c3SArseniy Krasnov 	len = sizeof(sock_buf_size);
643685a21c3SArseniy Krasnov 
644e18c7092SArseniy Krasnov 	fd = vsock_seqpacket_connect(opts->peer_cid, opts->peer_port);
645685a21c3SArseniy Krasnov 	if (fd < 0) {
646685a21c3SArseniy Krasnov 		perror("connect");
647685a21c3SArseniy Krasnov 		exit(EXIT_FAILURE);
648685a21c3SArseniy Krasnov 	}
649685a21c3SArseniy Krasnov 
650685a21c3SArseniy Krasnov 	if (getsockopt(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_SIZE,
651685a21c3SArseniy Krasnov 		       &sock_buf_size, &len)) {
652685a21c3SArseniy Krasnov 		perror("getsockopt");
653685a21c3SArseniy Krasnov 		exit(EXIT_FAILURE);
654685a21c3SArseniy Krasnov 	}
655685a21c3SArseniy Krasnov 
656685a21c3SArseniy Krasnov 	sock_buf_size++;
657685a21c3SArseniy Krasnov 
658685a21c3SArseniy Krasnov 	data = malloc(sock_buf_size);
659685a21c3SArseniy Krasnov 	if (!data) {
660685a21c3SArseniy Krasnov 		perror("malloc");
661685a21c3SArseniy Krasnov 		exit(EXIT_FAILURE);
662685a21c3SArseniy Krasnov 	}
663685a21c3SArseniy Krasnov 
6642a8548a9SStefano Garzarella 	send_buf(fd, data, sock_buf_size, 0, -EMSGSIZE);
665685a21c3SArseniy Krasnov 
666685a21c3SArseniy Krasnov 	control_writeln("CLISENT");
667685a21c3SArseniy Krasnov 
668685a21c3SArseniy Krasnov 	free(data);
669685a21c3SArseniy Krasnov 	close(fd);
670685a21c3SArseniy Krasnov }
671685a21c3SArseniy Krasnov 
test_seqpacket_bigmsg_server(const struct test_opts * opts)672685a21c3SArseniy Krasnov static void test_seqpacket_bigmsg_server(const struct test_opts *opts)
673685a21c3SArseniy Krasnov {
674685a21c3SArseniy Krasnov 	int fd;
675685a21c3SArseniy Krasnov 
676e18c7092SArseniy Krasnov 	fd = vsock_seqpacket_accept(VMADDR_CID_ANY, opts->peer_port, NULL);
677685a21c3SArseniy Krasnov 	if (fd < 0) {
678685a21c3SArseniy Krasnov 		perror("accept");
679685a21c3SArseniy Krasnov 		exit(EXIT_FAILURE);
680685a21c3SArseniy Krasnov 	}
681685a21c3SArseniy Krasnov 
682685a21c3SArseniy Krasnov 	control_expectln("CLISENT");
683685a21c3SArseniy Krasnov 
684685a21c3SArseniy Krasnov 	close(fd);
685685a21c3SArseniy Krasnov }
686685a21c3SArseniy Krasnov 
687e89600ebSKrasnov Arseniy Vladimirovich #define BUF_PATTERN_1 'a'
688e89600ebSKrasnov Arseniy Vladimirovich #define BUF_PATTERN_2 'b'
689e89600ebSKrasnov Arseniy Vladimirovich 
test_seqpacket_invalid_rec_buffer_client(const struct test_opts * opts)690e89600ebSKrasnov Arseniy Vladimirovich static void test_seqpacket_invalid_rec_buffer_client(const struct test_opts *opts)
691e89600ebSKrasnov Arseniy Vladimirovich {
692e89600ebSKrasnov Arseniy Vladimirovich 	int fd;
693e89600ebSKrasnov Arseniy Vladimirovich 	unsigned char *buf1;
694e89600ebSKrasnov Arseniy Vladimirovich 	unsigned char *buf2;
695e89600ebSKrasnov Arseniy Vladimirovich 	int buf_size = getpagesize() * 3;
696e89600ebSKrasnov Arseniy Vladimirovich 
697e18c7092SArseniy Krasnov 	fd = vsock_seqpacket_connect(opts->peer_cid, opts->peer_port);
698e89600ebSKrasnov Arseniy Vladimirovich 	if (fd < 0) {
699e89600ebSKrasnov Arseniy Vladimirovich 		perror("connect");
700e89600ebSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
701e89600ebSKrasnov Arseniy Vladimirovich 	}
702e89600ebSKrasnov Arseniy Vladimirovich 
703e89600ebSKrasnov Arseniy Vladimirovich 	buf1 = malloc(buf_size);
704e89600ebSKrasnov Arseniy Vladimirovich 	if (!buf1) {
705e89600ebSKrasnov Arseniy Vladimirovich 		perror("'malloc()' for 'buf1'");
706e89600ebSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
707e89600ebSKrasnov Arseniy Vladimirovich 	}
708e89600ebSKrasnov Arseniy Vladimirovich 
709e89600ebSKrasnov Arseniy Vladimirovich 	buf2 = malloc(buf_size);
710e89600ebSKrasnov Arseniy Vladimirovich 	if (!buf2) {
711e89600ebSKrasnov Arseniy Vladimirovich 		perror("'malloc()' for 'buf2'");
712e89600ebSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
713e89600ebSKrasnov Arseniy Vladimirovich 	}
714e89600ebSKrasnov Arseniy Vladimirovich 
715e89600ebSKrasnov Arseniy Vladimirovich 	memset(buf1, BUF_PATTERN_1, buf_size);
716e89600ebSKrasnov Arseniy Vladimirovich 	memset(buf2, BUF_PATTERN_2, buf_size);
717e89600ebSKrasnov Arseniy Vladimirovich 
7182a8548a9SStefano Garzarella 	send_buf(fd, buf1, buf_size, 0, buf_size);
719e89600ebSKrasnov Arseniy Vladimirovich 
7202a8548a9SStefano Garzarella 	send_buf(fd, buf2, buf_size, 0, buf_size);
721e89600ebSKrasnov Arseniy Vladimirovich 
722e89600ebSKrasnov Arseniy Vladimirovich 	close(fd);
723e89600ebSKrasnov Arseniy Vladimirovich }
724e89600ebSKrasnov Arseniy Vladimirovich 
test_seqpacket_invalid_rec_buffer_server(const struct test_opts * opts)725e89600ebSKrasnov Arseniy Vladimirovich static void test_seqpacket_invalid_rec_buffer_server(const struct test_opts *opts)
726e89600ebSKrasnov Arseniy Vladimirovich {
727e89600ebSKrasnov Arseniy Vladimirovich 	int fd;
728e89600ebSKrasnov Arseniy Vladimirovich 	unsigned char *broken_buf;
729e89600ebSKrasnov Arseniy Vladimirovich 	unsigned char *valid_buf;
730e89600ebSKrasnov Arseniy Vladimirovich 	int page_size = getpagesize();
731e89600ebSKrasnov Arseniy Vladimirovich 	int buf_size = page_size * 3;
732e89600ebSKrasnov Arseniy Vladimirovich 	ssize_t res;
733e89600ebSKrasnov Arseniy Vladimirovich 	int prot = PROT_READ | PROT_WRITE;
734e89600ebSKrasnov Arseniy Vladimirovich 	int flags = MAP_PRIVATE | MAP_ANONYMOUS;
735e89600ebSKrasnov Arseniy Vladimirovich 	int i;
736e89600ebSKrasnov Arseniy Vladimirovich 
737e18c7092SArseniy Krasnov 	fd = vsock_seqpacket_accept(VMADDR_CID_ANY, opts->peer_port, NULL);
738e89600ebSKrasnov Arseniy Vladimirovich 	if (fd < 0) {
739e89600ebSKrasnov Arseniy Vladimirovich 		perror("accept");
740e89600ebSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
741e89600ebSKrasnov Arseniy Vladimirovich 	}
742e89600ebSKrasnov Arseniy Vladimirovich 
743e89600ebSKrasnov Arseniy Vladimirovich 	/* Setup first buffer. */
744e89600ebSKrasnov Arseniy Vladimirovich 	broken_buf = mmap(NULL, buf_size, prot, flags, -1, 0);
745e89600ebSKrasnov Arseniy Vladimirovich 	if (broken_buf == MAP_FAILED) {
746e89600ebSKrasnov Arseniy Vladimirovich 		perror("mmap for 'broken_buf'");
747e89600ebSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
748e89600ebSKrasnov Arseniy Vladimirovich 	}
749e89600ebSKrasnov Arseniy Vladimirovich 
750e89600ebSKrasnov Arseniy Vladimirovich 	/* Unmap "hole" in buffer. */
751e89600ebSKrasnov Arseniy Vladimirovich 	if (munmap(broken_buf + page_size, page_size)) {
752e89600ebSKrasnov Arseniy Vladimirovich 		perror("'broken_buf' setup");
753e89600ebSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
754e89600ebSKrasnov Arseniy Vladimirovich 	}
755e89600ebSKrasnov Arseniy Vladimirovich 
756e89600ebSKrasnov Arseniy Vladimirovich 	valid_buf = mmap(NULL, buf_size, prot, flags, -1, 0);
757e89600ebSKrasnov Arseniy Vladimirovich 	if (valid_buf == MAP_FAILED) {
758e89600ebSKrasnov Arseniy Vladimirovich 		perror("mmap for 'valid_buf'");
759e89600ebSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
760e89600ebSKrasnov Arseniy Vladimirovich 	}
761e89600ebSKrasnov Arseniy Vladimirovich 
762e89600ebSKrasnov Arseniy Vladimirovich 	/* Try to fill buffer with unmapped middle. */
763e89600ebSKrasnov Arseniy Vladimirovich 	res = read(fd, broken_buf, buf_size);
764e89600ebSKrasnov Arseniy Vladimirovich 	if (res != -1) {
765e89600ebSKrasnov Arseniy Vladimirovich 		fprintf(stderr,
766e89600ebSKrasnov Arseniy Vladimirovich 			"expected 'broken_buf' read(2) failure, got %zi\n",
767e89600ebSKrasnov Arseniy Vladimirovich 			res);
768e89600ebSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
769e89600ebSKrasnov Arseniy Vladimirovich 	}
770e89600ebSKrasnov Arseniy Vladimirovich 
771b5d54eb5SArseniy Krasnov 	if (errno != EFAULT) {
772e89600ebSKrasnov Arseniy Vladimirovich 		perror("unexpected errno of 'broken_buf'");
773e89600ebSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
774e89600ebSKrasnov Arseniy Vladimirovich 	}
775e89600ebSKrasnov Arseniy Vladimirovich 
776e89600ebSKrasnov Arseniy Vladimirovich 	/* Try to fill valid buffer. */
777e89600ebSKrasnov Arseniy Vladimirovich 	res = read(fd, valid_buf, buf_size);
778e89600ebSKrasnov Arseniy Vladimirovich 	if (res < 0) {
779e89600ebSKrasnov Arseniy Vladimirovich 		perror("unexpected 'valid_buf' read(2) failure");
780e89600ebSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
781e89600ebSKrasnov Arseniy Vladimirovich 	}
782e89600ebSKrasnov Arseniy Vladimirovich 
783e89600ebSKrasnov Arseniy Vladimirovich 	if (res != buf_size) {
784e89600ebSKrasnov Arseniy Vladimirovich 		fprintf(stderr,
785e89600ebSKrasnov Arseniy Vladimirovich 			"invalid 'valid_buf' read(2), expected %i, got %zi\n",
786e89600ebSKrasnov Arseniy Vladimirovich 			buf_size, res);
787e89600ebSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
788e89600ebSKrasnov Arseniy Vladimirovich 	}
789e89600ebSKrasnov Arseniy Vladimirovich 
790e89600ebSKrasnov Arseniy Vladimirovich 	for (i = 0; i < buf_size; i++) {
791e89600ebSKrasnov Arseniy Vladimirovich 		if (valid_buf[i] != BUF_PATTERN_2) {
792e89600ebSKrasnov Arseniy Vladimirovich 			fprintf(stderr,
793e89600ebSKrasnov Arseniy Vladimirovich 				"invalid pattern for 'valid_buf' at %i, expected %hhX, got %hhX\n",
794e89600ebSKrasnov Arseniy Vladimirovich 				i, BUF_PATTERN_2, valid_buf[i]);
795e89600ebSKrasnov Arseniy Vladimirovich 			exit(EXIT_FAILURE);
796e89600ebSKrasnov Arseniy Vladimirovich 		}
797e89600ebSKrasnov Arseniy Vladimirovich 	}
798e89600ebSKrasnov Arseniy Vladimirovich 
799e89600ebSKrasnov Arseniy Vladimirovich 	/* Unmap buffers. */
800e89600ebSKrasnov Arseniy Vladimirovich 	munmap(broken_buf, page_size);
801e89600ebSKrasnov Arseniy Vladimirovich 	munmap(broken_buf + page_size * 2, page_size);
802e89600ebSKrasnov Arseniy Vladimirovich 	munmap(valid_buf, buf_size);
803e89600ebSKrasnov Arseniy Vladimirovich 	close(fd);
804e89600ebSKrasnov Arseniy Vladimirovich }
805e89600ebSKrasnov Arseniy Vladimirovich 
806b1346338SArseniy Krasnov #define RCVLOWAT_BUF_SIZE 128
807b1346338SArseniy Krasnov 
test_stream_poll_rcvlowat_server(const struct test_opts * opts)808b1346338SArseniy Krasnov static void test_stream_poll_rcvlowat_server(const struct test_opts *opts)
809b1346338SArseniy Krasnov {
810b1346338SArseniy Krasnov 	int fd;
811b1346338SArseniy Krasnov 	int i;
812b1346338SArseniy Krasnov 
813e18c7092SArseniy Krasnov 	fd = vsock_stream_accept(VMADDR_CID_ANY, opts->peer_port, NULL);
814b1346338SArseniy Krasnov 	if (fd < 0) {
815b1346338SArseniy Krasnov 		perror("accept");
816b1346338SArseniy Krasnov 		exit(EXIT_FAILURE);
817b1346338SArseniy Krasnov 	}
818b1346338SArseniy Krasnov 
819b1346338SArseniy Krasnov 	/* Send 1 byte. */
820b1346338SArseniy Krasnov 	send_byte(fd, 1, 0);
821b1346338SArseniy Krasnov 
822b1346338SArseniy Krasnov 	control_writeln("SRVSENT");
823b1346338SArseniy Krasnov 
824b1346338SArseniy Krasnov 	/* Wait until client is ready to receive rest of data. */
825b1346338SArseniy Krasnov 	control_expectln("CLNSENT");
826b1346338SArseniy Krasnov 
827b1346338SArseniy Krasnov 	for (i = 0; i < RCVLOWAT_BUF_SIZE - 1; i++)
828b1346338SArseniy Krasnov 		send_byte(fd, 1, 0);
829b1346338SArseniy Krasnov 
830b1346338SArseniy Krasnov 	/* Keep socket in active state. */
831b1346338SArseniy Krasnov 	control_expectln("POLLDONE");
832b1346338SArseniy Krasnov 
833b1346338SArseniy Krasnov 	close(fd);
834b1346338SArseniy Krasnov }
835b1346338SArseniy Krasnov 
test_stream_poll_rcvlowat_client(const struct test_opts * opts)836b1346338SArseniy Krasnov static void test_stream_poll_rcvlowat_client(const struct test_opts *opts)
837b1346338SArseniy Krasnov {
838b1346338SArseniy Krasnov 	unsigned long lowat_val = RCVLOWAT_BUF_SIZE;
839b1346338SArseniy Krasnov 	char buf[RCVLOWAT_BUF_SIZE];
840b1346338SArseniy Krasnov 	struct pollfd fds;
841b1346338SArseniy Krasnov 	short poll_flags;
842b1346338SArseniy Krasnov 	int fd;
843b1346338SArseniy Krasnov 
844e18c7092SArseniy Krasnov 	fd = vsock_stream_connect(opts->peer_cid, opts->peer_port);
845b1346338SArseniy Krasnov 	if (fd < 0) {
846b1346338SArseniy Krasnov 		perror("connect");
847b1346338SArseniy Krasnov 		exit(EXIT_FAILURE);
848b1346338SArseniy Krasnov 	}
849b1346338SArseniy Krasnov 
850b1346338SArseniy Krasnov 	if (setsockopt(fd, SOL_SOCKET, SO_RCVLOWAT,
851b1346338SArseniy Krasnov 		       &lowat_val, sizeof(lowat_val))) {
8525c338112SArseniy Krasnov 		perror("setsockopt(SO_RCVLOWAT)");
853b1346338SArseniy Krasnov 		exit(EXIT_FAILURE);
854b1346338SArseniy Krasnov 	}
855b1346338SArseniy Krasnov 
856b1346338SArseniy Krasnov 	control_expectln("SRVSENT");
857b1346338SArseniy Krasnov 
858b1346338SArseniy Krasnov 	/* At this point, server sent 1 byte. */
859b1346338SArseniy Krasnov 	fds.fd = fd;
860b1346338SArseniy Krasnov 	poll_flags = POLLIN | POLLRDNORM;
861b1346338SArseniy Krasnov 	fds.events = poll_flags;
862b1346338SArseniy Krasnov 
863b1346338SArseniy Krasnov 	/* Try to wait for 1 sec. */
864b1346338SArseniy Krasnov 	if (poll(&fds, 1, 1000) < 0) {
865b1346338SArseniy Krasnov 		perror("poll");
866b1346338SArseniy Krasnov 		exit(EXIT_FAILURE);
867b1346338SArseniy Krasnov 	}
868b1346338SArseniy Krasnov 
869b1346338SArseniy Krasnov 	/* poll() must return nothing. */
870b1346338SArseniy Krasnov 	if (fds.revents) {
871b1346338SArseniy Krasnov 		fprintf(stderr, "Unexpected poll result %hx\n",
872b1346338SArseniy Krasnov 			fds.revents);
873b1346338SArseniy Krasnov 		exit(EXIT_FAILURE);
874b1346338SArseniy Krasnov 	}
875b1346338SArseniy Krasnov 
876b1346338SArseniy Krasnov 	/* Tell server to send rest of data. */
877b1346338SArseniy Krasnov 	control_writeln("CLNSENT");
878b1346338SArseniy Krasnov 
879b1346338SArseniy Krasnov 	/* Poll for data. */
880b1346338SArseniy Krasnov 	if (poll(&fds, 1, 10000) < 0) {
881b1346338SArseniy Krasnov 		perror("poll");
882b1346338SArseniy Krasnov 		exit(EXIT_FAILURE);
883b1346338SArseniy Krasnov 	}
884b1346338SArseniy Krasnov 
885b1346338SArseniy Krasnov 	/* Only these two bits are expected. */
886b1346338SArseniy Krasnov 	if (fds.revents != poll_flags) {
887b1346338SArseniy Krasnov 		fprintf(stderr, "Unexpected poll result %hx\n",
888b1346338SArseniy Krasnov 			fds.revents);
889b1346338SArseniy Krasnov 		exit(EXIT_FAILURE);
890b1346338SArseniy Krasnov 	}
891b1346338SArseniy Krasnov 
892b1346338SArseniy Krasnov 	/* Use MSG_DONTWAIT, if call is going to wait, EAGAIN
893b1346338SArseniy Krasnov 	 * will be returned.
894b1346338SArseniy Krasnov 	 */
895a0bcb835SStefano Garzarella 	recv_buf(fd, buf, sizeof(buf), MSG_DONTWAIT, RCVLOWAT_BUF_SIZE);
896b1346338SArseniy Krasnov 
897b1346338SArseniy Krasnov 	control_writeln("POLLDONE");
898b1346338SArseniy Krasnov 
899b1346338SArseniy Krasnov 	close(fd);
900b1346338SArseniy Krasnov }
901b1346338SArseniy Krasnov 
9027e699d2aSArseniy Krasnov #define INV_BUF_TEST_DATA_LEN 512
9037e699d2aSArseniy Krasnov 
test_inv_buf_client(const struct test_opts * opts,bool stream)9047e699d2aSArseniy Krasnov static void test_inv_buf_client(const struct test_opts *opts, bool stream)
9057e699d2aSArseniy Krasnov {
9067e699d2aSArseniy Krasnov 	unsigned char data[INV_BUF_TEST_DATA_LEN] = {0};
907a0bcb835SStefano Garzarella 	ssize_t expected_ret;
9087e699d2aSArseniy Krasnov 	int fd;
9097e699d2aSArseniy Krasnov 
9107e699d2aSArseniy Krasnov 	if (stream)
911e18c7092SArseniy Krasnov 		fd = vsock_stream_connect(opts->peer_cid, opts->peer_port);
9127e699d2aSArseniy Krasnov 	else
913e18c7092SArseniy Krasnov 		fd = vsock_seqpacket_connect(opts->peer_cid, opts->peer_port);
9147e699d2aSArseniy Krasnov 
9157e699d2aSArseniy Krasnov 	if (fd < 0) {
9167e699d2aSArseniy Krasnov 		perror("connect");
9177e699d2aSArseniy Krasnov 		exit(EXIT_FAILURE);
9187e699d2aSArseniy Krasnov 	}
9197e699d2aSArseniy Krasnov 
9207e699d2aSArseniy Krasnov 	control_expectln("SENDDONE");
9217e699d2aSArseniy Krasnov 
9227e699d2aSArseniy Krasnov 	/* Use invalid buffer here. */
923a0bcb835SStefano Garzarella 	recv_buf(fd, NULL, sizeof(data), 0, -EFAULT);
9247e699d2aSArseniy Krasnov 
9257e699d2aSArseniy Krasnov 	if (stream) {
9267e699d2aSArseniy Krasnov 		/* For SOCK_STREAM we must continue reading. */
927a0bcb835SStefano Garzarella 		expected_ret = sizeof(data);
9287e699d2aSArseniy Krasnov 	} else {
9297e699d2aSArseniy Krasnov 		/* For SOCK_SEQPACKET socket's queue must be empty. */
930a0bcb835SStefano Garzarella 		expected_ret = -EAGAIN;
9317e699d2aSArseniy Krasnov 	}
9327e699d2aSArseniy Krasnov 
933a0bcb835SStefano Garzarella 	recv_buf(fd, data, sizeof(data), MSG_DONTWAIT, expected_ret);
9347e699d2aSArseniy Krasnov 
9357e699d2aSArseniy Krasnov 	control_writeln("DONE");
9367e699d2aSArseniy Krasnov 
9377e699d2aSArseniy Krasnov 	close(fd);
9387e699d2aSArseniy Krasnov }
9397e699d2aSArseniy Krasnov 
test_inv_buf_server(const struct test_opts * opts,bool stream)9407e699d2aSArseniy Krasnov static void test_inv_buf_server(const struct test_opts *opts, bool stream)
9417e699d2aSArseniy Krasnov {
9427e699d2aSArseniy Krasnov 	unsigned char data[INV_BUF_TEST_DATA_LEN] = {0};
9437e699d2aSArseniy Krasnov 	int fd;
9447e699d2aSArseniy Krasnov 
9457e699d2aSArseniy Krasnov 	if (stream)
946e18c7092SArseniy Krasnov 		fd = vsock_stream_accept(VMADDR_CID_ANY, opts->peer_port, NULL);
9477e699d2aSArseniy Krasnov 	else
948e18c7092SArseniy Krasnov 		fd = vsock_seqpacket_accept(VMADDR_CID_ANY, opts->peer_port, NULL);
9497e699d2aSArseniy Krasnov 
9507e699d2aSArseniy Krasnov 	if (fd < 0) {
9517e699d2aSArseniy Krasnov 		perror("accept");
9527e699d2aSArseniy Krasnov 		exit(EXIT_FAILURE);
9537e699d2aSArseniy Krasnov 	}
9547e699d2aSArseniy Krasnov 
9552a8548a9SStefano Garzarella 	send_buf(fd, data, sizeof(data), 0, sizeof(data));
9567e699d2aSArseniy Krasnov 
9577e699d2aSArseniy Krasnov 	control_writeln("SENDDONE");
9587e699d2aSArseniy Krasnov 
9597e699d2aSArseniy Krasnov 	control_expectln("DONE");
9607e699d2aSArseniy Krasnov 
9617e699d2aSArseniy Krasnov 	close(fd);
9627e699d2aSArseniy Krasnov }
9637e699d2aSArseniy Krasnov 
test_stream_inv_buf_client(const struct test_opts * opts)9647e699d2aSArseniy Krasnov static void test_stream_inv_buf_client(const struct test_opts *opts)
9657e699d2aSArseniy Krasnov {
9667e699d2aSArseniy Krasnov 	test_inv_buf_client(opts, true);
9677e699d2aSArseniy Krasnov }
9687e699d2aSArseniy Krasnov 
test_stream_inv_buf_server(const struct test_opts * opts)9697e699d2aSArseniy Krasnov static void test_stream_inv_buf_server(const struct test_opts *opts)
9707e699d2aSArseniy Krasnov {
9717e699d2aSArseniy Krasnov 	test_inv_buf_server(opts, true);
9727e699d2aSArseniy Krasnov }
9737e699d2aSArseniy Krasnov 
test_seqpacket_inv_buf_client(const struct test_opts * opts)9747e699d2aSArseniy Krasnov static void test_seqpacket_inv_buf_client(const struct test_opts *opts)
9757e699d2aSArseniy Krasnov {
9767e699d2aSArseniy Krasnov 	test_inv_buf_client(opts, false);
9777e699d2aSArseniy Krasnov }
9787e699d2aSArseniy Krasnov 
test_seqpacket_inv_buf_server(const struct test_opts * opts)9797e699d2aSArseniy Krasnov static void test_seqpacket_inv_buf_server(const struct test_opts *opts)
9807e699d2aSArseniy Krasnov {
9817e699d2aSArseniy Krasnov 	test_inv_buf_server(opts, false);
9827e699d2aSArseniy Krasnov }
9837e699d2aSArseniy Krasnov 
98425209a32SArseniy Krasnov #define HELLO_STR "HELLO"
98525209a32SArseniy Krasnov #define WORLD_STR "WORLD"
98625209a32SArseniy Krasnov 
test_stream_virtio_skb_merge_client(const struct test_opts * opts)98725209a32SArseniy Krasnov static void test_stream_virtio_skb_merge_client(const struct test_opts *opts)
98825209a32SArseniy Krasnov {
98925209a32SArseniy Krasnov 	int fd;
99025209a32SArseniy Krasnov 
991e18c7092SArseniy Krasnov 	fd = vsock_stream_connect(opts->peer_cid, opts->peer_port);
99225209a32SArseniy Krasnov 	if (fd < 0) {
99325209a32SArseniy Krasnov 		perror("connect");
99425209a32SArseniy Krasnov 		exit(EXIT_FAILURE);
99525209a32SArseniy Krasnov 	}
99625209a32SArseniy Krasnov 
99725209a32SArseniy Krasnov 	/* Send first skbuff. */
9982a8548a9SStefano Garzarella 	send_buf(fd, HELLO_STR, strlen(HELLO_STR), 0, strlen(HELLO_STR));
99925209a32SArseniy Krasnov 
100025209a32SArseniy Krasnov 	control_writeln("SEND0");
100125209a32SArseniy Krasnov 	/* Peer reads part of first skbuff. */
100225209a32SArseniy Krasnov 	control_expectln("REPLY0");
100325209a32SArseniy Krasnov 
100425209a32SArseniy Krasnov 	/* Send second skbuff, it will be appended to the first. */
10052a8548a9SStefano Garzarella 	send_buf(fd, WORLD_STR, strlen(WORLD_STR), 0, strlen(WORLD_STR));
100625209a32SArseniy Krasnov 
100725209a32SArseniy Krasnov 	control_writeln("SEND1");
100825209a32SArseniy Krasnov 	/* Peer reads merged skbuff packet. */
100925209a32SArseniy Krasnov 	control_expectln("REPLY1");
101025209a32SArseniy Krasnov 
101125209a32SArseniy Krasnov 	close(fd);
101225209a32SArseniy Krasnov }
101325209a32SArseniy Krasnov 
test_stream_virtio_skb_merge_server(const struct test_opts * opts)101425209a32SArseniy Krasnov static void test_stream_virtio_skb_merge_server(const struct test_opts *opts)
101525209a32SArseniy Krasnov {
1016bc7bea45SStefano Garzarella 	size_t read = 0, to_read;
101725209a32SArseniy Krasnov 	unsigned char buf[64];
101825209a32SArseniy Krasnov 	int fd;
101925209a32SArseniy Krasnov 
1020e18c7092SArseniy Krasnov 	fd = vsock_stream_accept(VMADDR_CID_ANY, opts->peer_port, NULL);
102125209a32SArseniy Krasnov 	if (fd < 0) {
102225209a32SArseniy Krasnov 		perror("accept");
102325209a32SArseniy Krasnov 		exit(EXIT_FAILURE);
102425209a32SArseniy Krasnov 	}
102525209a32SArseniy Krasnov 
102625209a32SArseniy Krasnov 	control_expectln("SEND0");
102725209a32SArseniy Krasnov 
102825209a32SArseniy Krasnov 	/* Read skbuff partially. */
1029bc7bea45SStefano Garzarella 	to_read = 2;
1030bc7bea45SStefano Garzarella 	recv_buf(fd, buf + read, to_read, 0, to_read);
1031bc7bea45SStefano Garzarella 	read += to_read;
103225209a32SArseniy Krasnov 
103325209a32SArseniy Krasnov 	control_writeln("REPLY0");
103425209a32SArseniy Krasnov 	control_expectln("SEND1");
103525209a32SArseniy Krasnov 
1036bc7bea45SStefano Garzarella 	/* Read the rest of both buffers */
1037bc7bea45SStefano Garzarella 	to_read = strlen(HELLO_STR WORLD_STR) - read;
1038bc7bea45SStefano Garzarella 	recv_buf(fd, buf + read, to_read, 0, to_read);
1039bc7bea45SStefano Garzarella 	read += to_read;
104025209a32SArseniy Krasnov 
1041bc7bea45SStefano Garzarella 	/* No more bytes should be there */
1042bc7bea45SStefano Garzarella 	to_read = sizeof(buf) - read;
1043bc7bea45SStefano Garzarella 	recv_buf(fd, buf + read, to_read, MSG_DONTWAIT, -EAGAIN);
104425209a32SArseniy Krasnov 
104525209a32SArseniy Krasnov 	if (memcmp(buf, HELLO_STR WORLD_STR, strlen(HELLO_STR WORLD_STR))) {
104625209a32SArseniy Krasnov 		fprintf(stderr, "pattern mismatch\n");
104725209a32SArseniy Krasnov 		exit(EXIT_FAILURE);
104825209a32SArseniy Krasnov 	}
104925209a32SArseniy Krasnov 
105025209a32SArseniy Krasnov 	control_writeln("REPLY1");
105125209a32SArseniy Krasnov 
105225209a32SArseniy Krasnov 	close(fd);
105325209a32SArseniy Krasnov }
105425209a32SArseniy Krasnov 
test_seqpacket_msg_peek_client(const struct test_opts * opts)10558a0697f2SArseniy Krasnov static void test_seqpacket_msg_peek_client(const struct test_opts *opts)
10568a0697f2SArseniy Krasnov {
10578a0697f2SArseniy Krasnov 	return test_msg_peek_client(opts, true);
10588a0697f2SArseniy Krasnov }
10598a0697f2SArseniy Krasnov 
test_seqpacket_msg_peek_server(const struct test_opts * opts)10608a0697f2SArseniy Krasnov static void test_seqpacket_msg_peek_server(const struct test_opts *opts)
10618a0697f2SArseniy Krasnov {
10628a0697f2SArseniy Krasnov 	return test_msg_peek_server(opts, true);
10638a0697f2SArseniy Krasnov }
10648a0697f2SArseniy Krasnov 
1065b698bd97SArseniy Krasnov static sig_atomic_t have_sigpipe;
1066b698bd97SArseniy Krasnov 
sigpipe(int signo)1067b698bd97SArseniy Krasnov static void sigpipe(int signo)
1068b698bd97SArseniy Krasnov {
1069b698bd97SArseniy Krasnov 	have_sigpipe = 1;
1070b698bd97SArseniy Krasnov }
1071b698bd97SArseniy Krasnov 
test_stream_check_sigpipe(int fd)1072b698bd97SArseniy Krasnov static void test_stream_check_sigpipe(int fd)
1073b698bd97SArseniy Krasnov {
1074b698bd97SArseniy Krasnov 	ssize_t res;
1075b698bd97SArseniy Krasnov 
1076b698bd97SArseniy Krasnov 	have_sigpipe = 0;
1077b698bd97SArseniy Krasnov 
1078b698bd97SArseniy Krasnov 	res = send(fd, "A", 1, 0);
1079b698bd97SArseniy Krasnov 	if (res != -1) {
1080b698bd97SArseniy Krasnov 		fprintf(stderr, "expected send(2) failure, got %zi\n", res);
1081b698bd97SArseniy Krasnov 		exit(EXIT_FAILURE);
1082b698bd97SArseniy Krasnov 	}
1083b698bd97SArseniy Krasnov 
1084b698bd97SArseniy Krasnov 	if (!have_sigpipe) {
1085b698bd97SArseniy Krasnov 		fprintf(stderr, "SIGPIPE expected\n");
1086b698bd97SArseniy Krasnov 		exit(EXIT_FAILURE);
1087b698bd97SArseniy Krasnov 	}
1088b698bd97SArseniy Krasnov 
1089b698bd97SArseniy Krasnov 	have_sigpipe = 0;
1090b698bd97SArseniy Krasnov 
1091b698bd97SArseniy Krasnov 	res = send(fd, "A", 1, MSG_NOSIGNAL);
1092b698bd97SArseniy Krasnov 	if (res != -1) {
1093b698bd97SArseniy Krasnov 		fprintf(stderr, "expected send(2) failure, got %zi\n", res);
1094b698bd97SArseniy Krasnov 		exit(EXIT_FAILURE);
1095b698bd97SArseniy Krasnov 	}
1096b698bd97SArseniy Krasnov 
1097b698bd97SArseniy Krasnov 	if (have_sigpipe) {
1098b698bd97SArseniy Krasnov 		fprintf(stderr, "SIGPIPE not expected\n");
1099b698bd97SArseniy Krasnov 		exit(EXIT_FAILURE);
1100b698bd97SArseniy Krasnov 	}
1101b698bd97SArseniy Krasnov }
1102b698bd97SArseniy Krasnov 
test_stream_shutwr_client(const struct test_opts * opts)1103b698bd97SArseniy Krasnov static void test_stream_shutwr_client(const struct test_opts *opts)
1104b698bd97SArseniy Krasnov {
1105b698bd97SArseniy Krasnov 	int fd;
1106b698bd97SArseniy Krasnov 
1107b698bd97SArseniy Krasnov 	struct sigaction act = {
1108b698bd97SArseniy Krasnov 		.sa_handler = sigpipe,
1109b698bd97SArseniy Krasnov 	};
1110b698bd97SArseniy Krasnov 
1111b698bd97SArseniy Krasnov 	sigaction(SIGPIPE, &act, NULL);
1112b698bd97SArseniy Krasnov 
1113e18c7092SArseniy Krasnov 	fd = vsock_stream_connect(opts->peer_cid, opts->peer_port);
1114b698bd97SArseniy Krasnov 	if (fd < 0) {
1115b698bd97SArseniy Krasnov 		perror("connect");
1116b698bd97SArseniy Krasnov 		exit(EXIT_FAILURE);
1117b698bd97SArseniy Krasnov 	}
1118b698bd97SArseniy Krasnov 
1119b698bd97SArseniy Krasnov 	if (shutdown(fd, SHUT_WR)) {
1120b698bd97SArseniy Krasnov 		perror("shutdown");
1121b698bd97SArseniy Krasnov 		exit(EXIT_FAILURE);
1122b698bd97SArseniy Krasnov 	}
1123b698bd97SArseniy Krasnov 
1124b698bd97SArseniy Krasnov 	test_stream_check_sigpipe(fd);
1125b698bd97SArseniy Krasnov 
1126b698bd97SArseniy Krasnov 	control_writeln("CLIENTDONE");
1127b698bd97SArseniy Krasnov 
1128b698bd97SArseniy Krasnov 	close(fd);
1129b698bd97SArseniy Krasnov }
1130b698bd97SArseniy Krasnov 
test_stream_shutwr_server(const struct test_opts * opts)1131b698bd97SArseniy Krasnov static void test_stream_shutwr_server(const struct test_opts *opts)
1132b698bd97SArseniy Krasnov {
1133b698bd97SArseniy Krasnov 	int fd;
1134b698bd97SArseniy Krasnov 
1135e18c7092SArseniy Krasnov 	fd = vsock_stream_accept(VMADDR_CID_ANY, opts->peer_port, NULL);
1136b698bd97SArseniy Krasnov 	if (fd < 0) {
1137b698bd97SArseniy Krasnov 		perror("accept");
1138b698bd97SArseniy Krasnov 		exit(EXIT_FAILURE);
1139b698bd97SArseniy Krasnov 	}
1140b698bd97SArseniy Krasnov 
1141b698bd97SArseniy Krasnov 	control_expectln("CLIENTDONE");
1142b698bd97SArseniy Krasnov 
1143b698bd97SArseniy Krasnov 	close(fd);
1144b698bd97SArseniy Krasnov }
1145b698bd97SArseniy Krasnov 
test_stream_shutrd_client(const struct test_opts * opts)1146b698bd97SArseniy Krasnov static void test_stream_shutrd_client(const struct test_opts *opts)
1147b698bd97SArseniy Krasnov {
1148b698bd97SArseniy Krasnov 	int fd;
1149b698bd97SArseniy Krasnov 
1150b698bd97SArseniy Krasnov 	struct sigaction act = {
1151b698bd97SArseniy Krasnov 		.sa_handler = sigpipe,
1152b698bd97SArseniy Krasnov 	};
1153b698bd97SArseniy Krasnov 
1154b698bd97SArseniy Krasnov 	sigaction(SIGPIPE, &act, NULL);
1155b698bd97SArseniy Krasnov 
1156e18c7092SArseniy Krasnov 	fd = vsock_stream_connect(opts->peer_cid, opts->peer_port);
1157b698bd97SArseniy Krasnov 	if (fd < 0) {
1158b698bd97SArseniy Krasnov 		perror("connect");
1159b698bd97SArseniy Krasnov 		exit(EXIT_FAILURE);
1160b698bd97SArseniy Krasnov 	}
1161b698bd97SArseniy Krasnov 
1162b698bd97SArseniy Krasnov 	control_expectln("SHUTRDDONE");
1163b698bd97SArseniy Krasnov 
1164b698bd97SArseniy Krasnov 	test_stream_check_sigpipe(fd);
1165b698bd97SArseniy Krasnov 
1166b698bd97SArseniy Krasnov 	control_writeln("CLIENTDONE");
1167b698bd97SArseniy Krasnov 
1168b698bd97SArseniy Krasnov 	close(fd);
1169b698bd97SArseniy Krasnov }
1170b698bd97SArseniy Krasnov 
test_stream_shutrd_server(const struct test_opts * opts)1171b698bd97SArseniy Krasnov static void test_stream_shutrd_server(const struct test_opts *opts)
1172b698bd97SArseniy Krasnov {
1173b698bd97SArseniy Krasnov 	int fd;
1174b698bd97SArseniy Krasnov 
1175e18c7092SArseniy Krasnov 	fd = vsock_stream_accept(VMADDR_CID_ANY, opts->peer_port, NULL);
1176b698bd97SArseniy Krasnov 	if (fd < 0) {
1177b698bd97SArseniy Krasnov 		perror("accept");
1178b698bd97SArseniy Krasnov 		exit(EXIT_FAILURE);
1179b698bd97SArseniy Krasnov 	}
1180b698bd97SArseniy Krasnov 
1181b698bd97SArseniy Krasnov 	if (shutdown(fd, SHUT_RD)) {
1182b698bd97SArseniy Krasnov 		perror("shutdown");
1183b698bd97SArseniy Krasnov 		exit(EXIT_FAILURE);
1184b698bd97SArseniy Krasnov 	}
1185b698bd97SArseniy Krasnov 
1186b698bd97SArseniy Krasnov 	control_writeln("SHUTRDDONE");
1187b698bd97SArseniy Krasnov 	control_expectln("CLIENTDONE");
1188b698bd97SArseniy Krasnov 
1189b698bd97SArseniy Krasnov 	close(fd);
1190b698bd97SArseniy Krasnov }
1191b698bd97SArseniy Krasnov 
test_double_bind_connect_server(const struct test_opts * opts)1192d80f63f6SFilippo Storniolo static void test_double_bind_connect_server(const struct test_opts *opts)
1193d80f63f6SFilippo Storniolo {
1194d80f63f6SFilippo Storniolo 	int listen_fd, client_fd, i;
1195d80f63f6SFilippo Storniolo 	struct sockaddr_vm sa_client;
1196d80f63f6SFilippo Storniolo 	socklen_t socklen_client = sizeof(sa_client);
1197d80f63f6SFilippo Storniolo 
1198e18c7092SArseniy Krasnov 	listen_fd = vsock_stream_listen(VMADDR_CID_ANY, opts->peer_port);
1199d80f63f6SFilippo Storniolo 
1200d80f63f6SFilippo Storniolo 	for (i = 0; i < 2; i++) {
1201d80f63f6SFilippo Storniolo 		control_writeln("LISTENING");
1202d80f63f6SFilippo Storniolo 
1203d80f63f6SFilippo Storniolo 		timeout_begin(TIMEOUT);
1204d80f63f6SFilippo Storniolo 		do {
1205d80f63f6SFilippo Storniolo 			client_fd = accept(listen_fd, (struct sockaddr *)&sa_client,
1206d80f63f6SFilippo Storniolo 					   &socklen_client);
1207d80f63f6SFilippo Storniolo 			timeout_check("accept");
1208d80f63f6SFilippo Storniolo 		} while (client_fd < 0 && errno == EINTR);
1209d80f63f6SFilippo Storniolo 		timeout_end();
1210d80f63f6SFilippo Storniolo 
1211d80f63f6SFilippo Storniolo 		if (client_fd < 0) {
1212d80f63f6SFilippo Storniolo 			perror("accept");
1213d80f63f6SFilippo Storniolo 			exit(EXIT_FAILURE);
1214d80f63f6SFilippo Storniolo 		}
1215d80f63f6SFilippo Storniolo 
1216d80f63f6SFilippo Storniolo 		/* Waiting for remote peer to close connection */
1217d80f63f6SFilippo Storniolo 		vsock_wait_remote_close(client_fd);
1218d80f63f6SFilippo Storniolo 	}
1219d80f63f6SFilippo Storniolo 
1220d80f63f6SFilippo Storniolo 	close(listen_fd);
1221d80f63f6SFilippo Storniolo }
1222d80f63f6SFilippo Storniolo 
test_double_bind_connect_client(const struct test_opts * opts)1223d80f63f6SFilippo Storniolo static void test_double_bind_connect_client(const struct test_opts *opts)
1224d80f63f6SFilippo Storniolo {
1225d80f63f6SFilippo Storniolo 	int i, client_fd;
1226d80f63f6SFilippo Storniolo 
1227d80f63f6SFilippo Storniolo 	for (i = 0; i < 2; i++) {
1228d80f63f6SFilippo Storniolo 		/* Wait until server is ready to accept a new connection */
1229d80f63f6SFilippo Storniolo 		control_expectln("LISTENING");
1230d80f63f6SFilippo Storniolo 
1231e18c7092SArseniy Krasnov 		/* We use 'peer_port + 1' as "some" port for the 'bind()'
1232e18c7092SArseniy Krasnov 		 * call. It is safe for overflow, but must be considered,
1233e18c7092SArseniy Krasnov 		 * when running multiple test applications simultaneously
1234e18c7092SArseniy Krasnov 		 * where 'peer-port' argument differs by 1.
1235e18c7092SArseniy Krasnov 		 */
1236e18c7092SArseniy Krasnov 		client_fd = vsock_bind_connect(opts->peer_cid, opts->peer_port,
1237e18c7092SArseniy Krasnov 					       opts->peer_port + 1, SOCK_STREAM);
1238d80f63f6SFilippo Storniolo 
1239d80f63f6SFilippo Storniolo 		close(client_fd);
1240d80f63f6SFilippo Storniolo 	}
1241d80f63f6SFilippo Storniolo }
1242d80f63f6SFilippo Storniolo 
1243*18ee44ceSLuigi Leonardi #define MSG_BUF_IOCTL_LEN 64
test_unsent_bytes_server(const struct test_opts * opts,int type)1244*18ee44ceSLuigi Leonardi static void test_unsent_bytes_server(const struct test_opts *opts, int type)
1245*18ee44ceSLuigi Leonardi {
1246*18ee44ceSLuigi Leonardi 	unsigned char buf[MSG_BUF_IOCTL_LEN];
1247*18ee44ceSLuigi Leonardi 	int client_fd;
1248*18ee44ceSLuigi Leonardi 
1249*18ee44ceSLuigi Leonardi 	client_fd = vsock_accept(VMADDR_CID_ANY, opts->peer_port, NULL, type);
1250*18ee44ceSLuigi Leonardi 	if (client_fd < 0) {
1251*18ee44ceSLuigi Leonardi 		perror("accept");
1252*18ee44ceSLuigi Leonardi 		exit(EXIT_FAILURE);
1253*18ee44ceSLuigi Leonardi 	}
1254*18ee44ceSLuigi Leonardi 
1255*18ee44ceSLuigi Leonardi 	recv_buf(client_fd, buf, sizeof(buf), 0, sizeof(buf));
1256*18ee44ceSLuigi Leonardi 	control_writeln("RECEIVED");
1257*18ee44ceSLuigi Leonardi 
1258*18ee44ceSLuigi Leonardi 	close(client_fd);
1259*18ee44ceSLuigi Leonardi }
1260*18ee44ceSLuigi Leonardi 
test_unsent_bytes_client(const struct test_opts * opts,int type)1261*18ee44ceSLuigi Leonardi static void test_unsent_bytes_client(const struct test_opts *opts, int type)
1262*18ee44ceSLuigi Leonardi {
1263*18ee44ceSLuigi Leonardi 	unsigned char buf[MSG_BUF_IOCTL_LEN];
1264*18ee44ceSLuigi Leonardi 	int ret, fd, sock_bytes_unsent;
1265*18ee44ceSLuigi Leonardi 
1266*18ee44ceSLuigi Leonardi 	fd = vsock_connect(opts->peer_cid, opts->peer_port, type);
1267*18ee44ceSLuigi Leonardi 	if (fd < 0) {
1268*18ee44ceSLuigi Leonardi 		perror("connect");
1269*18ee44ceSLuigi Leonardi 		exit(EXIT_FAILURE);
1270*18ee44ceSLuigi Leonardi 	}
1271*18ee44ceSLuigi Leonardi 
1272*18ee44ceSLuigi Leonardi 	for (int i = 0; i < sizeof(buf); i++)
1273*18ee44ceSLuigi Leonardi 		buf[i] = rand() & 0xFF;
1274*18ee44ceSLuigi Leonardi 
1275*18ee44ceSLuigi Leonardi 	send_buf(fd, buf, sizeof(buf), 0, sizeof(buf));
1276*18ee44ceSLuigi Leonardi 	control_expectln("RECEIVED");
1277*18ee44ceSLuigi Leonardi 
1278*18ee44ceSLuigi Leonardi 	ret = ioctl(fd, SIOCOUTQ, &sock_bytes_unsent);
1279*18ee44ceSLuigi Leonardi 	if (ret < 0) {
1280*18ee44ceSLuigi Leonardi 		if (errno == EOPNOTSUPP) {
1281*18ee44ceSLuigi Leonardi 			fprintf(stderr, "Test skipped, SIOCOUTQ not supported.\n");
1282*18ee44ceSLuigi Leonardi 		} else {
1283*18ee44ceSLuigi Leonardi 			perror("ioctl");
1284*18ee44ceSLuigi Leonardi 			exit(EXIT_FAILURE);
1285*18ee44ceSLuigi Leonardi 		}
1286*18ee44ceSLuigi Leonardi 	} else if (ret == 0 && sock_bytes_unsent != 0) {
1287*18ee44ceSLuigi Leonardi 		fprintf(stderr,
1288*18ee44ceSLuigi Leonardi 			"Unexpected 'SIOCOUTQ' value, expected 0, got %i\n",
1289*18ee44ceSLuigi Leonardi 			sock_bytes_unsent);
1290*18ee44ceSLuigi Leonardi 		exit(EXIT_FAILURE);
1291*18ee44ceSLuigi Leonardi 	}
1292*18ee44ceSLuigi Leonardi 
1293*18ee44ceSLuigi Leonardi 	close(fd);
1294*18ee44ceSLuigi Leonardi }
1295*18ee44ceSLuigi Leonardi 
test_stream_unsent_bytes_client(const struct test_opts * opts)1296*18ee44ceSLuigi Leonardi static void test_stream_unsent_bytes_client(const struct test_opts *opts)
1297*18ee44ceSLuigi Leonardi {
1298*18ee44ceSLuigi Leonardi 	test_unsent_bytes_client(opts, SOCK_STREAM);
1299*18ee44ceSLuigi Leonardi }
1300*18ee44ceSLuigi Leonardi 
test_stream_unsent_bytes_server(const struct test_opts * opts)1301*18ee44ceSLuigi Leonardi static void test_stream_unsent_bytes_server(const struct test_opts *opts)
1302*18ee44ceSLuigi Leonardi {
1303*18ee44ceSLuigi Leonardi 	test_unsent_bytes_server(opts, SOCK_STREAM);
1304*18ee44ceSLuigi Leonardi }
1305*18ee44ceSLuigi Leonardi 
test_seqpacket_unsent_bytes_client(const struct test_opts * opts)1306*18ee44ceSLuigi Leonardi static void test_seqpacket_unsent_bytes_client(const struct test_opts *opts)
1307*18ee44ceSLuigi Leonardi {
1308*18ee44ceSLuigi Leonardi 	test_unsent_bytes_client(opts, SOCK_SEQPACKET);
1309*18ee44ceSLuigi Leonardi }
1310*18ee44ceSLuigi Leonardi 
test_seqpacket_unsent_bytes_server(const struct test_opts * opts)1311*18ee44ceSLuigi Leonardi static void test_seqpacket_unsent_bytes_server(const struct test_opts *opts)
1312*18ee44ceSLuigi Leonardi {
1313*18ee44ceSLuigi Leonardi 	test_unsent_bytes_server(opts, SOCK_SEQPACKET);
1314*18ee44ceSLuigi Leonardi }
1315*18ee44ceSLuigi Leonardi 
1316542e893fSArseniy Krasnov #define RCVLOWAT_CREDIT_UPD_BUF_SIZE	(1024 * 128)
1317542e893fSArseniy Krasnov /* This define is the same as in 'include/linux/virtio_vsock.h':
1318542e893fSArseniy Krasnov  * it is used to decide when to send credit update message during
1319542e893fSArseniy Krasnov  * reading from rx queue of a socket. Value and its usage in
1320542e893fSArseniy Krasnov  * kernel is important for this test.
1321542e893fSArseniy Krasnov  */
1322542e893fSArseniy Krasnov #define VIRTIO_VSOCK_MAX_PKT_BUF_SIZE	(1024 * 64)
1323542e893fSArseniy Krasnov 
test_stream_rcvlowat_def_cred_upd_client(const struct test_opts * opts)1324542e893fSArseniy Krasnov static void test_stream_rcvlowat_def_cred_upd_client(const struct test_opts *opts)
1325542e893fSArseniy Krasnov {
1326542e893fSArseniy Krasnov 	size_t buf_size;
1327542e893fSArseniy Krasnov 	void *buf;
1328542e893fSArseniy Krasnov 	int fd;
1329542e893fSArseniy Krasnov 
1330e18c7092SArseniy Krasnov 	fd = vsock_stream_connect(opts->peer_cid, opts->peer_port);
1331542e893fSArseniy Krasnov 	if (fd < 0) {
1332542e893fSArseniy Krasnov 		perror("connect");
1333542e893fSArseniy Krasnov 		exit(EXIT_FAILURE);
1334542e893fSArseniy Krasnov 	}
1335542e893fSArseniy Krasnov 
1336542e893fSArseniy Krasnov 	/* Send 1 byte more than peer's buffer size. */
1337542e893fSArseniy Krasnov 	buf_size = RCVLOWAT_CREDIT_UPD_BUF_SIZE + 1;
1338542e893fSArseniy Krasnov 
1339542e893fSArseniy Krasnov 	buf = malloc(buf_size);
1340542e893fSArseniy Krasnov 	if (!buf) {
1341542e893fSArseniy Krasnov 		perror("malloc");
1342542e893fSArseniy Krasnov 		exit(EXIT_FAILURE);
1343542e893fSArseniy Krasnov 	}
1344542e893fSArseniy Krasnov 
1345542e893fSArseniy Krasnov 	/* Wait until peer sets needed buffer size. */
1346542e893fSArseniy Krasnov 	recv_byte(fd, 1, 0);
1347542e893fSArseniy Krasnov 
1348542e893fSArseniy Krasnov 	if (send(fd, buf, buf_size, 0) != buf_size) {
1349542e893fSArseniy Krasnov 		perror("send failed");
1350542e893fSArseniy Krasnov 		exit(EXIT_FAILURE);
1351542e893fSArseniy Krasnov 	}
1352542e893fSArseniy Krasnov 
1353542e893fSArseniy Krasnov 	free(buf);
1354542e893fSArseniy Krasnov 	close(fd);
1355542e893fSArseniy Krasnov }
1356542e893fSArseniy Krasnov 
test_stream_credit_update_test(const struct test_opts * opts,bool low_rx_bytes_test)1357542e893fSArseniy Krasnov static void test_stream_credit_update_test(const struct test_opts *opts,
1358542e893fSArseniy Krasnov 					   bool low_rx_bytes_test)
1359542e893fSArseniy Krasnov {
1360542e893fSArseniy Krasnov 	size_t recv_buf_size;
1361542e893fSArseniy Krasnov 	struct pollfd fds;
1362542e893fSArseniy Krasnov 	size_t buf_size;
1363542e893fSArseniy Krasnov 	void *buf;
1364542e893fSArseniy Krasnov 	int fd;
1365542e893fSArseniy Krasnov 
1366e18c7092SArseniy Krasnov 	fd = vsock_stream_accept(VMADDR_CID_ANY, opts->peer_port, NULL);
1367542e893fSArseniy Krasnov 	if (fd < 0) {
1368542e893fSArseniy Krasnov 		perror("accept");
1369542e893fSArseniy Krasnov 		exit(EXIT_FAILURE);
1370542e893fSArseniy Krasnov 	}
1371542e893fSArseniy Krasnov 
1372542e893fSArseniy Krasnov 	buf_size = RCVLOWAT_CREDIT_UPD_BUF_SIZE;
1373542e893fSArseniy Krasnov 
1374542e893fSArseniy Krasnov 	if (setsockopt(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_SIZE,
1375542e893fSArseniy Krasnov 		       &buf_size, sizeof(buf_size))) {
1376542e893fSArseniy Krasnov 		perror("setsockopt(SO_VM_SOCKETS_BUFFER_SIZE)");
1377542e893fSArseniy Krasnov 		exit(EXIT_FAILURE);
1378542e893fSArseniy Krasnov 	}
1379542e893fSArseniy Krasnov 
1380542e893fSArseniy Krasnov 	if (low_rx_bytes_test) {
1381542e893fSArseniy Krasnov 		/* Set new SO_RCVLOWAT here. This enables sending credit
1382542e893fSArseniy Krasnov 		 * update when number of bytes if our rx queue become <
1383542e893fSArseniy Krasnov 		 * SO_RCVLOWAT value.
1384542e893fSArseniy Krasnov 		 */
1385542e893fSArseniy Krasnov 		recv_buf_size = 1 + VIRTIO_VSOCK_MAX_PKT_BUF_SIZE;
1386542e893fSArseniy Krasnov 
1387542e893fSArseniy Krasnov 		if (setsockopt(fd, SOL_SOCKET, SO_RCVLOWAT,
1388542e893fSArseniy Krasnov 			       &recv_buf_size, sizeof(recv_buf_size))) {
1389542e893fSArseniy Krasnov 			perror("setsockopt(SO_RCVLOWAT)");
1390542e893fSArseniy Krasnov 			exit(EXIT_FAILURE);
1391542e893fSArseniy Krasnov 		}
1392542e893fSArseniy Krasnov 	}
1393542e893fSArseniy Krasnov 
1394542e893fSArseniy Krasnov 	/* Send one dummy byte here, because 'setsockopt()' above also
1395542e893fSArseniy Krasnov 	 * sends special packet which tells sender to update our buffer
1396542e893fSArseniy Krasnov 	 * size. This 'send_byte()' will serialize such packet with data
1397542e893fSArseniy Krasnov 	 * reads in a loop below. Sender starts transmission only when
1398542e893fSArseniy Krasnov 	 * it receives this single byte.
1399542e893fSArseniy Krasnov 	 */
1400542e893fSArseniy Krasnov 	send_byte(fd, 1, 0);
1401542e893fSArseniy Krasnov 
1402542e893fSArseniy Krasnov 	buf = malloc(buf_size);
1403542e893fSArseniy Krasnov 	if (!buf) {
1404542e893fSArseniy Krasnov 		perror("malloc");
1405542e893fSArseniy Krasnov 		exit(EXIT_FAILURE);
1406542e893fSArseniy Krasnov 	}
1407542e893fSArseniy Krasnov 
1408542e893fSArseniy Krasnov 	/* Wait until there will be 128KB of data in rx queue. */
1409542e893fSArseniy Krasnov 	while (1) {
1410542e893fSArseniy Krasnov 		ssize_t res;
1411542e893fSArseniy Krasnov 
1412542e893fSArseniy Krasnov 		res = recv(fd, buf, buf_size, MSG_PEEK);
1413542e893fSArseniy Krasnov 		if (res == buf_size)
1414542e893fSArseniy Krasnov 			break;
1415542e893fSArseniy Krasnov 
1416542e893fSArseniy Krasnov 		if (res <= 0) {
1417542e893fSArseniy Krasnov 			fprintf(stderr, "unexpected 'recv()' return: %zi\n", res);
1418542e893fSArseniy Krasnov 			exit(EXIT_FAILURE);
1419542e893fSArseniy Krasnov 		}
1420542e893fSArseniy Krasnov 	}
1421542e893fSArseniy Krasnov 
1422542e893fSArseniy Krasnov 	/* There is 128KB of data in the socket's rx queue, dequeue first
1423542e893fSArseniy Krasnov 	 * 64KB, credit update is sent if 'low_rx_bytes_test' == true.
1424542e893fSArseniy Krasnov 	 * Otherwise, credit update is sent in 'if (!low_rx_bytes_test)'.
1425542e893fSArseniy Krasnov 	 */
1426542e893fSArseniy Krasnov 	recv_buf_size = VIRTIO_VSOCK_MAX_PKT_BUF_SIZE;
1427542e893fSArseniy Krasnov 	recv_buf(fd, buf, recv_buf_size, 0, recv_buf_size);
1428542e893fSArseniy Krasnov 
1429542e893fSArseniy Krasnov 	if (!low_rx_bytes_test) {
1430542e893fSArseniy Krasnov 		recv_buf_size++;
1431542e893fSArseniy Krasnov 
1432542e893fSArseniy Krasnov 		/* Updating SO_RCVLOWAT will send credit update. */
1433542e893fSArseniy Krasnov 		if (setsockopt(fd, SOL_SOCKET, SO_RCVLOWAT,
1434542e893fSArseniy Krasnov 			       &recv_buf_size, sizeof(recv_buf_size))) {
1435542e893fSArseniy Krasnov 			perror("setsockopt(SO_RCVLOWAT)");
1436542e893fSArseniy Krasnov 			exit(EXIT_FAILURE);
1437542e893fSArseniy Krasnov 		}
1438542e893fSArseniy Krasnov 	}
1439542e893fSArseniy Krasnov 
1440542e893fSArseniy Krasnov 	fds.fd = fd;
1441542e893fSArseniy Krasnov 	fds.events = POLLIN | POLLRDNORM | POLLERR |
1442542e893fSArseniy Krasnov 		     POLLRDHUP | POLLHUP;
1443542e893fSArseniy Krasnov 
1444542e893fSArseniy Krasnov 	/* This 'poll()' will return once we receive last byte
1445542e893fSArseniy Krasnov 	 * sent by client.
1446542e893fSArseniy Krasnov 	 */
1447542e893fSArseniy Krasnov 	if (poll(&fds, 1, -1) < 0) {
1448542e893fSArseniy Krasnov 		perror("poll");
1449542e893fSArseniy Krasnov 		exit(EXIT_FAILURE);
1450542e893fSArseniy Krasnov 	}
1451542e893fSArseniy Krasnov 
1452542e893fSArseniy Krasnov 	if (fds.revents & POLLERR) {
1453542e893fSArseniy Krasnov 		fprintf(stderr, "'poll()' error\n");
1454542e893fSArseniy Krasnov 		exit(EXIT_FAILURE);
1455542e893fSArseniy Krasnov 	}
1456542e893fSArseniy Krasnov 
1457542e893fSArseniy Krasnov 	if (fds.revents & (POLLIN | POLLRDNORM)) {
1458542e893fSArseniy Krasnov 		recv_buf(fd, buf, recv_buf_size, MSG_DONTWAIT, recv_buf_size);
1459542e893fSArseniy Krasnov 	} else {
1460542e893fSArseniy Krasnov 		/* These flags must be set, as there is at
1461542e893fSArseniy Krasnov 		 * least 64KB of data ready to read.
1462542e893fSArseniy Krasnov 		 */
1463542e893fSArseniy Krasnov 		fprintf(stderr, "POLLIN | POLLRDNORM expected\n");
1464542e893fSArseniy Krasnov 		exit(EXIT_FAILURE);
1465542e893fSArseniy Krasnov 	}
1466542e893fSArseniy Krasnov 
1467542e893fSArseniy Krasnov 	free(buf);
1468542e893fSArseniy Krasnov 	close(fd);
1469542e893fSArseniy Krasnov }
1470542e893fSArseniy Krasnov 
test_stream_cred_upd_on_low_rx_bytes(const struct test_opts * opts)1471542e893fSArseniy Krasnov static void test_stream_cred_upd_on_low_rx_bytes(const struct test_opts *opts)
1472542e893fSArseniy Krasnov {
1473542e893fSArseniy Krasnov 	test_stream_credit_update_test(opts, true);
1474542e893fSArseniy Krasnov }
1475542e893fSArseniy Krasnov 
test_stream_cred_upd_on_set_rcvlowat(const struct test_opts * opts)1476542e893fSArseniy Krasnov static void test_stream_cred_upd_on_set_rcvlowat(const struct test_opts *opts)
1477542e893fSArseniy Krasnov {
1478542e893fSArseniy Krasnov 	test_stream_credit_update_test(opts, false);
1479542e893fSArseniy Krasnov }
1480542e893fSArseniy Krasnov 
1481cdbcc18dSStefan Hajnoczi static struct test_case test_cases[] = {
1482cdbcc18dSStefan Hajnoczi 	{
1483cdbcc18dSStefan Hajnoczi 		.name = "SOCK_STREAM connection reset",
1484cdbcc18dSStefan Hajnoczi 		.run_client = test_stream_connection_reset,
1485cdbcc18dSStefan Hajnoczi 	},
1486cdbcc18dSStefan Hajnoczi 	{
14879de9f7d1SSebastien Boeuf 		.name = "SOCK_STREAM bind only",
14889de9f7d1SSebastien Boeuf 		.run_client = test_stream_bind_only_client,
14899de9f7d1SSebastien Boeuf 		.run_server = test_stream_bind_only_server,
14909de9f7d1SSebastien Boeuf 	},
14919de9f7d1SSebastien Boeuf 	{
1492cdbcc18dSStefan Hajnoczi 		.name = "SOCK_STREAM client close",
1493cdbcc18dSStefan Hajnoczi 		.run_client = test_stream_client_close_client,
1494cdbcc18dSStefan Hajnoczi 		.run_server = test_stream_client_close_server,
1495cdbcc18dSStefan Hajnoczi 	},
1496cdbcc18dSStefan Hajnoczi 	{
1497cdbcc18dSStefan Hajnoczi 		.name = "SOCK_STREAM server close",
1498cdbcc18dSStefan Hajnoczi 		.run_client = test_stream_server_close_client,
1499cdbcc18dSStefan Hajnoczi 		.run_server = test_stream_server_close_server,
1500cdbcc18dSStefan Hajnoczi 	},
1501cdbcc18dSStefan Hajnoczi 	{
1502cdbcc18dSStefan Hajnoczi 		.name = "SOCK_STREAM multiple connections",
1503cdbcc18dSStefan Hajnoczi 		.run_client = test_stream_multiconn_client,
1504cdbcc18dSStefan Hajnoczi 		.run_server = test_stream_multiconn_server,
1505cdbcc18dSStefan Hajnoczi 	},
1506d6269a93SStefano Garzarella 	{
1507d6269a93SStefano Garzarella 		.name = "SOCK_STREAM MSG_PEEK",
1508d6269a93SStefano Garzarella 		.run_client = test_stream_msg_peek_client,
1509d6269a93SStefano Garzarella 		.run_server = test_stream_msg_peek_server,
1510d6269a93SStefano Garzarella 	},
151141b792d7SArseny Krasnov 	{
151241b792d7SArseny Krasnov 		.name = "SOCK_SEQPACKET msg bounds",
151341b792d7SArseny Krasnov 		.run_client = test_seqpacket_msg_bounds_client,
151441b792d7SArseny Krasnov 		.run_server = test_seqpacket_msg_bounds_server,
151541b792d7SArseny Krasnov 	},
151641b792d7SArseny Krasnov 	{
151741b792d7SArseny Krasnov 		.name = "SOCK_SEQPACKET MSG_TRUNC flag",
151841b792d7SArseny Krasnov 		.run_client = test_seqpacket_msg_trunc_client,
151941b792d7SArseny Krasnov 		.run_server = test_seqpacket_msg_trunc_server,
152041b792d7SArseny Krasnov 	},
1521efb3719fSKrasnov Arseniy Vladimirovich 	{
1522efb3719fSKrasnov Arseniy Vladimirovich 		.name = "SOCK_SEQPACKET timeout",
1523efb3719fSKrasnov Arseniy Vladimirovich 		.run_client = test_seqpacket_timeout_client,
1524efb3719fSKrasnov Arseniy Vladimirovich 		.run_server = test_seqpacket_timeout_server,
1525efb3719fSKrasnov Arseniy Vladimirovich 	},
1526e89600ebSKrasnov Arseniy Vladimirovich 	{
1527e89600ebSKrasnov Arseniy Vladimirovich 		.name = "SOCK_SEQPACKET invalid receive buffer",
1528e89600ebSKrasnov Arseniy Vladimirovich 		.run_client = test_seqpacket_invalid_rec_buffer_client,
1529e89600ebSKrasnov Arseniy Vladimirovich 		.run_server = test_seqpacket_invalid_rec_buffer_server,
1530e89600ebSKrasnov Arseniy Vladimirovich 	},
1531b1346338SArseniy Krasnov 	{
1532b1346338SArseniy Krasnov 		.name = "SOCK_STREAM poll() + SO_RCVLOWAT",
1533b1346338SArseniy Krasnov 		.run_client = test_stream_poll_rcvlowat_client,
1534b1346338SArseniy Krasnov 		.run_server = test_stream_poll_rcvlowat_server,
1535b1346338SArseniy Krasnov 	},
1536685a21c3SArseniy Krasnov 	{
1537685a21c3SArseniy Krasnov 		.name = "SOCK_SEQPACKET big message",
1538685a21c3SArseniy Krasnov 		.run_client = test_seqpacket_bigmsg_client,
1539685a21c3SArseniy Krasnov 		.run_server = test_seqpacket_bigmsg_server,
1540685a21c3SArseniy Krasnov 	},
15417e699d2aSArseniy Krasnov 	{
15427e699d2aSArseniy Krasnov 		.name = "SOCK_STREAM test invalid buffer",
15437e699d2aSArseniy Krasnov 		.run_client = test_stream_inv_buf_client,
15447e699d2aSArseniy Krasnov 		.run_server = test_stream_inv_buf_server,
15457e699d2aSArseniy Krasnov 	},
15467e699d2aSArseniy Krasnov 	{
15477e699d2aSArseniy Krasnov 		.name = "SOCK_SEQPACKET test invalid buffer",
15487e699d2aSArseniy Krasnov 		.run_client = test_seqpacket_inv_buf_client,
15497e699d2aSArseniy Krasnov 		.run_server = test_seqpacket_inv_buf_server,
15507e699d2aSArseniy Krasnov 	},
155125209a32SArseniy Krasnov 	{
155225209a32SArseniy Krasnov 		.name = "SOCK_STREAM virtio skb merge",
155325209a32SArseniy Krasnov 		.run_client = test_stream_virtio_skb_merge_client,
155425209a32SArseniy Krasnov 		.run_server = test_stream_virtio_skb_merge_server,
155525209a32SArseniy Krasnov 	},
15568a0697f2SArseniy Krasnov 	{
15578a0697f2SArseniy Krasnov 		.name = "SOCK_SEQPACKET MSG_PEEK",
15588a0697f2SArseniy Krasnov 		.run_client = test_seqpacket_msg_peek_client,
15598a0697f2SArseniy Krasnov 		.run_server = test_seqpacket_msg_peek_server,
15608a0697f2SArseniy Krasnov 	},
1561b698bd97SArseniy Krasnov 	{
1562b698bd97SArseniy Krasnov 		.name = "SOCK_STREAM SHUT_WR",
1563b698bd97SArseniy Krasnov 		.run_client = test_stream_shutwr_client,
1564b698bd97SArseniy Krasnov 		.run_server = test_stream_shutwr_server,
1565b698bd97SArseniy Krasnov 	},
1566b698bd97SArseniy Krasnov 	{
1567b698bd97SArseniy Krasnov 		.name = "SOCK_STREAM SHUT_RD",
1568b698bd97SArseniy Krasnov 		.run_client = test_stream_shutrd_client,
1569b698bd97SArseniy Krasnov 		.run_server = test_stream_shutrd_server,
1570b698bd97SArseniy Krasnov 	},
1571bc36442eSArseniy Krasnov 	{
1572bc36442eSArseniy Krasnov 		.name = "SOCK_STREAM MSG_ZEROCOPY",
1573bc36442eSArseniy Krasnov 		.run_client = test_stream_msgzcopy_client,
1574bc36442eSArseniy Krasnov 		.run_server = test_stream_msgzcopy_server,
1575bc36442eSArseniy Krasnov 	},
1576bc36442eSArseniy Krasnov 	{
1577bc36442eSArseniy Krasnov 		.name = "SOCK_SEQPACKET MSG_ZEROCOPY",
1578bc36442eSArseniy Krasnov 		.run_client = test_seqpacket_msgzcopy_client,
1579bc36442eSArseniy Krasnov 		.run_server = test_seqpacket_msgzcopy_server,
1580bc36442eSArseniy Krasnov 	},
1581bc36442eSArseniy Krasnov 	{
1582bc36442eSArseniy Krasnov 		.name = "SOCK_STREAM MSG_ZEROCOPY empty MSG_ERRQUEUE",
1583bc36442eSArseniy Krasnov 		.run_client = test_stream_msgzcopy_empty_errq_client,
1584bc36442eSArseniy Krasnov 		.run_server = test_stream_msgzcopy_empty_errq_server,
1585bc36442eSArseniy Krasnov 	},
1586d80f63f6SFilippo Storniolo 	{
1587d80f63f6SFilippo Storniolo 		.name = "SOCK_STREAM double bind connect",
1588d80f63f6SFilippo Storniolo 		.run_client = test_double_bind_connect_client,
1589d80f63f6SFilippo Storniolo 		.run_server = test_double_bind_connect_server,
1590d80f63f6SFilippo Storniolo 	},
1591542e893fSArseniy Krasnov 	{
1592542e893fSArseniy Krasnov 		.name = "SOCK_STREAM virtio credit update + SO_RCVLOWAT",
1593542e893fSArseniy Krasnov 		.run_client = test_stream_rcvlowat_def_cred_upd_client,
1594542e893fSArseniy Krasnov 		.run_server = test_stream_cred_upd_on_set_rcvlowat,
1595542e893fSArseniy Krasnov 	},
1596542e893fSArseniy Krasnov 	{
1597542e893fSArseniy Krasnov 		.name = "SOCK_STREAM virtio credit update + low rx_bytes",
1598542e893fSArseniy Krasnov 		.run_client = test_stream_rcvlowat_def_cred_upd_client,
1599542e893fSArseniy Krasnov 		.run_server = test_stream_cred_upd_on_low_rx_bytes,
1600542e893fSArseniy Krasnov 	},
1601*18ee44ceSLuigi Leonardi 	{
1602*18ee44ceSLuigi Leonardi 		.name = "SOCK_STREAM ioctl(SIOCOUTQ) 0 unsent bytes",
1603*18ee44ceSLuigi Leonardi 		.run_client = test_stream_unsent_bytes_client,
1604*18ee44ceSLuigi Leonardi 		.run_server = test_stream_unsent_bytes_server,
1605*18ee44ceSLuigi Leonardi 	},
1606*18ee44ceSLuigi Leonardi 	{
1607*18ee44ceSLuigi Leonardi 		.name = "SOCK_SEQPACKET ioctl(SIOCOUTQ) 0 unsent bytes",
1608*18ee44ceSLuigi Leonardi 		.run_client = test_seqpacket_unsent_bytes_client,
1609*18ee44ceSLuigi Leonardi 		.run_server = test_seqpacket_unsent_bytes_server,
1610*18ee44ceSLuigi Leonardi 	},
1611cdbcc18dSStefan Hajnoczi 	{},
1612cdbcc18dSStefan Hajnoczi };
1613cdbcc18dSStefan Hajnoczi 
1614cdbcc18dSStefan Hajnoczi static const char optstring[] = "";
1615cdbcc18dSStefan Hajnoczi static const struct option longopts[] = {
1616cdbcc18dSStefan Hajnoczi 	{
1617cdbcc18dSStefan Hajnoczi 		.name = "control-host",
1618cdbcc18dSStefan Hajnoczi 		.has_arg = required_argument,
1619cdbcc18dSStefan Hajnoczi 		.val = 'H',
1620cdbcc18dSStefan Hajnoczi 	},
1621cdbcc18dSStefan Hajnoczi 	{
1622cdbcc18dSStefan Hajnoczi 		.name = "control-port",
1623cdbcc18dSStefan Hajnoczi 		.has_arg = required_argument,
1624cdbcc18dSStefan Hajnoczi 		.val = 'P',
1625cdbcc18dSStefan Hajnoczi 	},
1626cdbcc18dSStefan Hajnoczi 	{
1627cdbcc18dSStefan Hajnoczi 		.name = "mode",
1628cdbcc18dSStefan Hajnoczi 		.has_arg = required_argument,
1629cdbcc18dSStefan Hajnoczi 		.val = 'm',
1630cdbcc18dSStefan Hajnoczi 	},
1631cdbcc18dSStefan Hajnoczi 	{
1632cdbcc18dSStefan Hajnoczi 		.name = "peer-cid",
1633cdbcc18dSStefan Hajnoczi 		.has_arg = required_argument,
1634cdbcc18dSStefan Hajnoczi 		.val = 'p',
1635cdbcc18dSStefan Hajnoczi 	},
1636cdbcc18dSStefan Hajnoczi 	{
1637e18c7092SArseniy Krasnov 		.name = "peer-port",
1638e18c7092SArseniy Krasnov 		.has_arg = required_argument,
1639e18c7092SArseniy Krasnov 		.val = 'q',
1640e18c7092SArseniy Krasnov 	},
1641e18c7092SArseniy Krasnov 	{
16425a2b2425SStefano Garzarella 		.name = "list",
16435a2b2425SStefano Garzarella 		.has_arg = no_argument,
16445a2b2425SStefano Garzarella 		.val = 'l',
16455a2b2425SStefano Garzarella 	},
16465a2b2425SStefano Garzarella 	{
16475a2b2425SStefano Garzarella 		.name = "skip",
16485a2b2425SStefano Garzarella 		.has_arg = required_argument,
16495a2b2425SStefano Garzarella 		.val = 's',
16505a2b2425SStefano Garzarella 	},
16515a2b2425SStefano Garzarella 	{
1652cdbcc18dSStefan Hajnoczi 		.name = "help",
1653cdbcc18dSStefan Hajnoczi 		.has_arg = no_argument,
1654cdbcc18dSStefan Hajnoczi 		.val = '?',
1655cdbcc18dSStefan Hajnoczi 	},
1656cdbcc18dSStefan Hajnoczi 	{},
1657cdbcc18dSStefan Hajnoczi };
1658cdbcc18dSStefan Hajnoczi 
usage(void)1659cdbcc18dSStefan Hajnoczi static void usage(void)
1660cdbcc18dSStefan Hajnoczi {
1661e18c7092SArseniy Krasnov 	fprintf(stderr, "Usage: vsock_test [--help] [--control-host=<host>] --control-port=<port> --mode=client|server --peer-cid=<cid> [--peer-port=<port>] [--list] [--skip=<test_id>]\n"
1662cdbcc18dSStefan Hajnoczi 		"\n"
1663cdbcc18dSStefan Hajnoczi 		"  Server: vsock_test --control-port=1234 --mode=server --peer-cid=3\n"
1664cdbcc18dSStefan Hajnoczi 		"  Client: vsock_test --control-host=192.168.0.1 --control-port=1234 --mode=client --peer-cid=2\n"
1665cdbcc18dSStefan Hajnoczi 		"\n"
1666cdbcc18dSStefan Hajnoczi 		"Run vsock.ko tests.  Must be launched in both guest\n"
1667cdbcc18dSStefan Hajnoczi 		"and host.  One side must use --mode=client and\n"
1668cdbcc18dSStefan Hajnoczi 		"the other side must use --mode=server.\n"
1669cdbcc18dSStefan Hajnoczi 		"\n"
1670cdbcc18dSStefan Hajnoczi 		"A TCP control socket connection is used to coordinate tests\n"
1671cdbcc18dSStefan Hajnoczi 		"between the client and the server.  The server requires a\n"
1672cdbcc18dSStefan Hajnoczi 		"listen address and the client requires an address to\n"
1673cdbcc18dSStefan Hajnoczi 		"connect to.\n"
1674cdbcc18dSStefan Hajnoczi 		"\n"
16758d00b93fSStefano Garzarella 		"The CID of the other side must be given with --peer-cid=<cid>.\n"
1676e18c7092SArseniy Krasnov 		"During the test, two AF_VSOCK ports will be used: the port\n"
1677e18c7092SArseniy Krasnov 		"specified with --peer-port=<port> (or the default port)\n"
1678e18c7092SArseniy Krasnov 		"and the next one.\n"
16798d00b93fSStefano Garzarella 		"\n"
16808d00b93fSStefano Garzarella 		"Options:\n"
16818d00b93fSStefano Garzarella 		"  --help                 This help message\n"
16828d00b93fSStefano Garzarella 		"  --control-host <host>  Server IP address to connect to\n"
16838d00b93fSStefano Garzarella 		"  --control-port <port>  Server port to listen on/connect to\n"
16848d00b93fSStefano Garzarella 		"  --mode client|server   Server or client mode\n"
16858d00b93fSStefano Garzarella 		"  --peer-cid <cid>       CID of the other side\n"
1686e18c7092SArseniy Krasnov 		"  --peer-port <port>     AF_VSOCK port used for the test [default: %d]\n"
16878d00b93fSStefano Garzarella 		"  --list                 List of tests that will be executed\n"
16888d00b93fSStefano Garzarella 		"  --skip <test_id>       Test ID to skip;\n"
1689e18c7092SArseniy Krasnov 		"                         use multiple --skip options to skip more tests\n",
1690e18c7092SArseniy Krasnov 		DEFAULT_PEER_PORT
16918d00b93fSStefano Garzarella 		);
1692cdbcc18dSStefan Hajnoczi 	exit(EXIT_FAILURE);
1693cdbcc18dSStefan Hajnoczi }
1694cdbcc18dSStefan Hajnoczi 
main(int argc,char ** argv)1695cdbcc18dSStefan Hajnoczi int main(int argc, char **argv)
1696cdbcc18dSStefan Hajnoczi {
1697cdbcc18dSStefan Hajnoczi 	const char *control_host = NULL;
1698cdbcc18dSStefan Hajnoczi 	const char *control_port = NULL;
1699cdbcc18dSStefan Hajnoczi 	struct test_opts opts = {
1700cdbcc18dSStefan Hajnoczi 		.mode = TEST_MODE_UNSET,
1701cdbcc18dSStefan Hajnoczi 		.peer_cid = VMADDR_CID_ANY,
1702e18c7092SArseniy Krasnov 		.peer_port = DEFAULT_PEER_PORT,
1703cdbcc18dSStefan Hajnoczi 	};
1704cdbcc18dSStefan Hajnoczi 
17055c338112SArseniy Krasnov 	srand(time(NULL));
1706cdbcc18dSStefan Hajnoczi 	init_signals();
1707cdbcc18dSStefan Hajnoczi 
1708cdbcc18dSStefan Hajnoczi 	for (;;) {
1709cdbcc18dSStefan Hajnoczi 		int opt = getopt_long(argc, argv, optstring, longopts, NULL);
1710cdbcc18dSStefan Hajnoczi 
1711cdbcc18dSStefan Hajnoczi 		if (opt == -1)
1712cdbcc18dSStefan Hajnoczi 			break;
1713cdbcc18dSStefan Hajnoczi 
1714cdbcc18dSStefan Hajnoczi 		switch (opt) {
1715cdbcc18dSStefan Hajnoczi 		case 'H':
1716cdbcc18dSStefan Hajnoczi 			control_host = optarg;
1717cdbcc18dSStefan Hajnoczi 			break;
1718cdbcc18dSStefan Hajnoczi 		case 'm':
1719cdbcc18dSStefan Hajnoczi 			if (strcmp(optarg, "client") == 0)
1720cdbcc18dSStefan Hajnoczi 				opts.mode = TEST_MODE_CLIENT;
1721cdbcc18dSStefan Hajnoczi 			else if (strcmp(optarg, "server") == 0)
1722cdbcc18dSStefan Hajnoczi 				opts.mode = TEST_MODE_SERVER;
1723cdbcc18dSStefan Hajnoczi 			else {
1724cdbcc18dSStefan Hajnoczi 				fprintf(stderr, "--mode must be \"client\" or \"server\"\n");
1725cdbcc18dSStefan Hajnoczi 				return EXIT_FAILURE;
1726cdbcc18dSStefan Hajnoczi 			}
1727cdbcc18dSStefan Hajnoczi 			break;
1728cdbcc18dSStefan Hajnoczi 		case 'p':
1729cdbcc18dSStefan Hajnoczi 			opts.peer_cid = parse_cid(optarg);
1730cdbcc18dSStefan Hajnoczi 			break;
1731e18c7092SArseniy Krasnov 		case 'q':
1732e18c7092SArseniy Krasnov 			opts.peer_port = parse_port(optarg);
1733e18c7092SArseniy Krasnov 			break;
1734cdbcc18dSStefan Hajnoczi 		case 'P':
1735cdbcc18dSStefan Hajnoczi 			control_port = optarg;
1736cdbcc18dSStefan Hajnoczi 			break;
17375a2b2425SStefano Garzarella 		case 'l':
17385a2b2425SStefano Garzarella 			list_tests(test_cases);
17395a2b2425SStefano Garzarella 			break;
17405a2b2425SStefano Garzarella 		case 's':
17415a2b2425SStefano Garzarella 			skip_test(test_cases, ARRAY_SIZE(test_cases) - 1,
17425a2b2425SStefano Garzarella 				  optarg);
17435a2b2425SStefano Garzarella 			break;
1744cdbcc18dSStefan Hajnoczi 		case '?':
1745cdbcc18dSStefan Hajnoczi 		default:
1746cdbcc18dSStefan Hajnoczi 			usage();
1747cdbcc18dSStefan Hajnoczi 		}
1748cdbcc18dSStefan Hajnoczi 	}
1749cdbcc18dSStefan Hajnoczi 
1750cdbcc18dSStefan Hajnoczi 	if (!control_port)
1751cdbcc18dSStefan Hajnoczi 		usage();
1752cdbcc18dSStefan Hajnoczi 	if (opts.mode == TEST_MODE_UNSET)
1753cdbcc18dSStefan Hajnoczi 		usage();
1754cdbcc18dSStefan Hajnoczi 	if (opts.peer_cid == VMADDR_CID_ANY)
1755cdbcc18dSStefan Hajnoczi 		usage();
1756cdbcc18dSStefan Hajnoczi 
1757cdbcc18dSStefan Hajnoczi 	if (!control_host) {
1758cdbcc18dSStefan Hajnoczi 		if (opts.mode != TEST_MODE_SERVER)
1759cdbcc18dSStefan Hajnoczi 			usage();
1760cdbcc18dSStefan Hajnoczi 		control_host = "0.0.0.0";
1761cdbcc18dSStefan Hajnoczi 	}
1762cdbcc18dSStefan Hajnoczi 
1763cdbcc18dSStefan Hajnoczi 	control_init(control_host, control_port,
1764cdbcc18dSStefan Hajnoczi 		     opts.mode == TEST_MODE_SERVER);
1765cdbcc18dSStefan Hajnoczi 
1766cdbcc18dSStefan Hajnoczi 	run_tests(test_cases, &opts);
1767cdbcc18dSStefan Hajnoczi 
1768cdbcc18dSStefan Hajnoczi 	control_cleanup();
1769cdbcc18dSStefan Hajnoczi 	return EXIT_SUCCESS;
1770cdbcc18dSStefan Hajnoczi }
1771