xref: /openbmc/linux/tools/testing/vsock/vsock_test.c (revision 25209a32)
1cdbcc18dSStefan Hajnoczi // SPDX-License-Identifier: GPL-2.0-only
2cdbcc18dSStefan Hajnoczi /*
3cdbcc18dSStefan Hajnoczi  * vsock_test - vsock.ko test suite
4cdbcc18dSStefan Hajnoczi  *
5cdbcc18dSStefan Hajnoczi  * Copyright (C) 2017 Red Hat, Inc.
6cdbcc18dSStefan Hajnoczi  *
7cdbcc18dSStefan Hajnoczi  * Author: Stefan Hajnoczi <stefanha@redhat.com>
8cdbcc18dSStefan Hajnoczi  */
9cdbcc18dSStefan Hajnoczi 
10cdbcc18dSStefan Hajnoczi #include <getopt.h>
11cdbcc18dSStefan Hajnoczi #include <stdio.h>
12cdbcc18dSStefan Hajnoczi #include <stdlib.h>
13cdbcc18dSStefan Hajnoczi #include <string.h>
14cdbcc18dSStefan Hajnoczi #include <errno.h>
15cdbcc18dSStefan Hajnoczi #include <unistd.h>
165a2b2425SStefano Garzarella #include <linux/kernel.h>
1741b792d7SArseny Krasnov #include <sys/types.h>
1841b792d7SArseny Krasnov #include <sys/socket.h>
19efb3719fSKrasnov Arseniy Vladimirovich #include <time.h>
20e89600ebSKrasnov Arseniy Vladimirovich #include <sys/mman.h>
21b1346338SArseniy Krasnov #include <poll.h>
22cdbcc18dSStefan Hajnoczi 
23cdbcc18dSStefan Hajnoczi #include "timeout.h"
24cdbcc18dSStefan Hajnoczi #include "control.h"
25cdbcc18dSStefan Hajnoczi #include "util.h"
26cdbcc18dSStefan Hajnoczi 
27cdbcc18dSStefan Hajnoczi static void test_stream_connection_reset(const struct test_opts *opts)
28cdbcc18dSStefan Hajnoczi {
29cdbcc18dSStefan Hajnoczi 	union {
30cdbcc18dSStefan Hajnoczi 		struct sockaddr sa;
31cdbcc18dSStefan Hajnoczi 		struct sockaddr_vm svm;
32cdbcc18dSStefan Hajnoczi 	} addr = {
33cdbcc18dSStefan Hajnoczi 		.svm = {
34cdbcc18dSStefan Hajnoczi 			.svm_family = AF_VSOCK,
35cdbcc18dSStefan Hajnoczi 			.svm_port = 1234,
36cdbcc18dSStefan Hajnoczi 			.svm_cid = opts->peer_cid,
37cdbcc18dSStefan Hajnoczi 		},
38cdbcc18dSStefan Hajnoczi 	};
39cdbcc18dSStefan Hajnoczi 	int ret;
40cdbcc18dSStefan Hajnoczi 	int fd;
41cdbcc18dSStefan Hajnoczi 
42cdbcc18dSStefan Hajnoczi 	fd = socket(AF_VSOCK, SOCK_STREAM, 0);
43cdbcc18dSStefan Hajnoczi 
44cdbcc18dSStefan Hajnoczi 	timeout_begin(TIMEOUT);
45cdbcc18dSStefan Hajnoczi 	do {
46cdbcc18dSStefan Hajnoczi 		ret = connect(fd, &addr.sa, sizeof(addr.svm));
47cdbcc18dSStefan Hajnoczi 		timeout_check("connect");
48cdbcc18dSStefan Hajnoczi 	} while (ret < 0 && errno == EINTR);
49cdbcc18dSStefan Hajnoczi 	timeout_end();
50cdbcc18dSStefan Hajnoczi 
51cdbcc18dSStefan Hajnoczi 	if (ret != -1) {
52cdbcc18dSStefan Hajnoczi 		fprintf(stderr, "expected connect(2) failure, got %d\n", ret);
53cdbcc18dSStefan Hajnoczi 		exit(EXIT_FAILURE);
54cdbcc18dSStefan Hajnoczi 	}
55cdbcc18dSStefan Hajnoczi 	if (errno != ECONNRESET) {
56cdbcc18dSStefan Hajnoczi 		fprintf(stderr, "unexpected connect(2) errno %d\n", errno);
57cdbcc18dSStefan Hajnoczi 		exit(EXIT_FAILURE);
58cdbcc18dSStefan Hajnoczi 	}
59cdbcc18dSStefan Hajnoczi 
60cdbcc18dSStefan Hajnoczi 	close(fd);
61cdbcc18dSStefan Hajnoczi }
62cdbcc18dSStefan Hajnoczi 
639de9f7d1SSebastien Boeuf static void test_stream_bind_only_client(const struct test_opts *opts)
649de9f7d1SSebastien Boeuf {
659de9f7d1SSebastien Boeuf 	union {
669de9f7d1SSebastien Boeuf 		struct sockaddr sa;
679de9f7d1SSebastien Boeuf 		struct sockaddr_vm svm;
689de9f7d1SSebastien Boeuf 	} addr = {
699de9f7d1SSebastien Boeuf 		.svm = {
709de9f7d1SSebastien Boeuf 			.svm_family = AF_VSOCK,
719de9f7d1SSebastien Boeuf 			.svm_port = 1234,
729de9f7d1SSebastien Boeuf 			.svm_cid = opts->peer_cid,
739de9f7d1SSebastien Boeuf 		},
749de9f7d1SSebastien Boeuf 	};
759de9f7d1SSebastien Boeuf 	int ret;
769de9f7d1SSebastien Boeuf 	int fd;
779de9f7d1SSebastien Boeuf 
789de9f7d1SSebastien Boeuf 	/* Wait for the server to be ready */
799de9f7d1SSebastien Boeuf 	control_expectln("BIND");
809de9f7d1SSebastien Boeuf 
819de9f7d1SSebastien Boeuf 	fd = socket(AF_VSOCK, SOCK_STREAM, 0);
829de9f7d1SSebastien Boeuf 
839de9f7d1SSebastien Boeuf 	timeout_begin(TIMEOUT);
849de9f7d1SSebastien Boeuf 	do {
859de9f7d1SSebastien Boeuf 		ret = connect(fd, &addr.sa, sizeof(addr.svm));
869de9f7d1SSebastien Boeuf 		timeout_check("connect");
879de9f7d1SSebastien Boeuf 	} while (ret < 0 && errno == EINTR);
889de9f7d1SSebastien Boeuf 	timeout_end();
899de9f7d1SSebastien Boeuf 
909de9f7d1SSebastien Boeuf 	if (ret != -1) {
919de9f7d1SSebastien Boeuf 		fprintf(stderr, "expected connect(2) failure, got %d\n", ret);
929de9f7d1SSebastien Boeuf 		exit(EXIT_FAILURE);
939de9f7d1SSebastien Boeuf 	}
949de9f7d1SSebastien Boeuf 	if (errno != ECONNRESET) {
959de9f7d1SSebastien Boeuf 		fprintf(stderr, "unexpected connect(2) errno %d\n", errno);
969de9f7d1SSebastien Boeuf 		exit(EXIT_FAILURE);
979de9f7d1SSebastien Boeuf 	}
989de9f7d1SSebastien Boeuf 
999de9f7d1SSebastien Boeuf 	/* Notify the server that the client has finished */
1009de9f7d1SSebastien Boeuf 	control_writeln("DONE");
1019de9f7d1SSebastien Boeuf 
1029de9f7d1SSebastien Boeuf 	close(fd);
1039de9f7d1SSebastien Boeuf }
1049de9f7d1SSebastien Boeuf 
1059de9f7d1SSebastien Boeuf static void test_stream_bind_only_server(const struct test_opts *opts)
1069de9f7d1SSebastien Boeuf {
1079de9f7d1SSebastien Boeuf 	union {
1089de9f7d1SSebastien Boeuf 		struct sockaddr sa;
1099de9f7d1SSebastien Boeuf 		struct sockaddr_vm svm;
1109de9f7d1SSebastien Boeuf 	} addr = {
1119de9f7d1SSebastien Boeuf 		.svm = {
1129de9f7d1SSebastien Boeuf 			.svm_family = AF_VSOCK,
1139de9f7d1SSebastien Boeuf 			.svm_port = 1234,
1149de9f7d1SSebastien Boeuf 			.svm_cid = VMADDR_CID_ANY,
1159de9f7d1SSebastien Boeuf 		},
1169de9f7d1SSebastien Boeuf 	};
1179de9f7d1SSebastien Boeuf 	int fd;
1189de9f7d1SSebastien Boeuf 
1199de9f7d1SSebastien Boeuf 	fd = socket(AF_VSOCK, SOCK_STREAM, 0);
1209de9f7d1SSebastien Boeuf 
1219de9f7d1SSebastien Boeuf 	if (bind(fd, &addr.sa, sizeof(addr.svm)) < 0) {
1229de9f7d1SSebastien Boeuf 		perror("bind");
1239de9f7d1SSebastien Boeuf 		exit(EXIT_FAILURE);
1249de9f7d1SSebastien Boeuf 	}
1259de9f7d1SSebastien Boeuf 
1269de9f7d1SSebastien Boeuf 	/* Notify the client that the server is ready */
1279de9f7d1SSebastien Boeuf 	control_writeln("BIND");
1289de9f7d1SSebastien Boeuf 
1299de9f7d1SSebastien Boeuf 	/* Wait for the client to finish */
1309de9f7d1SSebastien Boeuf 	control_expectln("DONE");
1319de9f7d1SSebastien Boeuf 
1329de9f7d1SSebastien Boeuf 	close(fd);
1339de9f7d1SSebastien Boeuf }
1349de9f7d1SSebastien Boeuf 
135cdbcc18dSStefan Hajnoczi static void test_stream_client_close_client(const struct test_opts *opts)
136cdbcc18dSStefan Hajnoczi {
137cdbcc18dSStefan Hajnoczi 	int fd;
138cdbcc18dSStefan Hajnoczi 
139cdbcc18dSStefan Hajnoczi 	fd = vsock_stream_connect(opts->peer_cid, 1234);
140cdbcc18dSStefan Hajnoczi 	if (fd < 0) {
141cdbcc18dSStefan Hajnoczi 		perror("connect");
142cdbcc18dSStefan Hajnoczi 		exit(EXIT_FAILURE);
143cdbcc18dSStefan Hajnoczi 	}
144cdbcc18dSStefan Hajnoczi 
145cdbcc18dSStefan Hajnoczi 	send_byte(fd, 1, 0);
146cdbcc18dSStefan Hajnoczi 	close(fd);
147cdbcc18dSStefan Hajnoczi }
148cdbcc18dSStefan Hajnoczi 
149cdbcc18dSStefan Hajnoczi static void test_stream_client_close_server(const struct test_opts *opts)
150cdbcc18dSStefan Hajnoczi {
151cdbcc18dSStefan Hajnoczi 	int fd;
152cdbcc18dSStefan Hajnoczi 
153cdbcc18dSStefan Hajnoczi 	fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
154cdbcc18dSStefan Hajnoczi 	if (fd < 0) {
155cdbcc18dSStefan Hajnoczi 		perror("accept");
156cdbcc18dSStefan Hajnoczi 		exit(EXIT_FAILURE);
157cdbcc18dSStefan Hajnoczi 	}
158cdbcc18dSStefan Hajnoczi 
159770ce007SStefano Garzarella 	/* Wait for the remote to close the connection, before check
160770ce007SStefano Garzarella 	 * -EPIPE error on send.
161770ce007SStefano Garzarella 	 */
162770ce007SStefano Garzarella 	vsock_wait_remote_close(fd);
163cdbcc18dSStefan Hajnoczi 
164cdbcc18dSStefan Hajnoczi 	send_byte(fd, -EPIPE, 0);
165cdbcc18dSStefan Hajnoczi 	recv_byte(fd, 1, 0);
166cdbcc18dSStefan Hajnoczi 	recv_byte(fd, 0, 0);
167cdbcc18dSStefan Hajnoczi 	close(fd);
168cdbcc18dSStefan Hajnoczi }
169cdbcc18dSStefan Hajnoczi 
170cdbcc18dSStefan Hajnoczi static void test_stream_server_close_client(const struct test_opts *opts)
171cdbcc18dSStefan Hajnoczi {
172cdbcc18dSStefan Hajnoczi 	int fd;
173cdbcc18dSStefan Hajnoczi 
174cdbcc18dSStefan Hajnoczi 	fd = vsock_stream_connect(opts->peer_cid, 1234);
175cdbcc18dSStefan Hajnoczi 	if (fd < 0) {
176cdbcc18dSStefan Hajnoczi 		perror("connect");
177cdbcc18dSStefan Hajnoczi 		exit(EXIT_FAILURE);
178cdbcc18dSStefan Hajnoczi 	}
179cdbcc18dSStefan Hajnoczi 
180770ce007SStefano Garzarella 	/* Wait for the remote to close the connection, before check
181770ce007SStefano Garzarella 	 * -EPIPE error on send.
182770ce007SStefano Garzarella 	 */
183770ce007SStefano Garzarella 	vsock_wait_remote_close(fd);
184cdbcc18dSStefan Hajnoczi 
185cdbcc18dSStefan Hajnoczi 	send_byte(fd, -EPIPE, 0);
186cdbcc18dSStefan Hajnoczi 	recv_byte(fd, 1, 0);
187cdbcc18dSStefan Hajnoczi 	recv_byte(fd, 0, 0);
188cdbcc18dSStefan Hajnoczi 	close(fd);
189cdbcc18dSStefan Hajnoczi }
190cdbcc18dSStefan Hajnoczi 
191cdbcc18dSStefan Hajnoczi static void test_stream_server_close_server(const struct test_opts *opts)
192cdbcc18dSStefan Hajnoczi {
193cdbcc18dSStefan Hajnoczi 	int fd;
194cdbcc18dSStefan Hajnoczi 
195cdbcc18dSStefan Hajnoczi 	fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
196cdbcc18dSStefan Hajnoczi 	if (fd < 0) {
197cdbcc18dSStefan Hajnoczi 		perror("accept");
198cdbcc18dSStefan Hajnoczi 		exit(EXIT_FAILURE);
199cdbcc18dSStefan Hajnoczi 	}
200cdbcc18dSStefan Hajnoczi 
201cdbcc18dSStefan Hajnoczi 	send_byte(fd, 1, 0);
202cdbcc18dSStefan Hajnoczi 	close(fd);
203cdbcc18dSStefan Hajnoczi }
204cdbcc18dSStefan Hajnoczi 
205cdbcc18dSStefan Hajnoczi /* With the standard socket sizes, VMCI is able to support about 100
206cdbcc18dSStefan Hajnoczi  * concurrent stream connections.
207cdbcc18dSStefan Hajnoczi  */
208cdbcc18dSStefan Hajnoczi #define MULTICONN_NFDS 100
209cdbcc18dSStefan Hajnoczi 
210cdbcc18dSStefan Hajnoczi static void test_stream_multiconn_client(const struct test_opts *opts)
211cdbcc18dSStefan Hajnoczi {
212cdbcc18dSStefan Hajnoczi 	int fds[MULTICONN_NFDS];
213cdbcc18dSStefan Hajnoczi 	int i;
214cdbcc18dSStefan Hajnoczi 
215cdbcc18dSStefan Hajnoczi 	for (i = 0; i < MULTICONN_NFDS; i++) {
216cdbcc18dSStefan Hajnoczi 		fds[i] = vsock_stream_connect(opts->peer_cid, 1234);
217cdbcc18dSStefan Hajnoczi 		if (fds[i] < 0) {
218cdbcc18dSStefan Hajnoczi 			perror("connect");
219cdbcc18dSStefan Hajnoczi 			exit(EXIT_FAILURE);
220cdbcc18dSStefan Hajnoczi 		}
221cdbcc18dSStefan Hajnoczi 	}
222cdbcc18dSStefan Hajnoczi 
223cdbcc18dSStefan Hajnoczi 	for (i = 0; i < MULTICONN_NFDS; i++) {
224cdbcc18dSStefan Hajnoczi 		if (i % 2)
225cdbcc18dSStefan Hajnoczi 			recv_byte(fds[i], 1, 0);
226cdbcc18dSStefan Hajnoczi 		else
227cdbcc18dSStefan Hajnoczi 			send_byte(fds[i], 1, 0);
228cdbcc18dSStefan Hajnoczi 	}
229cdbcc18dSStefan Hajnoczi 
230cdbcc18dSStefan Hajnoczi 	for (i = 0; i < MULTICONN_NFDS; i++)
231cdbcc18dSStefan Hajnoczi 		close(fds[i]);
232cdbcc18dSStefan Hajnoczi }
233cdbcc18dSStefan Hajnoczi 
234cdbcc18dSStefan Hajnoczi static void test_stream_multiconn_server(const struct test_opts *opts)
235cdbcc18dSStefan Hajnoczi {
236cdbcc18dSStefan Hajnoczi 	int fds[MULTICONN_NFDS];
237cdbcc18dSStefan Hajnoczi 	int i;
238cdbcc18dSStefan Hajnoczi 
239cdbcc18dSStefan Hajnoczi 	for (i = 0; i < MULTICONN_NFDS; i++) {
240cdbcc18dSStefan Hajnoczi 		fds[i] = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
241cdbcc18dSStefan Hajnoczi 		if (fds[i] < 0) {
242cdbcc18dSStefan Hajnoczi 			perror("accept");
243cdbcc18dSStefan Hajnoczi 			exit(EXIT_FAILURE);
244cdbcc18dSStefan Hajnoczi 		}
245cdbcc18dSStefan Hajnoczi 	}
246cdbcc18dSStefan Hajnoczi 
247cdbcc18dSStefan Hajnoczi 	for (i = 0; i < MULTICONN_NFDS; i++) {
248cdbcc18dSStefan Hajnoczi 		if (i % 2)
249cdbcc18dSStefan Hajnoczi 			send_byte(fds[i], 1, 0);
250cdbcc18dSStefan Hajnoczi 		else
251cdbcc18dSStefan Hajnoczi 			recv_byte(fds[i], 1, 0);
252cdbcc18dSStefan Hajnoczi 	}
253cdbcc18dSStefan Hajnoczi 
254cdbcc18dSStefan Hajnoczi 	for (i = 0; i < MULTICONN_NFDS; i++)
255cdbcc18dSStefan Hajnoczi 		close(fds[i]);
256cdbcc18dSStefan Hajnoczi }
257cdbcc18dSStefan Hajnoczi 
258d6269a93SStefano Garzarella static void test_stream_msg_peek_client(const struct test_opts *opts)
259d6269a93SStefano Garzarella {
260d6269a93SStefano Garzarella 	int fd;
261d6269a93SStefano Garzarella 
262d6269a93SStefano Garzarella 	fd = vsock_stream_connect(opts->peer_cid, 1234);
263d6269a93SStefano Garzarella 	if (fd < 0) {
264d6269a93SStefano Garzarella 		perror("connect");
265d6269a93SStefano Garzarella 		exit(EXIT_FAILURE);
266d6269a93SStefano Garzarella 	}
267d6269a93SStefano Garzarella 
268d6269a93SStefano Garzarella 	send_byte(fd, 1, 0);
269d6269a93SStefano Garzarella 	close(fd);
270d6269a93SStefano Garzarella }
271d6269a93SStefano Garzarella 
272d6269a93SStefano Garzarella static void test_stream_msg_peek_server(const struct test_opts *opts)
273d6269a93SStefano Garzarella {
274d6269a93SStefano Garzarella 	int fd;
275d6269a93SStefano Garzarella 
276d6269a93SStefano Garzarella 	fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
277d6269a93SStefano Garzarella 	if (fd < 0) {
278d6269a93SStefano Garzarella 		perror("accept");
279d6269a93SStefano Garzarella 		exit(EXIT_FAILURE);
280d6269a93SStefano Garzarella 	}
281d6269a93SStefano Garzarella 
282d6269a93SStefano Garzarella 	recv_byte(fd, 1, MSG_PEEK);
283d6269a93SStefano Garzarella 	recv_byte(fd, 1, 0);
284d6269a93SStefano Garzarella 	close(fd);
285d6269a93SStefano Garzarella }
286d6269a93SStefano Garzarella 
2875c338112SArseniy Krasnov #define SOCK_BUF_SIZE (2 * 1024 * 1024)
2885c338112SArseniy Krasnov #define MAX_MSG_SIZE (32 * 1024)
2895c338112SArseniy Krasnov 
29041b792d7SArseny Krasnov static void test_seqpacket_msg_bounds_client(const struct test_opts *opts)
29141b792d7SArseny Krasnov {
2925c338112SArseniy Krasnov 	unsigned long curr_hash;
2935c338112SArseniy Krasnov 	int page_size;
2945c338112SArseniy Krasnov 	int msg_count;
29541b792d7SArseny Krasnov 	int fd;
29641b792d7SArseny Krasnov 
29741b792d7SArseny Krasnov 	fd = vsock_seqpacket_connect(opts->peer_cid, 1234);
29841b792d7SArseny Krasnov 	if (fd < 0) {
29941b792d7SArseny Krasnov 		perror("connect");
30041b792d7SArseny Krasnov 		exit(EXIT_FAILURE);
30141b792d7SArseny Krasnov 	}
30241b792d7SArseny Krasnov 
3035c338112SArseniy Krasnov 	/* Wait, until receiver sets buffer size. */
3045c338112SArseniy Krasnov 	control_expectln("SRVREADY");
3055c338112SArseniy Krasnov 
3065c338112SArseniy Krasnov 	curr_hash = 0;
3075c338112SArseniy Krasnov 	page_size = getpagesize();
3085c338112SArseniy Krasnov 	msg_count = SOCK_BUF_SIZE / MAX_MSG_SIZE;
3095c338112SArseniy Krasnov 
3105c338112SArseniy Krasnov 	for (int i = 0; i < msg_count; i++) {
3115c338112SArseniy Krasnov 		ssize_t send_size;
3125c338112SArseniy Krasnov 		size_t buf_size;
3135c338112SArseniy Krasnov 		int flags;
3145c338112SArseniy Krasnov 		void *buf;
3155c338112SArseniy Krasnov 
3165c338112SArseniy Krasnov 		/* Use "small" buffers and "big" buffers. */
3175c338112SArseniy Krasnov 		if (i & 1)
3185c338112SArseniy Krasnov 			buf_size = page_size +
3195c338112SArseniy Krasnov 					(rand() % (MAX_MSG_SIZE - page_size));
3205c338112SArseniy Krasnov 		else
3215c338112SArseniy Krasnov 			buf_size = 1 + (rand() % page_size);
3225c338112SArseniy Krasnov 
3235c338112SArseniy Krasnov 		buf = malloc(buf_size);
3245c338112SArseniy Krasnov 
3255c338112SArseniy Krasnov 		if (!buf) {
3265c338112SArseniy Krasnov 			perror("malloc");
3275c338112SArseniy Krasnov 			exit(EXIT_FAILURE);
3285c338112SArseniy Krasnov 		}
3295c338112SArseniy Krasnov 
3305c338112SArseniy Krasnov 		memset(buf, rand() & 0xff, buf_size);
3315c338112SArseniy Krasnov 		/* Set at least one MSG_EOR + some random. */
3325c338112SArseniy Krasnov 		if (i == (msg_count / 2) || (rand() & 1)) {
3335c338112SArseniy Krasnov 			flags = MSG_EOR;
3345c338112SArseniy Krasnov 			curr_hash++;
3355c338112SArseniy Krasnov 		} else {
3365c338112SArseniy Krasnov 			flags = 0;
3375c338112SArseniy Krasnov 		}
3385c338112SArseniy Krasnov 
3395c338112SArseniy Krasnov 		send_size = send(fd, buf, buf_size, flags);
3405c338112SArseniy Krasnov 
3415c338112SArseniy Krasnov 		if (send_size < 0) {
3425c338112SArseniy Krasnov 			perror("send");
3435c338112SArseniy Krasnov 			exit(EXIT_FAILURE);
3445c338112SArseniy Krasnov 		}
3455c338112SArseniy Krasnov 
3465c338112SArseniy Krasnov 		if (send_size != buf_size) {
3475c338112SArseniy Krasnov 			fprintf(stderr, "Invalid send size\n");
3485c338112SArseniy Krasnov 			exit(EXIT_FAILURE);
3495c338112SArseniy Krasnov 		}
3505c338112SArseniy Krasnov 
3515c338112SArseniy Krasnov 		/*
3525c338112SArseniy Krasnov 		 * Hash sum is computed at both client and server in
3535c338112SArseniy Krasnov 		 * the same way:
3545c338112SArseniy Krasnov 		 * H += hash('message data')
3555c338112SArseniy Krasnov 		 * Such hash "controls" both data integrity and message
3565c338112SArseniy Krasnov 		 * bounds. After data exchange, both sums are compared
3575c338112SArseniy Krasnov 		 * using control socket, and if message bounds wasn't
3585c338112SArseniy Krasnov 		 * broken - two values must be equal.
3595c338112SArseniy Krasnov 		 */
3605c338112SArseniy Krasnov 		curr_hash += hash_djb2(buf, buf_size);
3615c338112SArseniy Krasnov 		free(buf);
3625c338112SArseniy Krasnov 	}
36341b792d7SArseny Krasnov 
36441b792d7SArseny Krasnov 	control_writeln("SENDDONE");
3655c338112SArseniy Krasnov 	control_writeulong(curr_hash);
36641b792d7SArseny Krasnov 	close(fd);
36741b792d7SArseny Krasnov }
36841b792d7SArseny Krasnov 
36941b792d7SArseny Krasnov static void test_seqpacket_msg_bounds_server(const struct test_opts *opts)
37041b792d7SArseny Krasnov {
3715c338112SArseniy Krasnov 	unsigned long sock_buf_size;
3725c338112SArseniy Krasnov 	unsigned long remote_hash;
3735c338112SArseniy Krasnov 	unsigned long curr_hash;
37441b792d7SArseny Krasnov 	int fd;
3755c338112SArseniy Krasnov 	char buf[MAX_MSG_SIZE];
37641b792d7SArseny Krasnov 	struct msghdr msg = {0};
37741b792d7SArseny Krasnov 	struct iovec iov = {0};
37841b792d7SArseny Krasnov 
37941b792d7SArseny Krasnov 	fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL);
38041b792d7SArseny Krasnov 	if (fd < 0) {
38141b792d7SArseny Krasnov 		perror("accept");
38241b792d7SArseny Krasnov 		exit(EXIT_FAILURE);
38341b792d7SArseny Krasnov 	}
38441b792d7SArseny Krasnov 
3855c338112SArseniy Krasnov 	sock_buf_size = SOCK_BUF_SIZE;
3865c338112SArseniy Krasnov 
3875c338112SArseniy Krasnov 	if (setsockopt(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_MAX_SIZE,
3885c338112SArseniy Krasnov 		       &sock_buf_size, sizeof(sock_buf_size))) {
3895c338112SArseniy Krasnov 		perror("setsockopt(SO_VM_SOCKETS_BUFFER_MAX_SIZE)");
3905c338112SArseniy Krasnov 		exit(EXIT_FAILURE);
3915c338112SArseniy Krasnov 	}
3925c338112SArseniy Krasnov 
3935c338112SArseniy Krasnov 	if (setsockopt(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_SIZE,
3945c338112SArseniy Krasnov 		       &sock_buf_size, sizeof(sock_buf_size))) {
3955c338112SArseniy Krasnov 		perror("setsockopt(SO_VM_SOCKETS_BUFFER_SIZE)");
3965c338112SArseniy Krasnov 		exit(EXIT_FAILURE);
3975c338112SArseniy Krasnov 	}
3985c338112SArseniy Krasnov 
3995c338112SArseniy Krasnov 	/* Ready to receive data. */
4005c338112SArseniy Krasnov 	control_writeln("SRVREADY");
4015c338112SArseniy Krasnov 	/* Wait, until peer sends whole data. */
40241b792d7SArseny Krasnov 	control_expectln("SENDDONE");
40341b792d7SArseny Krasnov 	iov.iov_base = buf;
40441b792d7SArseny Krasnov 	iov.iov_len = sizeof(buf);
40541b792d7SArseny Krasnov 	msg.msg_iov = &iov;
40641b792d7SArseny Krasnov 	msg.msg_iovlen = 1;
40741b792d7SArseny Krasnov 
4085c338112SArseniy Krasnov 	curr_hash = 0;
4095c338112SArseniy Krasnov 
4105c338112SArseniy Krasnov 	while (1) {
4115c338112SArseniy Krasnov 		ssize_t recv_size;
4125c338112SArseniy Krasnov 
4135c338112SArseniy Krasnov 		recv_size = recvmsg(fd, &msg, 0);
4145c338112SArseniy Krasnov 
4155c338112SArseniy Krasnov 		if (!recv_size)
4165c338112SArseniy Krasnov 			break;
4175c338112SArseniy Krasnov 
4185c338112SArseniy Krasnov 		if (recv_size < 0) {
4195c338112SArseniy Krasnov 			perror("recvmsg");
42041b792d7SArseny Krasnov 			exit(EXIT_FAILURE);
42141b792d7SArseny Krasnov 		}
4220e115c45SArseny Krasnov 
4235c338112SArseniy Krasnov 		if (msg.msg_flags & MSG_EOR)
4245c338112SArseniy Krasnov 			curr_hash++;
4255c338112SArseniy Krasnov 
4265c338112SArseniy Krasnov 		curr_hash += hash_djb2(msg.msg_iov[0].iov_base, recv_size);
42741b792d7SArseny Krasnov 	}
42841b792d7SArseny Krasnov 
42941b792d7SArseny Krasnov 	close(fd);
4305c338112SArseniy Krasnov 	remote_hash = control_readulong();
4315c338112SArseniy Krasnov 
4325c338112SArseniy Krasnov 	if (curr_hash != remote_hash) {
4335c338112SArseniy Krasnov 		fprintf(stderr, "Message bounds broken\n");
4345c338112SArseniy Krasnov 		exit(EXIT_FAILURE);
4355c338112SArseniy Krasnov 	}
43641b792d7SArseny Krasnov }
43741b792d7SArseny Krasnov 
43841b792d7SArseny Krasnov #define MESSAGE_TRUNC_SZ 32
43941b792d7SArseny Krasnov static void test_seqpacket_msg_trunc_client(const struct test_opts *opts)
44041b792d7SArseny Krasnov {
44141b792d7SArseny Krasnov 	int fd;
44241b792d7SArseny Krasnov 	char buf[MESSAGE_TRUNC_SZ];
44341b792d7SArseny Krasnov 
44441b792d7SArseny Krasnov 	fd = vsock_seqpacket_connect(opts->peer_cid, 1234);
44541b792d7SArseny Krasnov 	if (fd < 0) {
44641b792d7SArseny Krasnov 		perror("connect");
44741b792d7SArseny Krasnov 		exit(EXIT_FAILURE);
44841b792d7SArseny Krasnov 	}
44941b792d7SArseny Krasnov 
45041b792d7SArseny Krasnov 	if (send(fd, buf, sizeof(buf), 0) != sizeof(buf)) {
45141b792d7SArseny Krasnov 		perror("send failed");
45241b792d7SArseny Krasnov 		exit(EXIT_FAILURE);
45341b792d7SArseny Krasnov 	}
45441b792d7SArseny Krasnov 
45541b792d7SArseny Krasnov 	control_writeln("SENDDONE");
45641b792d7SArseny Krasnov 	close(fd);
45741b792d7SArseny Krasnov }
45841b792d7SArseny Krasnov 
45941b792d7SArseny Krasnov static void test_seqpacket_msg_trunc_server(const struct test_opts *opts)
46041b792d7SArseny Krasnov {
46141b792d7SArseny Krasnov 	int fd;
46241b792d7SArseny Krasnov 	char buf[MESSAGE_TRUNC_SZ / 2];
46341b792d7SArseny Krasnov 	struct msghdr msg = {0};
46441b792d7SArseny Krasnov 	struct iovec iov = {0};
46541b792d7SArseny Krasnov 
46641b792d7SArseny Krasnov 	fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL);
46741b792d7SArseny Krasnov 	if (fd < 0) {
46841b792d7SArseny Krasnov 		perror("accept");
46941b792d7SArseny Krasnov 		exit(EXIT_FAILURE);
47041b792d7SArseny Krasnov 	}
47141b792d7SArseny Krasnov 
47241b792d7SArseny Krasnov 	control_expectln("SENDDONE");
47341b792d7SArseny Krasnov 	iov.iov_base = buf;
47441b792d7SArseny Krasnov 	iov.iov_len = sizeof(buf);
47541b792d7SArseny Krasnov 	msg.msg_iov = &iov;
47641b792d7SArseny Krasnov 	msg.msg_iovlen = 1;
47741b792d7SArseny Krasnov 
47841b792d7SArseny Krasnov 	ssize_t ret = recvmsg(fd, &msg, MSG_TRUNC);
47941b792d7SArseny Krasnov 
48041b792d7SArseny Krasnov 	if (ret != MESSAGE_TRUNC_SZ) {
48141b792d7SArseny Krasnov 		printf("%zi\n", ret);
48241b792d7SArseny Krasnov 		perror("MSG_TRUNC doesn't work");
48341b792d7SArseny Krasnov 		exit(EXIT_FAILURE);
48441b792d7SArseny Krasnov 	}
48541b792d7SArseny Krasnov 
48641b792d7SArseny Krasnov 	if (!(msg.msg_flags & MSG_TRUNC)) {
48741b792d7SArseny Krasnov 		fprintf(stderr, "MSG_TRUNC expected\n");
48841b792d7SArseny Krasnov 		exit(EXIT_FAILURE);
48941b792d7SArseny Krasnov 	}
49041b792d7SArseny Krasnov 
49141b792d7SArseny Krasnov 	close(fd);
49241b792d7SArseny Krasnov }
49341b792d7SArseny Krasnov 
494efb3719fSKrasnov Arseniy Vladimirovich static time_t current_nsec(void)
495efb3719fSKrasnov Arseniy Vladimirovich {
496efb3719fSKrasnov Arseniy Vladimirovich 	struct timespec ts;
497efb3719fSKrasnov Arseniy Vladimirovich 
498efb3719fSKrasnov Arseniy Vladimirovich 	if (clock_gettime(CLOCK_REALTIME, &ts)) {
499efb3719fSKrasnov Arseniy Vladimirovich 		perror("clock_gettime(3) failed");
500efb3719fSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
501efb3719fSKrasnov Arseniy Vladimirovich 	}
502efb3719fSKrasnov Arseniy Vladimirovich 
503efb3719fSKrasnov Arseniy Vladimirovich 	return (ts.tv_sec * 1000000000ULL) + ts.tv_nsec;
504efb3719fSKrasnov Arseniy Vladimirovich }
505efb3719fSKrasnov Arseniy Vladimirovich 
506efb3719fSKrasnov Arseniy Vladimirovich #define RCVTIMEO_TIMEOUT_SEC 1
507efb3719fSKrasnov Arseniy Vladimirovich #define READ_OVERHEAD_NSEC 250000000 /* 0.25 sec */
508efb3719fSKrasnov Arseniy Vladimirovich 
509efb3719fSKrasnov Arseniy Vladimirovich static void test_seqpacket_timeout_client(const struct test_opts *opts)
510efb3719fSKrasnov Arseniy Vladimirovich {
511efb3719fSKrasnov Arseniy Vladimirovich 	int fd;
512efb3719fSKrasnov Arseniy Vladimirovich 	struct timeval tv;
513efb3719fSKrasnov Arseniy Vladimirovich 	char dummy;
514efb3719fSKrasnov Arseniy Vladimirovich 	time_t read_enter_ns;
515efb3719fSKrasnov Arseniy Vladimirovich 	time_t read_overhead_ns;
516efb3719fSKrasnov Arseniy Vladimirovich 
517efb3719fSKrasnov Arseniy Vladimirovich 	fd = vsock_seqpacket_connect(opts->peer_cid, 1234);
518efb3719fSKrasnov Arseniy Vladimirovich 	if (fd < 0) {
519efb3719fSKrasnov Arseniy Vladimirovich 		perror("connect");
520efb3719fSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
521efb3719fSKrasnov Arseniy Vladimirovich 	}
522efb3719fSKrasnov Arseniy Vladimirovich 
523efb3719fSKrasnov Arseniy Vladimirovich 	tv.tv_sec = RCVTIMEO_TIMEOUT_SEC;
524efb3719fSKrasnov Arseniy Vladimirovich 	tv.tv_usec = 0;
525efb3719fSKrasnov Arseniy Vladimirovich 
526efb3719fSKrasnov Arseniy Vladimirovich 	if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (void *)&tv, sizeof(tv)) == -1) {
5275c338112SArseniy Krasnov 		perror("setsockopt(SO_RCVTIMEO)");
528efb3719fSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
529efb3719fSKrasnov Arseniy Vladimirovich 	}
530efb3719fSKrasnov Arseniy Vladimirovich 
531efb3719fSKrasnov Arseniy Vladimirovich 	read_enter_ns = current_nsec();
532efb3719fSKrasnov Arseniy Vladimirovich 
533efb3719fSKrasnov Arseniy Vladimirovich 	if (read(fd, &dummy, sizeof(dummy)) != -1) {
534efb3719fSKrasnov Arseniy Vladimirovich 		fprintf(stderr,
535efb3719fSKrasnov Arseniy Vladimirovich 			"expected 'dummy' read(2) failure\n");
536efb3719fSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
537efb3719fSKrasnov Arseniy Vladimirovich 	}
538efb3719fSKrasnov Arseniy Vladimirovich 
539efb3719fSKrasnov Arseniy Vladimirovich 	if (errno != EAGAIN) {
540efb3719fSKrasnov Arseniy Vladimirovich 		perror("EAGAIN expected");
541efb3719fSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
542efb3719fSKrasnov Arseniy Vladimirovich 	}
543efb3719fSKrasnov Arseniy Vladimirovich 
544efb3719fSKrasnov Arseniy Vladimirovich 	read_overhead_ns = current_nsec() - read_enter_ns -
545efb3719fSKrasnov Arseniy Vladimirovich 			1000000000ULL * RCVTIMEO_TIMEOUT_SEC;
546efb3719fSKrasnov Arseniy Vladimirovich 
547efb3719fSKrasnov Arseniy Vladimirovich 	if (read_overhead_ns > READ_OVERHEAD_NSEC) {
548efb3719fSKrasnov Arseniy Vladimirovich 		fprintf(stderr,
549efb3719fSKrasnov Arseniy Vladimirovich 			"too much time in read(2), %lu > %i ns\n",
550efb3719fSKrasnov Arseniy Vladimirovich 			read_overhead_ns, READ_OVERHEAD_NSEC);
551efb3719fSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
552efb3719fSKrasnov Arseniy Vladimirovich 	}
553efb3719fSKrasnov Arseniy Vladimirovich 
554efb3719fSKrasnov Arseniy Vladimirovich 	control_writeln("WAITDONE");
555efb3719fSKrasnov Arseniy Vladimirovich 	close(fd);
556efb3719fSKrasnov Arseniy Vladimirovich }
557efb3719fSKrasnov Arseniy Vladimirovich 
558efb3719fSKrasnov Arseniy Vladimirovich static void test_seqpacket_timeout_server(const struct test_opts *opts)
559efb3719fSKrasnov Arseniy Vladimirovich {
560efb3719fSKrasnov Arseniy Vladimirovich 	int fd;
561efb3719fSKrasnov Arseniy Vladimirovich 
562efb3719fSKrasnov Arseniy Vladimirovich 	fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL);
563efb3719fSKrasnov Arseniy Vladimirovich 	if (fd < 0) {
564efb3719fSKrasnov Arseniy Vladimirovich 		perror("accept");
565efb3719fSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
566efb3719fSKrasnov Arseniy Vladimirovich 	}
567efb3719fSKrasnov Arseniy Vladimirovich 
568efb3719fSKrasnov Arseniy Vladimirovich 	control_expectln("WAITDONE");
569efb3719fSKrasnov Arseniy Vladimirovich 	close(fd);
570efb3719fSKrasnov Arseniy Vladimirovich }
571efb3719fSKrasnov Arseniy Vladimirovich 
572685a21c3SArseniy Krasnov static void test_seqpacket_bigmsg_client(const struct test_opts *opts)
573685a21c3SArseniy Krasnov {
574685a21c3SArseniy Krasnov 	unsigned long sock_buf_size;
575685a21c3SArseniy Krasnov 	ssize_t send_size;
576685a21c3SArseniy Krasnov 	socklen_t len;
577685a21c3SArseniy Krasnov 	void *data;
578685a21c3SArseniy Krasnov 	int fd;
579685a21c3SArseniy Krasnov 
580685a21c3SArseniy Krasnov 	len = sizeof(sock_buf_size);
581685a21c3SArseniy Krasnov 
582685a21c3SArseniy Krasnov 	fd = vsock_seqpacket_connect(opts->peer_cid, 1234);
583685a21c3SArseniy Krasnov 	if (fd < 0) {
584685a21c3SArseniy Krasnov 		perror("connect");
585685a21c3SArseniy Krasnov 		exit(EXIT_FAILURE);
586685a21c3SArseniy Krasnov 	}
587685a21c3SArseniy Krasnov 
588685a21c3SArseniy Krasnov 	if (getsockopt(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_SIZE,
589685a21c3SArseniy Krasnov 		       &sock_buf_size, &len)) {
590685a21c3SArseniy Krasnov 		perror("getsockopt");
591685a21c3SArseniy Krasnov 		exit(EXIT_FAILURE);
592685a21c3SArseniy Krasnov 	}
593685a21c3SArseniy Krasnov 
594685a21c3SArseniy Krasnov 	sock_buf_size++;
595685a21c3SArseniy Krasnov 
596685a21c3SArseniy Krasnov 	data = malloc(sock_buf_size);
597685a21c3SArseniy Krasnov 	if (!data) {
598685a21c3SArseniy Krasnov 		perror("malloc");
599685a21c3SArseniy Krasnov 		exit(EXIT_FAILURE);
600685a21c3SArseniy Krasnov 	}
601685a21c3SArseniy Krasnov 
602685a21c3SArseniy Krasnov 	send_size = send(fd, data, sock_buf_size, 0);
603685a21c3SArseniy Krasnov 	if (send_size != -1) {
604685a21c3SArseniy Krasnov 		fprintf(stderr, "expected 'send(2)' failure, got %zi\n",
605685a21c3SArseniy Krasnov 			send_size);
606685a21c3SArseniy Krasnov 		exit(EXIT_FAILURE);
607685a21c3SArseniy Krasnov 	}
608685a21c3SArseniy Krasnov 
609685a21c3SArseniy Krasnov 	if (errno != EMSGSIZE) {
610685a21c3SArseniy Krasnov 		fprintf(stderr, "expected EMSGSIZE in 'errno', got %i\n",
611685a21c3SArseniy Krasnov 			errno);
612685a21c3SArseniy Krasnov 		exit(EXIT_FAILURE);
613685a21c3SArseniy Krasnov 	}
614685a21c3SArseniy Krasnov 
615685a21c3SArseniy Krasnov 	control_writeln("CLISENT");
616685a21c3SArseniy Krasnov 
617685a21c3SArseniy Krasnov 	free(data);
618685a21c3SArseniy Krasnov 	close(fd);
619685a21c3SArseniy Krasnov }
620685a21c3SArseniy Krasnov 
621685a21c3SArseniy Krasnov static void test_seqpacket_bigmsg_server(const struct test_opts *opts)
622685a21c3SArseniy Krasnov {
623685a21c3SArseniy Krasnov 	int fd;
624685a21c3SArseniy Krasnov 
625685a21c3SArseniy Krasnov 	fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL);
626685a21c3SArseniy Krasnov 	if (fd < 0) {
627685a21c3SArseniy Krasnov 		perror("accept");
628685a21c3SArseniy Krasnov 		exit(EXIT_FAILURE);
629685a21c3SArseniy Krasnov 	}
630685a21c3SArseniy Krasnov 
631685a21c3SArseniy Krasnov 	control_expectln("CLISENT");
632685a21c3SArseniy Krasnov 
633685a21c3SArseniy Krasnov 	close(fd);
634685a21c3SArseniy Krasnov }
635685a21c3SArseniy Krasnov 
636e89600ebSKrasnov Arseniy Vladimirovich #define BUF_PATTERN_1 'a'
637e89600ebSKrasnov Arseniy Vladimirovich #define BUF_PATTERN_2 'b'
638e89600ebSKrasnov Arseniy Vladimirovich 
639e89600ebSKrasnov Arseniy Vladimirovich static void test_seqpacket_invalid_rec_buffer_client(const struct test_opts *opts)
640e89600ebSKrasnov Arseniy Vladimirovich {
641e89600ebSKrasnov Arseniy Vladimirovich 	int fd;
642e89600ebSKrasnov Arseniy Vladimirovich 	unsigned char *buf1;
643e89600ebSKrasnov Arseniy Vladimirovich 	unsigned char *buf2;
644e89600ebSKrasnov Arseniy Vladimirovich 	int buf_size = getpagesize() * 3;
645e89600ebSKrasnov Arseniy Vladimirovich 
646e89600ebSKrasnov Arseniy Vladimirovich 	fd = vsock_seqpacket_connect(opts->peer_cid, 1234);
647e89600ebSKrasnov Arseniy Vladimirovich 	if (fd < 0) {
648e89600ebSKrasnov Arseniy Vladimirovich 		perror("connect");
649e89600ebSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
650e89600ebSKrasnov Arseniy Vladimirovich 	}
651e89600ebSKrasnov Arseniy Vladimirovich 
652e89600ebSKrasnov Arseniy Vladimirovich 	buf1 = malloc(buf_size);
653e89600ebSKrasnov Arseniy Vladimirovich 	if (!buf1) {
654e89600ebSKrasnov Arseniy Vladimirovich 		perror("'malloc()' for 'buf1'");
655e89600ebSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
656e89600ebSKrasnov Arseniy Vladimirovich 	}
657e89600ebSKrasnov Arseniy Vladimirovich 
658e89600ebSKrasnov Arseniy Vladimirovich 	buf2 = malloc(buf_size);
659e89600ebSKrasnov Arseniy Vladimirovich 	if (!buf2) {
660e89600ebSKrasnov Arseniy Vladimirovich 		perror("'malloc()' for 'buf2'");
661e89600ebSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
662e89600ebSKrasnov Arseniy Vladimirovich 	}
663e89600ebSKrasnov Arseniy Vladimirovich 
664e89600ebSKrasnov Arseniy Vladimirovich 	memset(buf1, BUF_PATTERN_1, buf_size);
665e89600ebSKrasnov Arseniy Vladimirovich 	memset(buf2, BUF_PATTERN_2, buf_size);
666e89600ebSKrasnov Arseniy Vladimirovich 
667e89600ebSKrasnov Arseniy Vladimirovich 	if (send(fd, buf1, buf_size, 0) != buf_size) {
668e89600ebSKrasnov Arseniy Vladimirovich 		perror("send failed");
669e89600ebSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
670e89600ebSKrasnov Arseniy Vladimirovich 	}
671e89600ebSKrasnov Arseniy Vladimirovich 
672e89600ebSKrasnov Arseniy Vladimirovich 	if (send(fd, buf2, buf_size, 0) != buf_size) {
673e89600ebSKrasnov Arseniy Vladimirovich 		perror("send failed");
674e89600ebSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
675e89600ebSKrasnov Arseniy Vladimirovich 	}
676e89600ebSKrasnov Arseniy Vladimirovich 
677e89600ebSKrasnov Arseniy Vladimirovich 	close(fd);
678e89600ebSKrasnov Arseniy Vladimirovich }
679e89600ebSKrasnov Arseniy Vladimirovich 
680e89600ebSKrasnov Arseniy Vladimirovich static void test_seqpacket_invalid_rec_buffer_server(const struct test_opts *opts)
681e89600ebSKrasnov Arseniy Vladimirovich {
682e89600ebSKrasnov Arseniy Vladimirovich 	int fd;
683e89600ebSKrasnov Arseniy Vladimirovich 	unsigned char *broken_buf;
684e89600ebSKrasnov Arseniy Vladimirovich 	unsigned char *valid_buf;
685e89600ebSKrasnov Arseniy Vladimirovich 	int page_size = getpagesize();
686e89600ebSKrasnov Arseniy Vladimirovich 	int buf_size = page_size * 3;
687e89600ebSKrasnov Arseniy Vladimirovich 	ssize_t res;
688e89600ebSKrasnov Arseniy Vladimirovich 	int prot = PROT_READ | PROT_WRITE;
689e89600ebSKrasnov Arseniy Vladimirovich 	int flags = MAP_PRIVATE | MAP_ANONYMOUS;
690e89600ebSKrasnov Arseniy Vladimirovich 	int i;
691e89600ebSKrasnov Arseniy Vladimirovich 
692e89600ebSKrasnov Arseniy Vladimirovich 	fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL);
693e89600ebSKrasnov Arseniy Vladimirovich 	if (fd < 0) {
694e89600ebSKrasnov Arseniy Vladimirovich 		perror("accept");
695e89600ebSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
696e89600ebSKrasnov Arseniy Vladimirovich 	}
697e89600ebSKrasnov Arseniy Vladimirovich 
698e89600ebSKrasnov Arseniy Vladimirovich 	/* Setup first buffer. */
699e89600ebSKrasnov Arseniy Vladimirovich 	broken_buf = mmap(NULL, buf_size, prot, flags, -1, 0);
700e89600ebSKrasnov Arseniy Vladimirovich 	if (broken_buf == MAP_FAILED) {
701e89600ebSKrasnov Arseniy Vladimirovich 		perror("mmap for 'broken_buf'");
702e89600ebSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
703e89600ebSKrasnov Arseniy Vladimirovich 	}
704e89600ebSKrasnov Arseniy Vladimirovich 
705e89600ebSKrasnov Arseniy Vladimirovich 	/* Unmap "hole" in buffer. */
706e89600ebSKrasnov Arseniy Vladimirovich 	if (munmap(broken_buf + page_size, page_size)) {
707e89600ebSKrasnov Arseniy Vladimirovich 		perror("'broken_buf' setup");
708e89600ebSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
709e89600ebSKrasnov Arseniy Vladimirovich 	}
710e89600ebSKrasnov Arseniy Vladimirovich 
711e89600ebSKrasnov Arseniy Vladimirovich 	valid_buf = mmap(NULL, buf_size, prot, flags, -1, 0);
712e89600ebSKrasnov Arseniy Vladimirovich 	if (valid_buf == MAP_FAILED) {
713e89600ebSKrasnov Arseniy Vladimirovich 		perror("mmap for 'valid_buf'");
714e89600ebSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
715e89600ebSKrasnov Arseniy Vladimirovich 	}
716e89600ebSKrasnov Arseniy Vladimirovich 
717e89600ebSKrasnov Arseniy Vladimirovich 	/* Try to fill buffer with unmapped middle. */
718e89600ebSKrasnov Arseniy Vladimirovich 	res = read(fd, broken_buf, buf_size);
719e89600ebSKrasnov Arseniy Vladimirovich 	if (res != -1) {
720e89600ebSKrasnov Arseniy Vladimirovich 		fprintf(stderr,
721e89600ebSKrasnov Arseniy Vladimirovich 			"expected 'broken_buf' read(2) failure, got %zi\n",
722e89600ebSKrasnov Arseniy Vladimirovich 			res);
723e89600ebSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
724e89600ebSKrasnov Arseniy Vladimirovich 	}
725e89600ebSKrasnov Arseniy Vladimirovich 
726e89600ebSKrasnov Arseniy Vladimirovich 	if (errno != ENOMEM) {
727e89600ebSKrasnov Arseniy Vladimirovich 		perror("unexpected errno of 'broken_buf'");
728e89600ebSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
729e89600ebSKrasnov Arseniy Vladimirovich 	}
730e89600ebSKrasnov Arseniy Vladimirovich 
731e89600ebSKrasnov Arseniy Vladimirovich 	/* Try to fill valid buffer. */
732e89600ebSKrasnov Arseniy Vladimirovich 	res = read(fd, valid_buf, buf_size);
733e89600ebSKrasnov Arseniy Vladimirovich 	if (res < 0) {
734e89600ebSKrasnov Arseniy Vladimirovich 		perror("unexpected 'valid_buf' read(2) failure");
735e89600ebSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
736e89600ebSKrasnov Arseniy Vladimirovich 	}
737e89600ebSKrasnov Arseniy Vladimirovich 
738e89600ebSKrasnov Arseniy Vladimirovich 	if (res != buf_size) {
739e89600ebSKrasnov Arseniy Vladimirovich 		fprintf(stderr,
740e89600ebSKrasnov Arseniy Vladimirovich 			"invalid 'valid_buf' read(2), expected %i, got %zi\n",
741e89600ebSKrasnov Arseniy Vladimirovich 			buf_size, res);
742e89600ebSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
743e89600ebSKrasnov Arseniy Vladimirovich 	}
744e89600ebSKrasnov Arseniy Vladimirovich 
745e89600ebSKrasnov Arseniy Vladimirovich 	for (i = 0; i < buf_size; i++) {
746e89600ebSKrasnov Arseniy Vladimirovich 		if (valid_buf[i] != BUF_PATTERN_2) {
747e89600ebSKrasnov Arseniy Vladimirovich 			fprintf(stderr,
748e89600ebSKrasnov Arseniy Vladimirovich 				"invalid pattern for 'valid_buf' at %i, expected %hhX, got %hhX\n",
749e89600ebSKrasnov Arseniy Vladimirovich 				i, BUF_PATTERN_2, valid_buf[i]);
750e89600ebSKrasnov Arseniy Vladimirovich 			exit(EXIT_FAILURE);
751e89600ebSKrasnov Arseniy Vladimirovich 		}
752e89600ebSKrasnov Arseniy Vladimirovich 	}
753e89600ebSKrasnov Arseniy Vladimirovich 
754e89600ebSKrasnov Arseniy Vladimirovich 	/* Unmap buffers. */
755e89600ebSKrasnov Arseniy Vladimirovich 	munmap(broken_buf, page_size);
756e89600ebSKrasnov Arseniy Vladimirovich 	munmap(broken_buf + page_size * 2, page_size);
757e89600ebSKrasnov Arseniy Vladimirovich 	munmap(valid_buf, buf_size);
758e89600ebSKrasnov Arseniy Vladimirovich 	close(fd);
759e89600ebSKrasnov Arseniy Vladimirovich }
760e89600ebSKrasnov Arseniy Vladimirovich 
761b1346338SArseniy Krasnov #define RCVLOWAT_BUF_SIZE 128
762b1346338SArseniy Krasnov 
763b1346338SArseniy Krasnov static void test_stream_poll_rcvlowat_server(const struct test_opts *opts)
764b1346338SArseniy Krasnov {
765b1346338SArseniy Krasnov 	int fd;
766b1346338SArseniy Krasnov 	int i;
767b1346338SArseniy Krasnov 
768b1346338SArseniy Krasnov 	fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
769b1346338SArseniy Krasnov 	if (fd < 0) {
770b1346338SArseniy Krasnov 		perror("accept");
771b1346338SArseniy Krasnov 		exit(EXIT_FAILURE);
772b1346338SArseniy Krasnov 	}
773b1346338SArseniy Krasnov 
774b1346338SArseniy Krasnov 	/* Send 1 byte. */
775b1346338SArseniy Krasnov 	send_byte(fd, 1, 0);
776b1346338SArseniy Krasnov 
777b1346338SArseniy Krasnov 	control_writeln("SRVSENT");
778b1346338SArseniy Krasnov 
779b1346338SArseniy Krasnov 	/* Wait until client is ready to receive rest of data. */
780b1346338SArseniy Krasnov 	control_expectln("CLNSENT");
781b1346338SArseniy Krasnov 
782b1346338SArseniy Krasnov 	for (i = 0; i < RCVLOWAT_BUF_SIZE - 1; i++)
783b1346338SArseniy Krasnov 		send_byte(fd, 1, 0);
784b1346338SArseniy Krasnov 
785b1346338SArseniy Krasnov 	/* Keep socket in active state. */
786b1346338SArseniy Krasnov 	control_expectln("POLLDONE");
787b1346338SArseniy Krasnov 
788b1346338SArseniy Krasnov 	close(fd);
789b1346338SArseniy Krasnov }
790b1346338SArseniy Krasnov 
791b1346338SArseniy Krasnov static void test_stream_poll_rcvlowat_client(const struct test_opts *opts)
792b1346338SArseniy Krasnov {
793b1346338SArseniy Krasnov 	unsigned long lowat_val = RCVLOWAT_BUF_SIZE;
794b1346338SArseniy Krasnov 	char buf[RCVLOWAT_BUF_SIZE];
795b1346338SArseniy Krasnov 	struct pollfd fds;
796b1346338SArseniy Krasnov 	ssize_t read_res;
797b1346338SArseniy Krasnov 	short poll_flags;
798b1346338SArseniy Krasnov 	int fd;
799b1346338SArseniy Krasnov 
800b1346338SArseniy Krasnov 	fd = vsock_stream_connect(opts->peer_cid, 1234);
801b1346338SArseniy Krasnov 	if (fd < 0) {
802b1346338SArseniy Krasnov 		perror("connect");
803b1346338SArseniy Krasnov 		exit(EXIT_FAILURE);
804b1346338SArseniy Krasnov 	}
805b1346338SArseniy Krasnov 
806b1346338SArseniy Krasnov 	if (setsockopt(fd, SOL_SOCKET, SO_RCVLOWAT,
807b1346338SArseniy Krasnov 		       &lowat_val, sizeof(lowat_val))) {
8085c338112SArseniy Krasnov 		perror("setsockopt(SO_RCVLOWAT)");
809b1346338SArseniy Krasnov 		exit(EXIT_FAILURE);
810b1346338SArseniy Krasnov 	}
811b1346338SArseniy Krasnov 
812b1346338SArseniy Krasnov 	control_expectln("SRVSENT");
813b1346338SArseniy Krasnov 
814b1346338SArseniy Krasnov 	/* At this point, server sent 1 byte. */
815b1346338SArseniy Krasnov 	fds.fd = fd;
816b1346338SArseniy Krasnov 	poll_flags = POLLIN | POLLRDNORM;
817b1346338SArseniy Krasnov 	fds.events = poll_flags;
818b1346338SArseniy Krasnov 
819b1346338SArseniy Krasnov 	/* Try to wait for 1 sec. */
820b1346338SArseniy Krasnov 	if (poll(&fds, 1, 1000) < 0) {
821b1346338SArseniy Krasnov 		perror("poll");
822b1346338SArseniy Krasnov 		exit(EXIT_FAILURE);
823b1346338SArseniy Krasnov 	}
824b1346338SArseniy Krasnov 
825b1346338SArseniy Krasnov 	/* poll() must return nothing. */
826b1346338SArseniy Krasnov 	if (fds.revents) {
827b1346338SArseniy Krasnov 		fprintf(stderr, "Unexpected poll result %hx\n",
828b1346338SArseniy Krasnov 			fds.revents);
829b1346338SArseniy Krasnov 		exit(EXIT_FAILURE);
830b1346338SArseniy Krasnov 	}
831b1346338SArseniy Krasnov 
832b1346338SArseniy Krasnov 	/* Tell server to send rest of data. */
833b1346338SArseniy Krasnov 	control_writeln("CLNSENT");
834b1346338SArseniy Krasnov 
835b1346338SArseniy Krasnov 	/* Poll for data. */
836b1346338SArseniy Krasnov 	if (poll(&fds, 1, 10000) < 0) {
837b1346338SArseniy Krasnov 		perror("poll");
838b1346338SArseniy Krasnov 		exit(EXIT_FAILURE);
839b1346338SArseniy Krasnov 	}
840b1346338SArseniy Krasnov 
841b1346338SArseniy Krasnov 	/* Only these two bits are expected. */
842b1346338SArseniy Krasnov 	if (fds.revents != poll_flags) {
843b1346338SArseniy Krasnov 		fprintf(stderr, "Unexpected poll result %hx\n",
844b1346338SArseniy Krasnov 			fds.revents);
845b1346338SArseniy Krasnov 		exit(EXIT_FAILURE);
846b1346338SArseniy Krasnov 	}
847b1346338SArseniy Krasnov 
848b1346338SArseniy Krasnov 	/* Use MSG_DONTWAIT, if call is going to wait, EAGAIN
849b1346338SArseniy Krasnov 	 * will be returned.
850b1346338SArseniy Krasnov 	 */
851b1346338SArseniy Krasnov 	read_res = recv(fd, buf, sizeof(buf), MSG_DONTWAIT);
852b1346338SArseniy Krasnov 	if (read_res != RCVLOWAT_BUF_SIZE) {
853b1346338SArseniy Krasnov 		fprintf(stderr, "Unexpected recv result %zi\n",
854b1346338SArseniy Krasnov 			read_res);
855b1346338SArseniy Krasnov 		exit(EXIT_FAILURE);
856b1346338SArseniy Krasnov 	}
857b1346338SArseniy Krasnov 
858b1346338SArseniy Krasnov 	control_writeln("POLLDONE");
859b1346338SArseniy Krasnov 
860b1346338SArseniy Krasnov 	close(fd);
861b1346338SArseniy Krasnov }
862b1346338SArseniy Krasnov 
8637e699d2aSArseniy Krasnov #define INV_BUF_TEST_DATA_LEN 512
8647e699d2aSArseniy Krasnov 
8657e699d2aSArseniy Krasnov static void test_inv_buf_client(const struct test_opts *opts, bool stream)
8667e699d2aSArseniy Krasnov {
8677e699d2aSArseniy Krasnov 	unsigned char data[INV_BUF_TEST_DATA_LEN] = {0};
8687e699d2aSArseniy Krasnov 	ssize_t ret;
8697e699d2aSArseniy Krasnov 	int fd;
8707e699d2aSArseniy Krasnov 
8717e699d2aSArseniy Krasnov 	if (stream)
8727e699d2aSArseniy Krasnov 		fd = vsock_stream_connect(opts->peer_cid, 1234);
8737e699d2aSArseniy Krasnov 	else
8747e699d2aSArseniy Krasnov 		fd = vsock_seqpacket_connect(opts->peer_cid, 1234);
8757e699d2aSArseniy Krasnov 
8767e699d2aSArseniy Krasnov 	if (fd < 0) {
8777e699d2aSArseniy Krasnov 		perror("connect");
8787e699d2aSArseniy Krasnov 		exit(EXIT_FAILURE);
8797e699d2aSArseniy Krasnov 	}
8807e699d2aSArseniy Krasnov 
8817e699d2aSArseniy Krasnov 	control_expectln("SENDDONE");
8827e699d2aSArseniy Krasnov 
8837e699d2aSArseniy Krasnov 	/* Use invalid buffer here. */
8847e699d2aSArseniy Krasnov 	ret = recv(fd, NULL, sizeof(data), 0);
8857e699d2aSArseniy Krasnov 	if (ret != -1) {
8867e699d2aSArseniy Krasnov 		fprintf(stderr, "expected recv(2) failure, got %zi\n", ret);
8877e699d2aSArseniy Krasnov 		exit(EXIT_FAILURE);
8887e699d2aSArseniy Krasnov 	}
8897e699d2aSArseniy Krasnov 
8907e699d2aSArseniy Krasnov 	if (errno != ENOMEM) {
8917e699d2aSArseniy Krasnov 		fprintf(stderr, "unexpected recv(2) errno %d\n", errno);
8927e699d2aSArseniy Krasnov 		exit(EXIT_FAILURE);
8937e699d2aSArseniy Krasnov 	}
8947e699d2aSArseniy Krasnov 
8957e699d2aSArseniy Krasnov 	ret = recv(fd, data, sizeof(data), MSG_DONTWAIT);
8967e699d2aSArseniy Krasnov 
8977e699d2aSArseniy Krasnov 	if (stream) {
8987e699d2aSArseniy Krasnov 		/* For SOCK_STREAM we must continue reading. */
8997e699d2aSArseniy Krasnov 		if (ret != sizeof(data)) {
9007e699d2aSArseniy Krasnov 			fprintf(stderr, "expected recv(2) success, got %zi\n", ret);
9017e699d2aSArseniy Krasnov 			exit(EXIT_FAILURE);
9027e699d2aSArseniy Krasnov 		}
9037e699d2aSArseniy Krasnov 		/* Don't check errno in case of success. */
9047e699d2aSArseniy Krasnov 	} else {
9057e699d2aSArseniy Krasnov 		/* For SOCK_SEQPACKET socket's queue must be empty. */
9067e699d2aSArseniy Krasnov 		if (ret != -1) {
9077e699d2aSArseniy Krasnov 			fprintf(stderr, "expected recv(2) failure, got %zi\n", ret);
9087e699d2aSArseniy Krasnov 			exit(EXIT_FAILURE);
9097e699d2aSArseniy Krasnov 		}
9107e699d2aSArseniy Krasnov 
9117e699d2aSArseniy Krasnov 		if (errno != EAGAIN) {
9127e699d2aSArseniy Krasnov 			fprintf(stderr, "unexpected recv(2) errno %d\n", errno);
9137e699d2aSArseniy Krasnov 			exit(EXIT_FAILURE);
9147e699d2aSArseniy Krasnov 		}
9157e699d2aSArseniy Krasnov 	}
9167e699d2aSArseniy Krasnov 
9177e699d2aSArseniy Krasnov 	control_writeln("DONE");
9187e699d2aSArseniy Krasnov 
9197e699d2aSArseniy Krasnov 	close(fd);
9207e699d2aSArseniy Krasnov }
9217e699d2aSArseniy Krasnov 
9227e699d2aSArseniy Krasnov static void test_inv_buf_server(const struct test_opts *opts, bool stream)
9237e699d2aSArseniy Krasnov {
9247e699d2aSArseniy Krasnov 	unsigned char data[INV_BUF_TEST_DATA_LEN] = {0};
9257e699d2aSArseniy Krasnov 	ssize_t res;
9267e699d2aSArseniy Krasnov 	int fd;
9277e699d2aSArseniy Krasnov 
9287e699d2aSArseniy Krasnov 	if (stream)
9297e699d2aSArseniy Krasnov 		fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
9307e699d2aSArseniy Krasnov 	else
9317e699d2aSArseniy Krasnov 		fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL);
9327e699d2aSArseniy Krasnov 
9337e699d2aSArseniy Krasnov 	if (fd < 0) {
9347e699d2aSArseniy Krasnov 		perror("accept");
9357e699d2aSArseniy Krasnov 		exit(EXIT_FAILURE);
9367e699d2aSArseniy Krasnov 	}
9377e699d2aSArseniy Krasnov 
9387e699d2aSArseniy Krasnov 	res = send(fd, data, sizeof(data), 0);
9397e699d2aSArseniy Krasnov 	if (res != sizeof(data)) {
9407e699d2aSArseniy Krasnov 		fprintf(stderr, "unexpected send(2) result %zi\n", res);
9417e699d2aSArseniy Krasnov 		exit(EXIT_FAILURE);
9427e699d2aSArseniy Krasnov 	}
9437e699d2aSArseniy Krasnov 
9447e699d2aSArseniy Krasnov 	control_writeln("SENDDONE");
9457e699d2aSArseniy Krasnov 
9467e699d2aSArseniy Krasnov 	control_expectln("DONE");
9477e699d2aSArseniy Krasnov 
9487e699d2aSArseniy Krasnov 	close(fd);
9497e699d2aSArseniy Krasnov }
9507e699d2aSArseniy Krasnov 
9517e699d2aSArseniy Krasnov static void test_stream_inv_buf_client(const struct test_opts *opts)
9527e699d2aSArseniy Krasnov {
9537e699d2aSArseniy Krasnov 	test_inv_buf_client(opts, true);
9547e699d2aSArseniy Krasnov }
9557e699d2aSArseniy Krasnov 
9567e699d2aSArseniy Krasnov static void test_stream_inv_buf_server(const struct test_opts *opts)
9577e699d2aSArseniy Krasnov {
9587e699d2aSArseniy Krasnov 	test_inv_buf_server(opts, true);
9597e699d2aSArseniy Krasnov }
9607e699d2aSArseniy Krasnov 
9617e699d2aSArseniy Krasnov static void test_seqpacket_inv_buf_client(const struct test_opts *opts)
9627e699d2aSArseniy Krasnov {
9637e699d2aSArseniy Krasnov 	test_inv_buf_client(opts, false);
9647e699d2aSArseniy Krasnov }
9657e699d2aSArseniy Krasnov 
9667e699d2aSArseniy Krasnov static void test_seqpacket_inv_buf_server(const struct test_opts *opts)
9677e699d2aSArseniy Krasnov {
9687e699d2aSArseniy Krasnov 	test_inv_buf_server(opts, false);
9697e699d2aSArseniy Krasnov }
9707e699d2aSArseniy Krasnov 
971*25209a32SArseniy Krasnov #define HELLO_STR "HELLO"
972*25209a32SArseniy Krasnov #define WORLD_STR "WORLD"
973*25209a32SArseniy Krasnov 
974*25209a32SArseniy Krasnov static void test_stream_virtio_skb_merge_client(const struct test_opts *opts)
975*25209a32SArseniy Krasnov {
976*25209a32SArseniy Krasnov 	ssize_t res;
977*25209a32SArseniy Krasnov 	int fd;
978*25209a32SArseniy Krasnov 
979*25209a32SArseniy Krasnov 	fd = vsock_stream_connect(opts->peer_cid, 1234);
980*25209a32SArseniy Krasnov 	if (fd < 0) {
981*25209a32SArseniy Krasnov 		perror("connect");
982*25209a32SArseniy Krasnov 		exit(EXIT_FAILURE);
983*25209a32SArseniy Krasnov 	}
984*25209a32SArseniy Krasnov 
985*25209a32SArseniy Krasnov 	/* Send first skbuff. */
986*25209a32SArseniy Krasnov 	res = send(fd, HELLO_STR, strlen(HELLO_STR), 0);
987*25209a32SArseniy Krasnov 	if (res != strlen(HELLO_STR)) {
988*25209a32SArseniy Krasnov 		fprintf(stderr, "unexpected send(2) result %zi\n", res);
989*25209a32SArseniy Krasnov 		exit(EXIT_FAILURE);
990*25209a32SArseniy Krasnov 	}
991*25209a32SArseniy Krasnov 
992*25209a32SArseniy Krasnov 	control_writeln("SEND0");
993*25209a32SArseniy Krasnov 	/* Peer reads part of first skbuff. */
994*25209a32SArseniy Krasnov 	control_expectln("REPLY0");
995*25209a32SArseniy Krasnov 
996*25209a32SArseniy Krasnov 	/* Send second skbuff, it will be appended to the first. */
997*25209a32SArseniy Krasnov 	res = send(fd, WORLD_STR, strlen(WORLD_STR), 0);
998*25209a32SArseniy Krasnov 	if (res != strlen(WORLD_STR)) {
999*25209a32SArseniy Krasnov 		fprintf(stderr, "unexpected send(2) result %zi\n", res);
1000*25209a32SArseniy Krasnov 		exit(EXIT_FAILURE);
1001*25209a32SArseniy Krasnov 	}
1002*25209a32SArseniy Krasnov 
1003*25209a32SArseniy Krasnov 	control_writeln("SEND1");
1004*25209a32SArseniy Krasnov 	/* Peer reads merged skbuff packet. */
1005*25209a32SArseniy Krasnov 	control_expectln("REPLY1");
1006*25209a32SArseniy Krasnov 
1007*25209a32SArseniy Krasnov 	close(fd);
1008*25209a32SArseniy Krasnov }
1009*25209a32SArseniy Krasnov 
1010*25209a32SArseniy Krasnov static void test_stream_virtio_skb_merge_server(const struct test_opts *opts)
1011*25209a32SArseniy Krasnov {
1012*25209a32SArseniy Krasnov 	unsigned char buf[64];
1013*25209a32SArseniy Krasnov 	ssize_t res;
1014*25209a32SArseniy Krasnov 	int fd;
1015*25209a32SArseniy Krasnov 
1016*25209a32SArseniy Krasnov 	fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
1017*25209a32SArseniy Krasnov 	if (fd < 0) {
1018*25209a32SArseniy Krasnov 		perror("accept");
1019*25209a32SArseniy Krasnov 		exit(EXIT_FAILURE);
1020*25209a32SArseniy Krasnov 	}
1021*25209a32SArseniy Krasnov 
1022*25209a32SArseniy Krasnov 	control_expectln("SEND0");
1023*25209a32SArseniy Krasnov 
1024*25209a32SArseniy Krasnov 	/* Read skbuff partially. */
1025*25209a32SArseniy Krasnov 	res = recv(fd, buf, 2, 0);
1026*25209a32SArseniy Krasnov 	if (res != 2) {
1027*25209a32SArseniy Krasnov 		fprintf(stderr, "expected recv(2) returns 2 bytes, got %zi\n", res);
1028*25209a32SArseniy Krasnov 		exit(EXIT_FAILURE);
1029*25209a32SArseniy Krasnov 	}
1030*25209a32SArseniy Krasnov 
1031*25209a32SArseniy Krasnov 	control_writeln("REPLY0");
1032*25209a32SArseniy Krasnov 	control_expectln("SEND1");
1033*25209a32SArseniy Krasnov 
1034*25209a32SArseniy Krasnov 	res = recv(fd, buf + 2, sizeof(buf) - 2, 0);
1035*25209a32SArseniy Krasnov 	if (res != 8) {
1036*25209a32SArseniy Krasnov 		fprintf(stderr, "expected recv(2) returns 8 bytes, got %zi\n", res);
1037*25209a32SArseniy Krasnov 		exit(EXIT_FAILURE);
1038*25209a32SArseniy Krasnov 	}
1039*25209a32SArseniy Krasnov 
1040*25209a32SArseniy Krasnov 	res = recv(fd, buf, sizeof(buf) - 8 - 2, MSG_DONTWAIT);
1041*25209a32SArseniy Krasnov 	if (res != -1) {
1042*25209a32SArseniy Krasnov 		fprintf(stderr, "expected recv(2) failure, got %zi\n", res);
1043*25209a32SArseniy Krasnov 		exit(EXIT_FAILURE);
1044*25209a32SArseniy Krasnov 	}
1045*25209a32SArseniy Krasnov 
1046*25209a32SArseniy Krasnov 	if (memcmp(buf, HELLO_STR WORLD_STR, strlen(HELLO_STR WORLD_STR))) {
1047*25209a32SArseniy Krasnov 		fprintf(stderr, "pattern mismatch\n");
1048*25209a32SArseniy Krasnov 		exit(EXIT_FAILURE);
1049*25209a32SArseniy Krasnov 	}
1050*25209a32SArseniy Krasnov 
1051*25209a32SArseniy Krasnov 	control_writeln("REPLY1");
1052*25209a32SArseniy Krasnov 
1053*25209a32SArseniy Krasnov 	close(fd);
1054*25209a32SArseniy Krasnov }
1055*25209a32SArseniy Krasnov 
1056cdbcc18dSStefan Hajnoczi static struct test_case test_cases[] = {
1057cdbcc18dSStefan Hajnoczi 	{
1058cdbcc18dSStefan Hajnoczi 		.name = "SOCK_STREAM connection reset",
1059cdbcc18dSStefan Hajnoczi 		.run_client = test_stream_connection_reset,
1060cdbcc18dSStefan Hajnoczi 	},
1061cdbcc18dSStefan Hajnoczi 	{
10629de9f7d1SSebastien Boeuf 		.name = "SOCK_STREAM bind only",
10639de9f7d1SSebastien Boeuf 		.run_client = test_stream_bind_only_client,
10649de9f7d1SSebastien Boeuf 		.run_server = test_stream_bind_only_server,
10659de9f7d1SSebastien Boeuf 	},
10669de9f7d1SSebastien Boeuf 	{
1067cdbcc18dSStefan Hajnoczi 		.name = "SOCK_STREAM client close",
1068cdbcc18dSStefan Hajnoczi 		.run_client = test_stream_client_close_client,
1069cdbcc18dSStefan Hajnoczi 		.run_server = test_stream_client_close_server,
1070cdbcc18dSStefan Hajnoczi 	},
1071cdbcc18dSStefan Hajnoczi 	{
1072cdbcc18dSStefan Hajnoczi 		.name = "SOCK_STREAM server close",
1073cdbcc18dSStefan Hajnoczi 		.run_client = test_stream_server_close_client,
1074cdbcc18dSStefan Hajnoczi 		.run_server = test_stream_server_close_server,
1075cdbcc18dSStefan Hajnoczi 	},
1076cdbcc18dSStefan Hajnoczi 	{
1077cdbcc18dSStefan Hajnoczi 		.name = "SOCK_STREAM multiple connections",
1078cdbcc18dSStefan Hajnoczi 		.run_client = test_stream_multiconn_client,
1079cdbcc18dSStefan Hajnoczi 		.run_server = test_stream_multiconn_server,
1080cdbcc18dSStefan Hajnoczi 	},
1081d6269a93SStefano Garzarella 	{
1082d6269a93SStefano Garzarella 		.name = "SOCK_STREAM MSG_PEEK",
1083d6269a93SStefano Garzarella 		.run_client = test_stream_msg_peek_client,
1084d6269a93SStefano Garzarella 		.run_server = test_stream_msg_peek_server,
1085d6269a93SStefano Garzarella 	},
108641b792d7SArseny Krasnov 	{
108741b792d7SArseny Krasnov 		.name = "SOCK_SEQPACKET msg bounds",
108841b792d7SArseny Krasnov 		.run_client = test_seqpacket_msg_bounds_client,
108941b792d7SArseny Krasnov 		.run_server = test_seqpacket_msg_bounds_server,
109041b792d7SArseny Krasnov 	},
109141b792d7SArseny Krasnov 	{
109241b792d7SArseny Krasnov 		.name = "SOCK_SEQPACKET MSG_TRUNC flag",
109341b792d7SArseny Krasnov 		.run_client = test_seqpacket_msg_trunc_client,
109441b792d7SArseny Krasnov 		.run_server = test_seqpacket_msg_trunc_server,
109541b792d7SArseny Krasnov 	},
1096efb3719fSKrasnov Arseniy Vladimirovich 	{
1097efb3719fSKrasnov Arseniy Vladimirovich 		.name = "SOCK_SEQPACKET timeout",
1098efb3719fSKrasnov Arseniy Vladimirovich 		.run_client = test_seqpacket_timeout_client,
1099efb3719fSKrasnov Arseniy Vladimirovich 		.run_server = test_seqpacket_timeout_server,
1100efb3719fSKrasnov Arseniy Vladimirovich 	},
1101e89600ebSKrasnov Arseniy Vladimirovich 	{
1102e89600ebSKrasnov Arseniy Vladimirovich 		.name = "SOCK_SEQPACKET invalid receive buffer",
1103e89600ebSKrasnov Arseniy Vladimirovich 		.run_client = test_seqpacket_invalid_rec_buffer_client,
1104e89600ebSKrasnov Arseniy Vladimirovich 		.run_server = test_seqpacket_invalid_rec_buffer_server,
1105e89600ebSKrasnov Arseniy Vladimirovich 	},
1106b1346338SArseniy Krasnov 	{
1107b1346338SArseniy Krasnov 		.name = "SOCK_STREAM poll() + SO_RCVLOWAT",
1108b1346338SArseniy Krasnov 		.run_client = test_stream_poll_rcvlowat_client,
1109b1346338SArseniy Krasnov 		.run_server = test_stream_poll_rcvlowat_server,
1110b1346338SArseniy Krasnov 	},
1111685a21c3SArseniy Krasnov 	{
1112685a21c3SArseniy Krasnov 		.name = "SOCK_SEQPACKET big message",
1113685a21c3SArseniy Krasnov 		.run_client = test_seqpacket_bigmsg_client,
1114685a21c3SArseniy Krasnov 		.run_server = test_seqpacket_bigmsg_server,
1115685a21c3SArseniy Krasnov 	},
11167e699d2aSArseniy Krasnov 	{
11177e699d2aSArseniy Krasnov 		.name = "SOCK_STREAM test invalid buffer",
11187e699d2aSArseniy Krasnov 		.run_client = test_stream_inv_buf_client,
11197e699d2aSArseniy Krasnov 		.run_server = test_stream_inv_buf_server,
11207e699d2aSArseniy Krasnov 	},
11217e699d2aSArseniy Krasnov 	{
11227e699d2aSArseniy Krasnov 		.name = "SOCK_SEQPACKET test invalid buffer",
11237e699d2aSArseniy Krasnov 		.run_client = test_seqpacket_inv_buf_client,
11247e699d2aSArseniy Krasnov 		.run_server = test_seqpacket_inv_buf_server,
11257e699d2aSArseniy Krasnov 	},
1126*25209a32SArseniy Krasnov 	{
1127*25209a32SArseniy Krasnov 		.name = "SOCK_STREAM virtio skb merge",
1128*25209a32SArseniy Krasnov 		.run_client = test_stream_virtio_skb_merge_client,
1129*25209a32SArseniy Krasnov 		.run_server = test_stream_virtio_skb_merge_server,
1130*25209a32SArseniy Krasnov 	},
1131cdbcc18dSStefan Hajnoczi 	{},
1132cdbcc18dSStefan Hajnoczi };
1133cdbcc18dSStefan Hajnoczi 
1134cdbcc18dSStefan Hajnoczi static const char optstring[] = "";
1135cdbcc18dSStefan Hajnoczi static const struct option longopts[] = {
1136cdbcc18dSStefan Hajnoczi 	{
1137cdbcc18dSStefan Hajnoczi 		.name = "control-host",
1138cdbcc18dSStefan Hajnoczi 		.has_arg = required_argument,
1139cdbcc18dSStefan Hajnoczi 		.val = 'H',
1140cdbcc18dSStefan Hajnoczi 	},
1141cdbcc18dSStefan Hajnoczi 	{
1142cdbcc18dSStefan Hajnoczi 		.name = "control-port",
1143cdbcc18dSStefan Hajnoczi 		.has_arg = required_argument,
1144cdbcc18dSStefan Hajnoczi 		.val = 'P',
1145cdbcc18dSStefan Hajnoczi 	},
1146cdbcc18dSStefan Hajnoczi 	{
1147cdbcc18dSStefan Hajnoczi 		.name = "mode",
1148cdbcc18dSStefan Hajnoczi 		.has_arg = required_argument,
1149cdbcc18dSStefan Hajnoczi 		.val = 'm',
1150cdbcc18dSStefan Hajnoczi 	},
1151cdbcc18dSStefan Hajnoczi 	{
1152cdbcc18dSStefan Hajnoczi 		.name = "peer-cid",
1153cdbcc18dSStefan Hajnoczi 		.has_arg = required_argument,
1154cdbcc18dSStefan Hajnoczi 		.val = 'p',
1155cdbcc18dSStefan Hajnoczi 	},
1156cdbcc18dSStefan Hajnoczi 	{
11575a2b2425SStefano Garzarella 		.name = "list",
11585a2b2425SStefano Garzarella 		.has_arg = no_argument,
11595a2b2425SStefano Garzarella 		.val = 'l',
11605a2b2425SStefano Garzarella 	},
11615a2b2425SStefano Garzarella 	{
11625a2b2425SStefano Garzarella 		.name = "skip",
11635a2b2425SStefano Garzarella 		.has_arg = required_argument,
11645a2b2425SStefano Garzarella 		.val = 's',
11655a2b2425SStefano Garzarella 	},
11665a2b2425SStefano Garzarella 	{
1167cdbcc18dSStefan Hajnoczi 		.name = "help",
1168cdbcc18dSStefan Hajnoczi 		.has_arg = no_argument,
1169cdbcc18dSStefan Hajnoczi 		.val = '?',
1170cdbcc18dSStefan Hajnoczi 	},
1171cdbcc18dSStefan Hajnoczi 	{},
1172cdbcc18dSStefan Hajnoczi };
1173cdbcc18dSStefan Hajnoczi 
1174cdbcc18dSStefan Hajnoczi static void usage(void)
1175cdbcc18dSStefan Hajnoczi {
11765a2b2425SStefano Garzarella 	fprintf(stderr, "Usage: vsock_test [--help] [--control-host=<host>] --control-port=<port> --mode=client|server --peer-cid=<cid> [--list] [--skip=<test_id>]\n"
1177cdbcc18dSStefan Hajnoczi 		"\n"
1178cdbcc18dSStefan Hajnoczi 		"  Server: vsock_test --control-port=1234 --mode=server --peer-cid=3\n"
1179cdbcc18dSStefan Hajnoczi 		"  Client: vsock_test --control-host=192.168.0.1 --control-port=1234 --mode=client --peer-cid=2\n"
1180cdbcc18dSStefan Hajnoczi 		"\n"
1181cdbcc18dSStefan Hajnoczi 		"Run vsock.ko tests.  Must be launched in both guest\n"
1182cdbcc18dSStefan Hajnoczi 		"and host.  One side must use --mode=client and\n"
1183cdbcc18dSStefan Hajnoczi 		"the other side must use --mode=server.\n"
1184cdbcc18dSStefan Hajnoczi 		"\n"
1185cdbcc18dSStefan Hajnoczi 		"A TCP control socket connection is used to coordinate tests\n"
1186cdbcc18dSStefan Hajnoczi 		"between the client and the server.  The server requires a\n"
1187cdbcc18dSStefan Hajnoczi 		"listen address and the client requires an address to\n"
1188cdbcc18dSStefan Hajnoczi 		"connect to.\n"
1189cdbcc18dSStefan Hajnoczi 		"\n"
11908d00b93fSStefano Garzarella 		"The CID of the other side must be given with --peer-cid=<cid>.\n"
11918d00b93fSStefano Garzarella 		"\n"
11928d00b93fSStefano Garzarella 		"Options:\n"
11938d00b93fSStefano Garzarella 		"  --help                 This help message\n"
11948d00b93fSStefano Garzarella 		"  --control-host <host>  Server IP address to connect to\n"
11958d00b93fSStefano Garzarella 		"  --control-port <port>  Server port to listen on/connect to\n"
11968d00b93fSStefano Garzarella 		"  --mode client|server   Server or client mode\n"
11978d00b93fSStefano Garzarella 		"  --peer-cid <cid>       CID of the other side\n"
11988d00b93fSStefano Garzarella 		"  --list                 List of tests that will be executed\n"
11998d00b93fSStefano Garzarella 		"  --skip <test_id>       Test ID to skip;\n"
12008d00b93fSStefano Garzarella 		"                         use multiple --skip options to skip more tests\n"
12018d00b93fSStefano Garzarella 		);
1202cdbcc18dSStefan Hajnoczi 	exit(EXIT_FAILURE);
1203cdbcc18dSStefan Hajnoczi }
1204cdbcc18dSStefan Hajnoczi 
1205cdbcc18dSStefan Hajnoczi int main(int argc, char **argv)
1206cdbcc18dSStefan Hajnoczi {
1207cdbcc18dSStefan Hajnoczi 	const char *control_host = NULL;
1208cdbcc18dSStefan Hajnoczi 	const char *control_port = NULL;
1209cdbcc18dSStefan Hajnoczi 	struct test_opts opts = {
1210cdbcc18dSStefan Hajnoczi 		.mode = TEST_MODE_UNSET,
1211cdbcc18dSStefan Hajnoczi 		.peer_cid = VMADDR_CID_ANY,
1212cdbcc18dSStefan Hajnoczi 	};
1213cdbcc18dSStefan Hajnoczi 
12145c338112SArseniy Krasnov 	srand(time(NULL));
1215cdbcc18dSStefan Hajnoczi 	init_signals();
1216cdbcc18dSStefan Hajnoczi 
1217cdbcc18dSStefan Hajnoczi 	for (;;) {
1218cdbcc18dSStefan Hajnoczi 		int opt = getopt_long(argc, argv, optstring, longopts, NULL);
1219cdbcc18dSStefan Hajnoczi 
1220cdbcc18dSStefan Hajnoczi 		if (opt == -1)
1221cdbcc18dSStefan Hajnoczi 			break;
1222cdbcc18dSStefan Hajnoczi 
1223cdbcc18dSStefan Hajnoczi 		switch (opt) {
1224cdbcc18dSStefan Hajnoczi 		case 'H':
1225cdbcc18dSStefan Hajnoczi 			control_host = optarg;
1226cdbcc18dSStefan Hajnoczi 			break;
1227cdbcc18dSStefan Hajnoczi 		case 'm':
1228cdbcc18dSStefan Hajnoczi 			if (strcmp(optarg, "client") == 0)
1229cdbcc18dSStefan Hajnoczi 				opts.mode = TEST_MODE_CLIENT;
1230cdbcc18dSStefan Hajnoczi 			else if (strcmp(optarg, "server") == 0)
1231cdbcc18dSStefan Hajnoczi 				opts.mode = TEST_MODE_SERVER;
1232cdbcc18dSStefan Hajnoczi 			else {
1233cdbcc18dSStefan Hajnoczi 				fprintf(stderr, "--mode must be \"client\" or \"server\"\n");
1234cdbcc18dSStefan Hajnoczi 				return EXIT_FAILURE;
1235cdbcc18dSStefan Hajnoczi 			}
1236cdbcc18dSStefan Hajnoczi 			break;
1237cdbcc18dSStefan Hajnoczi 		case 'p':
1238cdbcc18dSStefan Hajnoczi 			opts.peer_cid = parse_cid(optarg);
1239cdbcc18dSStefan Hajnoczi 			break;
1240cdbcc18dSStefan Hajnoczi 		case 'P':
1241cdbcc18dSStefan Hajnoczi 			control_port = optarg;
1242cdbcc18dSStefan Hajnoczi 			break;
12435a2b2425SStefano Garzarella 		case 'l':
12445a2b2425SStefano Garzarella 			list_tests(test_cases);
12455a2b2425SStefano Garzarella 			break;
12465a2b2425SStefano Garzarella 		case 's':
12475a2b2425SStefano Garzarella 			skip_test(test_cases, ARRAY_SIZE(test_cases) - 1,
12485a2b2425SStefano Garzarella 				  optarg);
12495a2b2425SStefano Garzarella 			break;
1250cdbcc18dSStefan Hajnoczi 		case '?':
1251cdbcc18dSStefan Hajnoczi 		default:
1252cdbcc18dSStefan Hajnoczi 			usage();
1253cdbcc18dSStefan Hajnoczi 		}
1254cdbcc18dSStefan Hajnoczi 	}
1255cdbcc18dSStefan Hajnoczi 
1256cdbcc18dSStefan Hajnoczi 	if (!control_port)
1257cdbcc18dSStefan Hajnoczi 		usage();
1258cdbcc18dSStefan Hajnoczi 	if (opts.mode == TEST_MODE_UNSET)
1259cdbcc18dSStefan Hajnoczi 		usage();
1260cdbcc18dSStefan Hajnoczi 	if (opts.peer_cid == VMADDR_CID_ANY)
1261cdbcc18dSStefan Hajnoczi 		usage();
1262cdbcc18dSStefan Hajnoczi 
1263cdbcc18dSStefan Hajnoczi 	if (!control_host) {
1264cdbcc18dSStefan Hajnoczi 		if (opts.mode != TEST_MODE_SERVER)
1265cdbcc18dSStefan Hajnoczi 			usage();
1266cdbcc18dSStefan Hajnoczi 		control_host = "0.0.0.0";
1267cdbcc18dSStefan Hajnoczi 	}
1268cdbcc18dSStefan Hajnoczi 
1269cdbcc18dSStefan Hajnoczi 	control_init(control_host, control_port,
1270cdbcc18dSStefan Hajnoczi 		     opts.mode == TEST_MODE_SERVER);
1271cdbcc18dSStefan Hajnoczi 
1272cdbcc18dSStefan Hajnoczi 	run_tests(test_cases, &opts);
1273cdbcc18dSStefan Hajnoczi 
1274cdbcc18dSStefan Hajnoczi 	control_cleanup();
1275cdbcc18dSStefan Hajnoczi 	return EXIT_SUCCESS;
1276cdbcc18dSStefan Hajnoczi }
1277