xref: /openbmc/linux/tools/testing/vsock/vsock_test.c (revision 587ed79f)
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 
258*587ed79fSArseniy Krasnov #define MSG_PEEK_BUF_LEN 64
259*587ed79fSArseniy Krasnov 
260d6269a93SStefano Garzarella static void test_stream_msg_peek_client(const struct test_opts *opts)
261d6269a93SStefano Garzarella {
262*587ed79fSArseniy Krasnov 	unsigned char buf[MSG_PEEK_BUF_LEN];
263*587ed79fSArseniy Krasnov 	ssize_t send_size;
264d6269a93SStefano Garzarella 	int fd;
265*587ed79fSArseniy Krasnov 	int i;
266d6269a93SStefano Garzarella 
267d6269a93SStefano Garzarella 	fd = vsock_stream_connect(opts->peer_cid, 1234);
268d6269a93SStefano Garzarella 	if (fd < 0) {
269d6269a93SStefano Garzarella 		perror("connect");
270d6269a93SStefano Garzarella 		exit(EXIT_FAILURE);
271d6269a93SStefano Garzarella 	}
272d6269a93SStefano Garzarella 
273*587ed79fSArseniy Krasnov 	for (i = 0; i < sizeof(buf); i++)
274*587ed79fSArseniy Krasnov 		buf[i] = rand() & 0xFF;
275*587ed79fSArseniy Krasnov 
276*587ed79fSArseniy Krasnov 	control_expectln("SRVREADY");
277*587ed79fSArseniy Krasnov 
278*587ed79fSArseniy Krasnov 	send_size = send(fd, buf, sizeof(buf), 0);
279*587ed79fSArseniy Krasnov 
280*587ed79fSArseniy Krasnov 	if (send_size < 0) {
281*587ed79fSArseniy Krasnov 		perror("send");
282*587ed79fSArseniy Krasnov 		exit(EXIT_FAILURE);
283*587ed79fSArseniy Krasnov 	}
284*587ed79fSArseniy Krasnov 
285*587ed79fSArseniy Krasnov 	if (send_size != sizeof(buf)) {
286*587ed79fSArseniy Krasnov 		fprintf(stderr, "Invalid send size %zi\n", send_size);
287*587ed79fSArseniy Krasnov 		exit(EXIT_FAILURE);
288*587ed79fSArseniy Krasnov 	}
289*587ed79fSArseniy Krasnov 
290d6269a93SStefano Garzarella 	close(fd);
291d6269a93SStefano Garzarella }
292d6269a93SStefano Garzarella 
293d6269a93SStefano Garzarella static void test_stream_msg_peek_server(const struct test_opts *opts)
294d6269a93SStefano Garzarella {
295*587ed79fSArseniy Krasnov 	unsigned char buf_half[MSG_PEEK_BUF_LEN / 2];
296*587ed79fSArseniy Krasnov 	unsigned char buf_normal[MSG_PEEK_BUF_LEN];
297*587ed79fSArseniy Krasnov 	unsigned char buf_peek[MSG_PEEK_BUF_LEN];
298*587ed79fSArseniy Krasnov 	ssize_t res;
299d6269a93SStefano Garzarella 	int fd;
300d6269a93SStefano Garzarella 
301d6269a93SStefano Garzarella 	fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
302d6269a93SStefano Garzarella 	if (fd < 0) {
303d6269a93SStefano Garzarella 		perror("accept");
304d6269a93SStefano Garzarella 		exit(EXIT_FAILURE);
305d6269a93SStefano Garzarella 	}
306d6269a93SStefano Garzarella 
307*587ed79fSArseniy Krasnov 	/* Peek from empty socket. */
308*587ed79fSArseniy Krasnov 	res = recv(fd, buf_peek, sizeof(buf_peek), MSG_PEEK | MSG_DONTWAIT);
309*587ed79fSArseniy Krasnov 	if (res != -1) {
310*587ed79fSArseniy Krasnov 		fprintf(stderr, "expected recv(2) failure, got %zi\n", res);
311*587ed79fSArseniy Krasnov 		exit(EXIT_FAILURE);
312*587ed79fSArseniy Krasnov 	}
313*587ed79fSArseniy Krasnov 
314*587ed79fSArseniy Krasnov 	if (errno != EAGAIN) {
315*587ed79fSArseniy Krasnov 		perror("EAGAIN expected");
316*587ed79fSArseniy Krasnov 		exit(EXIT_FAILURE);
317*587ed79fSArseniy Krasnov 	}
318*587ed79fSArseniy Krasnov 
319*587ed79fSArseniy Krasnov 	control_writeln("SRVREADY");
320*587ed79fSArseniy Krasnov 
321*587ed79fSArseniy Krasnov 	/* Peek part of data. */
322*587ed79fSArseniy Krasnov 	res = recv(fd, buf_half, sizeof(buf_half), MSG_PEEK);
323*587ed79fSArseniy Krasnov 	if (res != sizeof(buf_half)) {
324*587ed79fSArseniy Krasnov 		fprintf(stderr, "recv(2) + MSG_PEEK, expected %zu, got %zi\n",
325*587ed79fSArseniy Krasnov 			sizeof(buf_half), res);
326*587ed79fSArseniy Krasnov 		exit(EXIT_FAILURE);
327*587ed79fSArseniy Krasnov 	}
328*587ed79fSArseniy Krasnov 
329*587ed79fSArseniy Krasnov 	/* Peek whole data. */
330*587ed79fSArseniy Krasnov 	res = recv(fd, buf_peek, sizeof(buf_peek), MSG_PEEK);
331*587ed79fSArseniy Krasnov 	if (res != sizeof(buf_peek)) {
332*587ed79fSArseniy Krasnov 		fprintf(stderr, "recv(2) + MSG_PEEK, expected %zu, got %zi\n",
333*587ed79fSArseniy Krasnov 			sizeof(buf_peek), res);
334*587ed79fSArseniy Krasnov 		exit(EXIT_FAILURE);
335*587ed79fSArseniy Krasnov 	}
336*587ed79fSArseniy Krasnov 
337*587ed79fSArseniy Krasnov 	/* Compare partial and full peek. */
338*587ed79fSArseniy Krasnov 	if (memcmp(buf_half, buf_peek, sizeof(buf_half))) {
339*587ed79fSArseniy Krasnov 		fprintf(stderr, "Partial peek data mismatch\n");
340*587ed79fSArseniy Krasnov 		exit(EXIT_FAILURE);
341*587ed79fSArseniy Krasnov 	}
342*587ed79fSArseniy Krasnov 
343*587ed79fSArseniy Krasnov 	res = recv(fd, buf_normal, sizeof(buf_normal), 0);
344*587ed79fSArseniy Krasnov 	if (res != sizeof(buf_normal)) {
345*587ed79fSArseniy Krasnov 		fprintf(stderr, "recv(2), expected %zu, got %zi\n",
346*587ed79fSArseniy Krasnov 			sizeof(buf_normal), res);
347*587ed79fSArseniy Krasnov 		exit(EXIT_FAILURE);
348*587ed79fSArseniy Krasnov 	}
349*587ed79fSArseniy Krasnov 
350*587ed79fSArseniy Krasnov 	/* Compare full peek and normal read. */
351*587ed79fSArseniy Krasnov 	if (memcmp(buf_peek, buf_normal, sizeof(buf_peek))) {
352*587ed79fSArseniy Krasnov 		fprintf(stderr, "Full peek data mismatch\n");
353*587ed79fSArseniy Krasnov 		exit(EXIT_FAILURE);
354*587ed79fSArseniy Krasnov 	}
355*587ed79fSArseniy Krasnov 
356d6269a93SStefano Garzarella 	close(fd);
357d6269a93SStefano Garzarella }
358d6269a93SStefano Garzarella 
3595c338112SArseniy Krasnov #define SOCK_BUF_SIZE (2 * 1024 * 1024)
3605c338112SArseniy Krasnov #define MAX_MSG_SIZE (32 * 1024)
3615c338112SArseniy Krasnov 
36241b792d7SArseny Krasnov static void test_seqpacket_msg_bounds_client(const struct test_opts *opts)
36341b792d7SArseny Krasnov {
3645c338112SArseniy Krasnov 	unsigned long curr_hash;
3655c338112SArseniy Krasnov 	int page_size;
3665c338112SArseniy Krasnov 	int msg_count;
36741b792d7SArseny Krasnov 	int fd;
36841b792d7SArseny Krasnov 
36941b792d7SArseny Krasnov 	fd = vsock_seqpacket_connect(opts->peer_cid, 1234);
37041b792d7SArseny Krasnov 	if (fd < 0) {
37141b792d7SArseny Krasnov 		perror("connect");
37241b792d7SArseny Krasnov 		exit(EXIT_FAILURE);
37341b792d7SArseny Krasnov 	}
37441b792d7SArseny Krasnov 
3755c338112SArseniy Krasnov 	/* Wait, until receiver sets buffer size. */
3765c338112SArseniy Krasnov 	control_expectln("SRVREADY");
3775c338112SArseniy Krasnov 
3785c338112SArseniy Krasnov 	curr_hash = 0;
3795c338112SArseniy Krasnov 	page_size = getpagesize();
3805c338112SArseniy Krasnov 	msg_count = SOCK_BUF_SIZE / MAX_MSG_SIZE;
3815c338112SArseniy Krasnov 
3825c338112SArseniy Krasnov 	for (int i = 0; i < msg_count; i++) {
3835c338112SArseniy Krasnov 		ssize_t send_size;
3845c338112SArseniy Krasnov 		size_t buf_size;
3855c338112SArseniy Krasnov 		int flags;
3865c338112SArseniy Krasnov 		void *buf;
3875c338112SArseniy Krasnov 
3885c338112SArseniy Krasnov 		/* Use "small" buffers and "big" buffers. */
3895c338112SArseniy Krasnov 		if (i & 1)
3905c338112SArseniy Krasnov 			buf_size = page_size +
3915c338112SArseniy Krasnov 					(rand() % (MAX_MSG_SIZE - page_size));
3925c338112SArseniy Krasnov 		else
3935c338112SArseniy Krasnov 			buf_size = 1 + (rand() % page_size);
3945c338112SArseniy Krasnov 
3955c338112SArseniy Krasnov 		buf = malloc(buf_size);
3965c338112SArseniy Krasnov 
3975c338112SArseniy Krasnov 		if (!buf) {
3985c338112SArseniy Krasnov 			perror("malloc");
3995c338112SArseniy Krasnov 			exit(EXIT_FAILURE);
4005c338112SArseniy Krasnov 		}
4015c338112SArseniy Krasnov 
4025c338112SArseniy Krasnov 		memset(buf, rand() & 0xff, buf_size);
4035c338112SArseniy Krasnov 		/* Set at least one MSG_EOR + some random. */
4045c338112SArseniy Krasnov 		if (i == (msg_count / 2) || (rand() & 1)) {
4055c338112SArseniy Krasnov 			flags = MSG_EOR;
4065c338112SArseniy Krasnov 			curr_hash++;
4075c338112SArseniy Krasnov 		} else {
4085c338112SArseniy Krasnov 			flags = 0;
4095c338112SArseniy Krasnov 		}
4105c338112SArseniy Krasnov 
4115c338112SArseniy Krasnov 		send_size = send(fd, buf, buf_size, flags);
4125c338112SArseniy Krasnov 
4135c338112SArseniy Krasnov 		if (send_size < 0) {
4145c338112SArseniy Krasnov 			perror("send");
4155c338112SArseniy Krasnov 			exit(EXIT_FAILURE);
4165c338112SArseniy Krasnov 		}
4175c338112SArseniy Krasnov 
4185c338112SArseniy Krasnov 		if (send_size != buf_size) {
4195c338112SArseniy Krasnov 			fprintf(stderr, "Invalid send size\n");
4205c338112SArseniy Krasnov 			exit(EXIT_FAILURE);
4215c338112SArseniy Krasnov 		}
4225c338112SArseniy Krasnov 
4235c338112SArseniy Krasnov 		/*
4245c338112SArseniy Krasnov 		 * Hash sum is computed at both client and server in
4255c338112SArseniy Krasnov 		 * the same way:
4265c338112SArseniy Krasnov 		 * H += hash('message data')
4275c338112SArseniy Krasnov 		 * Such hash "controls" both data integrity and message
4285c338112SArseniy Krasnov 		 * bounds. After data exchange, both sums are compared
4295c338112SArseniy Krasnov 		 * using control socket, and if message bounds wasn't
4305c338112SArseniy Krasnov 		 * broken - two values must be equal.
4315c338112SArseniy Krasnov 		 */
4325c338112SArseniy Krasnov 		curr_hash += hash_djb2(buf, buf_size);
4335c338112SArseniy Krasnov 		free(buf);
4345c338112SArseniy Krasnov 	}
43541b792d7SArseny Krasnov 
43641b792d7SArseny Krasnov 	control_writeln("SENDDONE");
4375c338112SArseniy Krasnov 	control_writeulong(curr_hash);
43841b792d7SArseny Krasnov 	close(fd);
43941b792d7SArseny Krasnov }
44041b792d7SArseny Krasnov 
44141b792d7SArseny Krasnov static void test_seqpacket_msg_bounds_server(const struct test_opts *opts)
44241b792d7SArseny Krasnov {
4435c338112SArseniy Krasnov 	unsigned long sock_buf_size;
4445c338112SArseniy Krasnov 	unsigned long remote_hash;
4455c338112SArseniy Krasnov 	unsigned long curr_hash;
44641b792d7SArseny Krasnov 	int fd;
4475c338112SArseniy Krasnov 	char buf[MAX_MSG_SIZE];
44841b792d7SArseny Krasnov 	struct msghdr msg = {0};
44941b792d7SArseny Krasnov 	struct iovec iov = {0};
45041b792d7SArseny Krasnov 
45141b792d7SArseny Krasnov 	fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL);
45241b792d7SArseny Krasnov 	if (fd < 0) {
45341b792d7SArseny Krasnov 		perror("accept");
45441b792d7SArseny Krasnov 		exit(EXIT_FAILURE);
45541b792d7SArseny Krasnov 	}
45641b792d7SArseny Krasnov 
4575c338112SArseniy Krasnov 	sock_buf_size = SOCK_BUF_SIZE;
4585c338112SArseniy Krasnov 
4595c338112SArseniy Krasnov 	if (setsockopt(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_MAX_SIZE,
4605c338112SArseniy Krasnov 		       &sock_buf_size, sizeof(sock_buf_size))) {
4615c338112SArseniy Krasnov 		perror("setsockopt(SO_VM_SOCKETS_BUFFER_MAX_SIZE)");
4625c338112SArseniy Krasnov 		exit(EXIT_FAILURE);
4635c338112SArseniy Krasnov 	}
4645c338112SArseniy Krasnov 
4655c338112SArseniy Krasnov 	if (setsockopt(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_SIZE,
4665c338112SArseniy Krasnov 		       &sock_buf_size, sizeof(sock_buf_size))) {
4675c338112SArseniy Krasnov 		perror("setsockopt(SO_VM_SOCKETS_BUFFER_SIZE)");
4685c338112SArseniy Krasnov 		exit(EXIT_FAILURE);
4695c338112SArseniy Krasnov 	}
4705c338112SArseniy Krasnov 
4715c338112SArseniy Krasnov 	/* Ready to receive data. */
4725c338112SArseniy Krasnov 	control_writeln("SRVREADY");
4735c338112SArseniy Krasnov 	/* Wait, until peer sends whole data. */
47441b792d7SArseny Krasnov 	control_expectln("SENDDONE");
47541b792d7SArseny Krasnov 	iov.iov_base = buf;
47641b792d7SArseny Krasnov 	iov.iov_len = sizeof(buf);
47741b792d7SArseny Krasnov 	msg.msg_iov = &iov;
47841b792d7SArseny Krasnov 	msg.msg_iovlen = 1;
47941b792d7SArseny Krasnov 
4805c338112SArseniy Krasnov 	curr_hash = 0;
4815c338112SArseniy Krasnov 
4825c338112SArseniy Krasnov 	while (1) {
4835c338112SArseniy Krasnov 		ssize_t recv_size;
4845c338112SArseniy Krasnov 
4855c338112SArseniy Krasnov 		recv_size = recvmsg(fd, &msg, 0);
4865c338112SArseniy Krasnov 
4875c338112SArseniy Krasnov 		if (!recv_size)
4885c338112SArseniy Krasnov 			break;
4895c338112SArseniy Krasnov 
4905c338112SArseniy Krasnov 		if (recv_size < 0) {
4915c338112SArseniy Krasnov 			perror("recvmsg");
49241b792d7SArseny Krasnov 			exit(EXIT_FAILURE);
49341b792d7SArseny Krasnov 		}
4940e115c45SArseny Krasnov 
4955c338112SArseniy Krasnov 		if (msg.msg_flags & MSG_EOR)
4965c338112SArseniy Krasnov 			curr_hash++;
4975c338112SArseniy Krasnov 
4985c338112SArseniy Krasnov 		curr_hash += hash_djb2(msg.msg_iov[0].iov_base, recv_size);
49941b792d7SArseny Krasnov 	}
50041b792d7SArseny Krasnov 
50141b792d7SArseny Krasnov 	close(fd);
5025c338112SArseniy Krasnov 	remote_hash = control_readulong();
5035c338112SArseniy Krasnov 
5045c338112SArseniy Krasnov 	if (curr_hash != remote_hash) {
5055c338112SArseniy Krasnov 		fprintf(stderr, "Message bounds broken\n");
5065c338112SArseniy Krasnov 		exit(EXIT_FAILURE);
5075c338112SArseniy Krasnov 	}
50841b792d7SArseny Krasnov }
50941b792d7SArseny Krasnov 
51041b792d7SArseny Krasnov #define MESSAGE_TRUNC_SZ 32
51141b792d7SArseny Krasnov static void test_seqpacket_msg_trunc_client(const struct test_opts *opts)
51241b792d7SArseny Krasnov {
51341b792d7SArseny Krasnov 	int fd;
51441b792d7SArseny Krasnov 	char buf[MESSAGE_TRUNC_SZ];
51541b792d7SArseny Krasnov 
51641b792d7SArseny Krasnov 	fd = vsock_seqpacket_connect(opts->peer_cid, 1234);
51741b792d7SArseny Krasnov 	if (fd < 0) {
51841b792d7SArseny Krasnov 		perror("connect");
51941b792d7SArseny Krasnov 		exit(EXIT_FAILURE);
52041b792d7SArseny Krasnov 	}
52141b792d7SArseny Krasnov 
52241b792d7SArseny Krasnov 	if (send(fd, buf, sizeof(buf), 0) != sizeof(buf)) {
52341b792d7SArseny Krasnov 		perror("send failed");
52441b792d7SArseny Krasnov 		exit(EXIT_FAILURE);
52541b792d7SArseny Krasnov 	}
52641b792d7SArseny Krasnov 
52741b792d7SArseny Krasnov 	control_writeln("SENDDONE");
52841b792d7SArseny Krasnov 	close(fd);
52941b792d7SArseny Krasnov }
53041b792d7SArseny Krasnov 
53141b792d7SArseny Krasnov static void test_seqpacket_msg_trunc_server(const struct test_opts *opts)
53241b792d7SArseny Krasnov {
53341b792d7SArseny Krasnov 	int fd;
53441b792d7SArseny Krasnov 	char buf[MESSAGE_TRUNC_SZ / 2];
53541b792d7SArseny Krasnov 	struct msghdr msg = {0};
53641b792d7SArseny Krasnov 	struct iovec iov = {0};
53741b792d7SArseny Krasnov 
53841b792d7SArseny Krasnov 	fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL);
53941b792d7SArseny Krasnov 	if (fd < 0) {
54041b792d7SArseny Krasnov 		perror("accept");
54141b792d7SArseny Krasnov 		exit(EXIT_FAILURE);
54241b792d7SArseny Krasnov 	}
54341b792d7SArseny Krasnov 
54441b792d7SArseny Krasnov 	control_expectln("SENDDONE");
54541b792d7SArseny Krasnov 	iov.iov_base = buf;
54641b792d7SArseny Krasnov 	iov.iov_len = sizeof(buf);
54741b792d7SArseny Krasnov 	msg.msg_iov = &iov;
54841b792d7SArseny Krasnov 	msg.msg_iovlen = 1;
54941b792d7SArseny Krasnov 
55041b792d7SArseny Krasnov 	ssize_t ret = recvmsg(fd, &msg, MSG_TRUNC);
55141b792d7SArseny Krasnov 
55241b792d7SArseny Krasnov 	if (ret != MESSAGE_TRUNC_SZ) {
55341b792d7SArseny Krasnov 		printf("%zi\n", ret);
55441b792d7SArseny Krasnov 		perror("MSG_TRUNC doesn't work");
55541b792d7SArseny Krasnov 		exit(EXIT_FAILURE);
55641b792d7SArseny Krasnov 	}
55741b792d7SArseny Krasnov 
55841b792d7SArseny Krasnov 	if (!(msg.msg_flags & MSG_TRUNC)) {
55941b792d7SArseny Krasnov 		fprintf(stderr, "MSG_TRUNC expected\n");
56041b792d7SArseny Krasnov 		exit(EXIT_FAILURE);
56141b792d7SArseny Krasnov 	}
56241b792d7SArseny Krasnov 
56341b792d7SArseny Krasnov 	close(fd);
56441b792d7SArseny Krasnov }
56541b792d7SArseny Krasnov 
566efb3719fSKrasnov Arseniy Vladimirovich static time_t current_nsec(void)
567efb3719fSKrasnov Arseniy Vladimirovich {
568efb3719fSKrasnov Arseniy Vladimirovich 	struct timespec ts;
569efb3719fSKrasnov Arseniy Vladimirovich 
570efb3719fSKrasnov Arseniy Vladimirovich 	if (clock_gettime(CLOCK_REALTIME, &ts)) {
571efb3719fSKrasnov Arseniy Vladimirovich 		perror("clock_gettime(3) failed");
572efb3719fSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
573efb3719fSKrasnov Arseniy Vladimirovich 	}
574efb3719fSKrasnov Arseniy Vladimirovich 
575efb3719fSKrasnov Arseniy Vladimirovich 	return (ts.tv_sec * 1000000000ULL) + ts.tv_nsec;
576efb3719fSKrasnov Arseniy Vladimirovich }
577efb3719fSKrasnov Arseniy Vladimirovich 
578efb3719fSKrasnov Arseniy Vladimirovich #define RCVTIMEO_TIMEOUT_SEC 1
579efb3719fSKrasnov Arseniy Vladimirovich #define READ_OVERHEAD_NSEC 250000000 /* 0.25 sec */
580efb3719fSKrasnov Arseniy Vladimirovich 
581efb3719fSKrasnov Arseniy Vladimirovich static void test_seqpacket_timeout_client(const struct test_opts *opts)
582efb3719fSKrasnov Arseniy Vladimirovich {
583efb3719fSKrasnov Arseniy Vladimirovich 	int fd;
584efb3719fSKrasnov Arseniy Vladimirovich 	struct timeval tv;
585efb3719fSKrasnov Arseniy Vladimirovich 	char dummy;
586efb3719fSKrasnov Arseniy Vladimirovich 	time_t read_enter_ns;
587efb3719fSKrasnov Arseniy Vladimirovich 	time_t read_overhead_ns;
588efb3719fSKrasnov Arseniy Vladimirovich 
589efb3719fSKrasnov Arseniy Vladimirovich 	fd = vsock_seqpacket_connect(opts->peer_cid, 1234);
590efb3719fSKrasnov Arseniy Vladimirovich 	if (fd < 0) {
591efb3719fSKrasnov Arseniy Vladimirovich 		perror("connect");
592efb3719fSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
593efb3719fSKrasnov Arseniy Vladimirovich 	}
594efb3719fSKrasnov Arseniy Vladimirovich 
595efb3719fSKrasnov Arseniy Vladimirovich 	tv.tv_sec = RCVTIMEO_TIMEOUT_SEC;
596efb3719fSKrasnov Arseniy Vladimirovich 	tv.tv_usec = 0;
597efb3719fSKrasnov Arseniy Vladimirovich 
598efb3719fSKrasnov Arseniy Vladimirovich 	if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (void *)&tv, sizeof(tv)) == -1) {
5995c338112SArseniy Krasnov 		perror("setsockopt(SO_RCVTIMEO)");
600efb3719fSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
601efb3719fSKrasnov Arseniy Vladimirovich 	}
602efb3719fSKrasnov Arseniy Vladimirovich 
603efb3719fSKrasnov Arseniy Vladimirovich 	read_enter_ns = current_nsec();
604efb3719fSKrasnov Arseniy Vladimirovich 
605efb3719fSKrasnov Arseniy Vladimirovich 	if (read(fd, &dummy, sizeof(dummy)) != -1) {
606efb3719fSKrasnov Arseniy Vladimirovich 		fprintf(stderr,
607efb3719fSKrasnov Arseniy Vladimirovich 			"expected 'dummy' read(2) failure\n");
608efb3719fSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
609efb3719fSKrasnov Arseniy Vladimirovich 	}
610efb3719fSKrasnov Arseniy Vladimirovich 
611efb3719fSKrasnov Arseniy Vladimirovich 	if (errno != EAGAIN) {
612efb3719fSKrasnov Arseniy Vladimirovich 		perror("EAGAIN expected");
613efb3719fSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
614efb3719fSKrasnov Arseniy Vladimirovich 	}
615efb3719fSKrasnov Arseniy Vladimirovich 
616efb3719fSKrasnov Arseniy Vladimirovich 	read_overhead_ns = current_nsec() - read_enter_ns -
617efb3719fSKrasnov Arseniy Vladimirovich 			1000000000ULL * RCVTIMEO_TIMEOUT_SEC;
618efb3719fSKrasnov Arseniy Vladimirovich 
619efb3719fSKrasnov Arseniy Vladimirovich 	if (read_overhead_ns > READ_OVERHEAD_NSEC) {
620efb3719fSKrasnov Arseniy Vladimirovich 		fprintf(stderr,
621efb3719fSKrasnov Arseniy Vladimirovich 			"too much time in read(2), %lu > %i ns\n",
622efb3719fSKrasnov Arseniy Vladimirovich 			read_overhead_ns, READ_OVERHEAD_NSEC);
623efb3719fSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
624efb3719fSKrasnov Arseniy Vladimirovich 	}
625efb3719fSKrasnov Arseniy Vladimirovich 
626efb3719fSKrasnov Arseniy Vladimirovich 	control_writeln("WAITDONE");
627efb3719fSKrasnov Arseniy Vladimirovich 	close(fd);
628efb3719fSKrasnov Arseniy Vladimirovich }
629efb3719fSKrasnov Arseniy Vladimirovich 
630efb3719fSKrasnov Arseniy Vladimirovich static void test_seqpacket_timeout_server(const struct test_opts *opts)
631efb3719fSKrasnov Arseniy Vladimirovich {
632efb3719fSKrasnov Arseniy Vladimirovich 	int fd;
633efb3719fSKrasnov Arseniy Vladimirovich 
634efb3719fSKrasnov Arseniy Vladimirovich 	fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL);
635efb3719fSKrasnov Arseniy Vladimirovich 	if (fd < 0) {
636efb3719fSKrasnov Arseniy Vladimirovich 		perror("accept");
637efb3719fSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
638efb3719fSKrasnov Arseniy Vladimirovich 	}
639efb3719fSKrasnov Arseniy Vladimirovich 
640efb3719fSKrasnov Arseniy Vladimirovich 	control_expectln("WAITDONE");
641efb3719fSKrasnov Arseniy Vladimirovich 	close(fd);
642efb3719fSKrasnov Arseniy Vladimirovich }
643efb3719fSKrasnov Arseniy Vladimirovich 
644685a21c3SArseniy Krasnov static void test_seqpacket_bigmsg_client(const struct test_opts *opts)
645685a21c3SArseniy Krasnov {
646685a21c3SArseniy Krasnov 	unsigned long sock_buf_size;
647685a21c3SArseniy Krasnov 	ssize_t send_size;
648685a21c3SArseniy Krasnov 	socklen_t len;
649685a21c3SArseniy Krasnov 	void *data;
650685a21c3SArseniy Krasnov 	int fd;
651685a21c3SArseniy Krasnov 
652685a21c3SArseniy Krasnov 	len = sizeof(sock_buf_size);
653685a21c3SArseniy Krasnov 
654685a21c3SArseniy Krasnov 	fd = vsock_seqpacket_connect(opts->peer_cid, 1234);
655685a21c3SArseniy Krasnov 	if (fd < 0) {
656685a21c3SArseniy Krasnov 		perror("connect");
657685a21c3SArseniy Krasnov 		exit(EXIT_FAILURE);
658685a21c3SArseniy Krasnov 	}
659685a21c3SArseniy Krasnov 
660685a21c3SArseniy Krasnov 	if (getsockopt(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_SIZE,
661685a21c3SArseniy Krasnov 		       &sock_buf_size, &len)) {
662685a21c3SArseniy Krasnov 		perror("getsockopt");
663685a21c3SArseniy Krasnov 		exit(EXIT_FAILURE);
664685a21c3SArseniy Krasnov 	}
665685a21c3SArseniy Krasnov 
666685a21c3SArseniy Krasnov 	sock_buf_size++;
667685a21c3SArseniy Krasnov 
668685a21c3SArseniy Krasnov 	data = malloc(sock_buf_size);
669685a21c3SArseniy Krasnov 	if (!data) {
670685a21c3SArseniy Krasnov 		perror("malloc");
671685a21c3SArseniy Krasnov 		exit(EXIT_FAILURE);
672685a21c3SArseniy Krasnov 	}
673685a21c3SArseniy Krasnov 
674685a21c3SArseniy Krasnov 	send_size = send(fd, data, sock_buf_size, 0);
675685a21c3SArseniy Krasnov 	if (send_size != -1) {
676685a21c3SArseniy Krasnov 		fprintf(stderr, "expected 'send(2)' failure, got %zi\n",
677685a21c3SArseniy Krasnov 			send_size);
678685a21c3SArseniy Krasnov 		exit(EXIT_FAILURE);
679685a21c3SArseniy Krasnov 	}
680685a21c3SArseniy Krasnov 
681685a21c3SArseniy Krasnov 	if (errno != EMSGSIZE) {
682685a21c3SArseniy Krasnov 		fprintf(stderr, "expected EMSGSIZE in 'errno', got %i\n",
683685a21c3SArseniy Krasnov 			errno);
684685a21c3SArseniy Krasnov 		exit(EXIT_FAILURE);
685685a21c3SArseniy Krasnov 	}
686685a21c3SArseniy Krasnov 
687685a21c3SArseniy Krasnov 	control_writeln("CLISENT");
688685a21c3SArseniy Krasnov 
689685a21c3SArseniy Krasnov 	free(data);
690685a21c3SArseniy Krasnov 	close(fd);
691685a21c3SArseniy Krasnov }
692685a21c3SArseniy Krasnov 
693685a21c3SArseniy Krasnov static void test_seqpacket_bigmsg_server(const struct test_opts *opts)
694685a21c3SArseniy Krasnov {
695685a21c3SArseniy Krasnov 	int fd;
696685a21c3SArseniy Krasnov 
697685a21c3SArseniy Krasnov 	fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL);
698685a21c3SArseniy Krasnov 	if (fd < 0) {
699685a21c3SArseniy Krasnov 		perror("accept");
700685a21c3SArseniy Krasnov 		exit(EXIT_FAILURE);
701685a21c3SArseniy Krasnov 	}
702685a21c3SArseniy Krasnov 
703685a21c3SArseniy Krasnov 	control_expectln("CLISENT");
704685a21c3SArseniy Krasnov 
705685a21c3SArseniy Krasnov 	close(fd);
706685a21c3SArseniy Krasnov }
707685a21c3SArseniy Krasnov 
708e89600ebSKrasnov Arseniy Vladimirovich #define BUF_PATTERN_1 'a'
709e89600ebSKrasnov Arseniy Vladimirovich #define BUF_PATTERN_2 'b'
710e89600ebSKrasnov Arseniy Vladimirovich 
711e89600ebSKrasnov Arseniy Vladimirovich static void test_seqpacket_invalid_rec_buffer_client(const struct test_opts *opts)
712e89600ebSKrasnov Arseniy Vladimirovich {
713e89600ebSKrasnov Arseniy Vladimirovich 	int fd;
714e89600ebSKrasnov Arseniy Vladimirovich 	unsigned char *buf1;
715e89600ebSKrasnov Arseniy Vladimirovich 	unsigned char *buf2;
716e89600ebSKrasnov Arseniy Vladimirovich 	int buf_size = getpagesize() * 3;
717e89600ebSKrasnov Arseniy Vladimirovich 
718e89600ebSKrasnov Arseniy Vladimirovich 	fd = vsock_seqpacket_connect(opts->peer_cid, 1234);
719e89600ebSKrasnov Arseniy Vladimirovich 	if (fd < 0) {
720e89600ebSKrasnov Arseniy Vladimirovich 		perror("connect");
721e89600ebSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
722e89600ebSKrasnov Arseniy Vladimirovich 	}
723e89600ebSKrasnov Arseniy Vladimirovich 
724e89600ebSKrasnov Arseniy Vladimirovich 	buf1 = malloc(buf_size);
725e89600ebSKrasnov Arseniy Vladimirovich 	if (!buf1) {
726e89600ebSKrasnov Arseniy Vladimirovich 		perror("'malloc()' for 'buf1'");
727e89600ebSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
728e89600ebSKrasnov Arseniy Vladimirovich 	}
729e89600ebSKrasnov Arseniy Vladimirovich 
730e89600ebSKrasnov Arseniy Vladimirovich 	buf2 = malloc(buf_size);
731e89600ebSKrasnov Arseniy Vladimirovich 	if (!buf2) {
732e89600ebSKrasnov Arseniy Vladimirovich 		perror("'malloc()' for 'buf2'");
733e89600ebSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
734e89600ebSKrasnov Arseniy Vladimirovich 	}
735e89600ebSKrasnov Arseniy Vladimirovich 
736e89600ebSKrasnov Arseniy Vladimirovich 	memset(buf1, BUF_PATTERN_1, buf_size);
737e89600ebSKrasnov Arseniy Vladimirovich 	memset(buf2, BUF_PATTERN_2, buf_size);
738e89600ebSKrasnov Arseniy Vladimirovich 
739e89600ebSKrasnov Arseniy Vladimirovich 	if (send(fd, buf1, buf_size, 0) != buf_size) {
740e89600ebSKrasnov Arseniy Vladimirovich 		perror("send failed");
741e89600ebSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
742e89600ebSKrasnov Arseniy Vladimirovich 	}
743e89600ebSKrasnov Arseniy Vladimirovich 
744e89600ebSKrasnov Arseniy Vladimirovich 	if (send(fd, buf2, buf_size, 0) != buf_size) {
745e89600ebSKrasnov Arseniy Vladimirovich 		perror("send failed");
746e89600ebSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
747e89600ebSKrasnov Arseniy Vladimirovich 	}
748e89600ebSKrasnov Arseniy Vladimirovich 
749e89600ebSKrasnov Arseniy Vladimirovich 	close(fd);
750e89600ebSKrasnov Arseniy Vladimirovich }
751e89600ebSKrasnov Arseniy Vladimirovich 
752e89600ebSKrasnov Arseniy Vladimirovich static void test_seqpacket_invalid_rec_buffer_server(const struct test_opts *opts)
753e89600ebSKrasnov Arseniy Vladimirovich {
754e89600ebSKrasnov Arseniy Vladimirovich 	int fd;
755e89600ebSKrasnov Arseniy Vladimirovich 	unsigned char *broken_buf;
756e89600ebSKrasnov Arseniy Vladimirovich 	unsigned char *valid_buf;
757e89600ebSKrasnov Arseniy Vladimirovich 	int page_size = getpagesize();
758e89600ebSKrasnov Arseniy Vladimirovich 	int buf_size = page_size * 3;
759e89600ebSKrasnov Arseniy Vladimirovich 	ssize_t res;
760e89600ebSKrasnov Arseniy Vladimirovich 	int prot = PROT_READ | PROT_WRITE;
761e89600ebSKrasnov Arseniy Vladimirovich 	int flags = MAP_PRIVATE | MAP_ANONYMOUS;
762e89600ebSKrasnov Arseniy Vladimirovich 	int i;
763e89600ebSKrasnov Arseniy Vladimirovich 
764e89600ebSKrasnov Arseniy Vladimirovich 	fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL);
765e89600ebSKrasnov Arseniy Vladimirovich 	if (fd < 0) {
766e89600ebSKrasnov Arseniy Vladimirovich 		perror("accept");
767e89600ebSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
768e89600ebSKrasnov Arseniy Vladimirovich 	}
769e89600ebSKrasnov Arseniy Vladimirovich 
770e89600ebSKrasnov Arseniy Vladimirovich 	/* Setup first buffer. */
771e89600ebSKrasnov Arseniy Vladimirovich 	broken_buf = mmap(NULL, buf_size, prot, flags, -1, 0);
772e89600ebSKrasnov Arseniy Vladimirovich 	if (broken_buf == MAP_FAILED) {
773e89600ebSKrasnov Arseniy Vladimirovich 		perror("mmap for 'broken_buf'");
774e89600ebSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
775e89600ebSKrasnov Arseniy Vladimirovich 	}
776e89600ebSKrasnov Arseniy Vladimirovich 
777e89600ebSKrasnov Arseniy Vladimirovich 	/* Unmap "hole" in buffer. */
778e89600ebSKrasnov Arseniy Vladimirovich 	if (munmap(broken_buf + page_size, page_size)) {
779e89600ebSKrasnov Arseniy Vladimirovich 		perror("'broken_buf' setup");
780e89600ebSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
781e89600ebSKrasnov Arseniy Vladimirovich 	}
782e89600ebSKrasnov Arseniy Vladimirovich 
783e89600ebSKrasnov Arseniy Vladimirovich 	valid_buf = mmap(NULL, buf_size, prot, flags, -1, 0);
784e89600ebSKrasnov Arseniy Vladimirovich 	if (valid_buf == MAP_FAILED) {
785e89600ebSKrasnov Arseniy Vladimirovich 		perror("mmap for 'valid_buf'");
786e89600ebSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
787e89600ebSKrasnov Arseniy Vladimirovich 	}
788e89600ebSKrasnov Arseniy Vladimirovich 
789e89600ebSKrasnov Arseniy Vladimirovich 	/* Try to fill buffer with unmapped middle. */
790e89600ebSKrasnov Arseniy Vladimirovich 	res = read(fd, broken_buf, buf_size);
791e89600ebSKrasnov Arseniy Vladimirovich 	if (res != -1) {
792e89600ebSKrasnov Arseniy Vladimirovich 		fprintf(stderr,
793e89600ebSKrasnov Arseniy Vladimirovich 			"expected 'broken_buf' read(2) failure, got %zi\n",
794e89600ebSKrasnov Arseniy Vladimirovich 			res);
795e89600ebSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
796e89600ebSKrasnov Arseniy Vladimirovich 	}
797e89600ebSKrasnov Arseniy Vladimirovich 
798b5d54eb5SArseniy Krasnov 	if (errno != EFAULT) {
799e89600ebSKrasnov Arseniy Vladimirovich 		perror("unexpected errno of 'broken_buf'");
800e89600ebSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
801e89600ebSKrasnov Arseniy Vladimirovich 	}
802e89600ebSKrasnov Arseniy Vladimirovich 
803e89600ebSKrasnov Arseniy Vladimirovich 	/* Try to fill valid buffer. */
804e89600ebSKrasnov Arseniy Vladimirovich 	res = read(fd, valid_buf, buf_size);
805e89600ebSKrasnov Arseniy Vladimirovich 	if (res < 0) {
806e89600ebSKrasnov Arseniy Vladimirovich 		perror("unexpected 'valid_buf' read(2) failure");
807e89600ebSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
808e89600ebSKrasnov Arseniy Vladimirovich 	}
809e89600ebSKrasnov Arseniy Vladimirovich 
810e89600ebSKrasnov Arseniy Vladimirovich 	if (res != buf_size) {
811e89600ebSKrasnov Arseniy Vladimirovich 		fprintf(stderr,
812e89600ebSKrasnov Arseniy Vladimirovich 			"invalid 'valid_buf' read(2), expected %i, got %zi\n",
813e89600ebSKrasnov Arseniy Vladimirovich 			buf_size, res);
814e89600ebSKrasnov Arseniy Vladimirovich 		exit(EXIT_FAILURE);
815e89600ebSKrasnov Arseniy Vladimirovich 	}
816e89600ebSKrasnov Arseniy Vladimirovich 
817e89600ebSKrasnov Arseniy Vladimirovich 	for (i = 0; i < buf_size; i++) {
818e89600ebSKrasnov Arseniy Vladimirovich 		if (valid_buf[i] != BUF_PATTERN_2) {
819e89600ebSKrasnov Arseniy Vladimirovich 			fprintf(stderr,
820e89600ebSKrasnov Arseniy Vladimirovich 				"invalid pattern for 'valid_buf' at %i, expected %hhX, got %hhX\n",
821e89600ebSKrasnov Arseniy Vladimirovich 				i, BUF_PATTERN_2, valid_buf[i]);
822e89600ebSKrasnov Arseniy Vladimirovich 			exit(EXIT_FAILURE);
823e89600ebSKrasnov Arseniy Vladimirovich 		}
824e89600ebSKrasnov Arseniy Vladimirovich 	}
825e89600ebSKrasnov Arseniy Vladimirovich 
826e89600ebSKrasnov Arseniy Vladimirovich 	/* Unmap buffers. */
827e89600ebSKrasnov Arseniy Vladimirovich 	munmap(broken_buf, page_size);
828e89600ebSKrasnov Arseniy Vladimirovich 	munmap(broken_buf + page_size * 2, page_size);
829e89600ebSKrasnov Arseniy Vladimirovich 	munmap(valid_buf, buf_size);
830e89600ebSKrasnov Arseniy Vladimirovich 	close(fd);
831e89600ebSKrasnov Arseniy Vladimirovich }
832e89600ebSKrasnov Arseniy Vladimirovich 
833b1346338SArseniy Krasnov #define RCVLOWAT_BUF_SIZE 128
834b1346338SArseniy Krasnov 
835b1346338SArseniy Krasnov static void test_stream_poll_rcvlowat_server(const struct test_opts *opts)
836b1346338SArseniy Krasnov {
837b1346338SArseniy Krasnov 	int fd;
838b1346338SArseniy Krasnov 	int i;
839b1346338SArseniy Krasnov 
840b1346338SArseniy Krasnov 	fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
841b1346338SArseniy Krasnov 	if (fd < 0) {
842b1346338SArseniy Krasnov 		perror("accept");
843b1346338SArseniy Krasnov 		exit(EXIT_FAILURE);
844b1346338SArseniy Krasnov 	}
845b1346338SArseniy Krasnov 
846b1346338SArseniy Krasnov 	/* Send 1 byte. */
847b1346338SArseniy Krasnov 	send_byte(fd, 1, 0);
848b1346338SArseniy Krasnov 
849b1346338SArseniy Krasnov 	control_writeln("SRVSENT");
850b1346338SArseniy Krasnov 
851b1346338SArseniy Krasnov 	/* Wait until client is ready to receive rest of data. */
852b1346338SArseniy Krasnov 	control_expectln("CLNSENT");
853b1346338SArseniy Krasnov 
854b1346338SArseniy Krasnov 	for (i = 0; i < RCVLOWAT_BUF_SIZE - 1; i++)
855b1346338SArseniy Krasnov 		send_byte(fd, 1, 0);
856b1346338SArseniy Krasnov 
857b1346338SArseniy Krasnov 	/* Keep socket in active state. */
858b1346338SArseniy Krasnov 	control_expectln("POLLDONE");
859b1346338SArseniy Krasnov 
860b1346338SArseniy Krasnov 	close(fd);
861b1346338SArseniy Krasnov }
862b1346338SArseniy Krasnov 
863b1346338SArseniy Krasnov static void test_stream_poll_rcvlowat_client(const struct test_opts *opts)
864b1346338SArseniy Krasnov {
865b1346338SArseniy Krasnov 	unsigned long lowat_val = RCVLOWAT_BUF_SIZE;
866b1346338SArseniy Krasnov 	char buf[RCVLOWAT_BUF_SIZE];
867b1346338SArseniy Krasnov 	struct pollfd fds;
868b1346338SArseniy Krasnov 	ssize_t read_res;
869b1346338SArseniy Krasnov 	short poll_flags;
870b1346338SArseniy Krasnov 	int fd;
871b1346338SArseniy Krasnov 
872b1346338SArseniy Krasnov 	fd = vsock_stream_connect(opts->peer_cid, 1234);
873b1346338SArseniy Krasnov 	if (fd < 0) {
874b1346338SArseniy Krasnov 		perror("connect");
875b1346338SArseniy Krasnov 		exit(EXIT_FAILURE);
876b1346338SArseniy Krasnov 	}
877b1346338SArseniy Krasnov 
878b1346338SArseniy Krasnov 	if (setsockopt(fd, SOL_SOCKET, SO_RCVLOWAT,
879b1346338SArseniy Krasnov 		       &lowat_val, sizeof(lowat_val))) {
8805c338112SArseniy Krasnov 		perror("setsockopt(SO_RCVLOWAT)");
881b1346338SArseniy Krasnov 		exit(EXIT_FAILURE);
882b1346338SArseniy Krasnov 	}
883b1346338SArseniy Krasnov 
884b1346338SArseniy Krasnov 	control_expectln("SRVSENT");
885b1346338SArseniy Krasnov 
886b1346338SArseniy Krasnov 	/* At this point, server sent 1 byte. */
887b1346338SArseniy Krasnov 	fds.fd = fd;
888b1346338SArseniy Krasnov 	poll_flags = POLLIN | POLLRDNORM;
889b1346338SArseniy Krasnov 	fds.events = poll_flags;
890b1346338SArseniy Krasnov 
891b1346338SArseniy Krasnov 	/* Try to wait for 1 sec. */
892b1346338SArseniy Krasnov 	if (poll(&fds, 1, 1000) < 0) {
893b1346338SArseniy Krasnov 		perror("poll");
894b1346338SArseniy Krasnov 		exit(EXIT_FAILURE);
895b1346338SArseniy Krasnov 	}
896b1346338SArseniy Krasnov 
897b1346338SArseniy Krasnov 	/* poll() must return nothing. */
898b1346338SArseniy Krasnov 	if (fds.revents) {
899b1346338SArseniy Krasnov 		fprintf(stderr, "Unexpected poll result %hx\n",
900b1346338SArseniy Krasnov 			fds.revents);
901b1346338SArseniy Krasnov 		exit(EXIT_FAILURE);
902b1346338SArseniy Krasnov 	}
903b1346338SArseniy Krasnov 
904b1346338SArseniy Krasnov 	/* Tell server to send rest of data. */
905b1346338SArseniy Krasnov 	control_writeln("CLNSENT");
906b1346338SArseniy Krasnov 
907b1346338SArseniy Krasnov 	/* Poll for data. */
908b1346338SArseniy Krasnov 	if (poll(&fds, 1, 10000) < 0) {
909b1346338SArseniy Krasnov 		perror("poll");
910b1346338SArseniy Krasnov 		exit(EXIT_FAILURE);
911b1346338SArseniy Krasnov 	}
912b1346338SArseniy Krasnov 
913b1346338SArseniy Krasnov 	/* Only these two bits are expected. */
914b1346338SArseniy Krasnov 	if (fds.revents != poll_flags) {
915b1346338SArseniy Krasnov 		fprintf(stderr, "Unexpected poll result %hx\n",
916b1346338SArseniy Krasnov 			fds.revents);
917b1346338SArseniy Krasnov 		exit(EXIT_FAILURE);
918b1346338SArseniy Krasnov 	}
919b1346338SArseniy Krasnov 
920b1346338SArseniy Krasnov 	/* Use MSG_DONTWAIT, if call is going to wait, EAGAIN
921b1346338SArseniy Krasnov 	 * will be returned.
922b1346338SArseniy Krasnov 	 */
923b1346338SArseniy Krasnov 	read_res = recv(fd, buf, sizeof(buf), MSG_DONTWAIT);
924b1346338SArseniy Krasnov 	if (read_res != RCVLOWAT_BUF_SIZE) {
925b1346338SArseniy Krasnov 		fprintf(stderr, "Unexpected recv result %zi\n",
926b1346338SArseniy Krasnov 			read_res);
927b1346338SArseniy Krasnov 		exit(EXIT_FAILURE);
928b1346338SArseniy Krasnov 	}
929b1346338SArseniy Krasnov 
930b1346338SArseniy Krasnov 	control_writeln("POLLDONE");
931b1346338SArseniy Krasnov 
932b1346338SArseniy Krasnov 	close(fd);
933b1346338SArseniy Krasnov }
934b1346338SArseniy Krasnov 
9357e699d2aSArseniy Krasnov #define INV_BUF_TEST_DATA_LEN 512
9367e699d2aSArseniy Krasnov 
9377e699d2aSArseniy Krasnov static void test_inv_buf_client(const struct test_opts *opts, bool stream)
9387e699d2aSArseniy Krasnov {
9397e699d2aSArseniy Krasnov 	unsigned char data[INV_BUF_TEST_DATA_LEN] = {0};
9407e699d2aSArseniy Krasnov 	ssize_t ret;
9417e699d2aSArseniy Krasnov 	int fd;
9427e699d2aSArseniy Krasnov 
9437e699d2aSArseniy Krasnov 	if (stream)
9447e699d2aSArseniy Krasnov 		fd = vsock_stream_connect(opts->peer_cid, 1234);
9457e699d2aSArseniy Krasnov 	else
9467e699d2aSArseniy Krasnov 		fd = vsock_seqpacket_connect(opts->peer_cid, 1234);
9477e699d2aSArseniy Krasnov 
9487e699d2aSArseniy Krasnov 	if (fd < 0) {
9497e699d2aSArseniy Krasnov 		perror("connect");
9507e699d2aSArseniy Krasnov 		exit(EXIT_FAILURE);
9517e699d2aSArseniy Krasnov 	}
9527e699d2aSArseniy Krasnov 
9537e699d2aSArseniy Krasnov 	control_expectln("SENDDONE");
9547e699d2aSArseniy Krasnov 
9557e699d2aSArseniy Krasnov 	/* Use invalid buffer here. */
9567e699d2aSArseniy Krasnov 	ret = recv(fd, NULL, sizeof(data), 0);
9577e699d2aSArseniy Krasnov 	if (ret != -1) {
9587e699d2aSArseniy Krasnov 		fprintf(stderr, "expected recv(2) failure, got %zi\n", ret);
9597e699d2aSArseniy Krasnov 		exit(EXIT_FAILURE);
9607e699d2aSArseniy Krasnov 	}
9617e699d2aSArseniy Krasnov 
962b5d54eb5SArseniy Krasnov 	if (errno != EFAULT) {
9637e699d2aSArseniy Krasnov 		fprintf(stderr, "unexpected recv(2) errno %d\n", errno);
9647e699d2aSArseniy Krasnov 		exit(EXIT_FAILURE);
9657e699d2aSArseniy Krasnov 	}
9667e699d2aSArseniy Krasnov 
9677e699d2aSArseniy Krasnov 	ret = recv(fd, data, sizeof(data), MSG_DONTWAIT);
9687e699d2aSArseniy Krasnov 
9697e699d2aSArseniy Krasnov 	if (stream) {
9707e699d2aSArseniy Krasnov 		/* For SOCK_STREAM we must continue reading. */
9717e699d2aSArseniy Krasnov 		if (ret != sizeof(data)) {
9727e699d2aSArseniy Krasnov 			fprintf(stderr, "expected recv(2) success, got %zi\n", ret);
9737e699d2aSArseniy Krasnov 			exit(EXIT_FAILURE);
9747e699d2aSArseniy Krasnov 		}
9757e699d2aSArseniy Krasnov 		/* Don't check errno in case of success. */
9767e699d2aSArseniy Krasnov 	} else {
9777e699d2aSArseniy Krasnov 		/* For SOCK_SEQPACKET socket's queue must be empty. */
9787e699d2aSArseniy Krasnov 		if (ret != -1) {
9797e699d2aSArseniy Krasnov 			fprintf(stderr, "expected recv(2) failure, got %zi\n", ret);
9807e699d2aSArseniy Krasnov 			exit(EXIT_FAILURE);
9817e699d2aSArseniy Krasnov 		}
9827e699d2aSArseniy Krasnov 
9837e699d2aSArseniy Krasnov 		if (errno != EAGAIN) {
9847e699d2aSArseniy Krasnov 			fprintf(stderr, "unexpected recv(2) errno %d\n", errno);
9857e699d2aSArseniy Krasnov 			exit(EXIT_FAILURE);
9867e699d2aSArseniy Krasnov 		}
9877e699d2aSArseniy Krasnov 	}
9887e699d2aSArseniy Krasnov 
9897e699d2aSArseniy Krasnov 	control_writeln("DONE");
9907e699d2aSArseniy Krasnov 
9917e699d2aSArseniy Krasnov 	close(fd);
9927e699d2aSArseniy Krasnov }
9937e699d2aSArseniy Krasnov 
9947e699d2aSArseniy Krasnov static void test_inv_buf_server(const struct test_opts *opts, bool stream)
9957e699d2aSArseniy Krasnov {
9967e699d2aSArseniy Krasnov 	unsigned char data[INV_BUF_TEST_DATA_LEN] = {0};
9977e699d2aSArseniy Krasnov 	ssize_t res;
9987e699d2aSArseniy Krasnov 	int fd;
9997e699d2aSArseniy Krasnov 
10007e699d2aSArseniy Krasnov 	if (stream)
10017e699d2aSArseniy Krasnov 		fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
10027e699d2aSArseniy Krasnov 	else
10037e699d2aSArseniy Krasnov 		fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL);
10047e699d2aSArseniy Krasnov 
10057e699d2aSArseniy Krasnov 	if (fd < 0) {
10067e699d2aSArseniy Krasnov 		perror("accept");
10077e699d2aSArseniy Krasnov 		exit(EXIT_FAILURE);
10087e699d2aSArseniy Krasnov 	}
10097e699d2aSArseniy Krasnov 
10107e699d2aSArseniy Krasnov 	res = send(fd, data, sizeof(data), 0);
10117e699d2aSArseniy Krasnov 	if (res != sizeof(data)) {
10127e699d2aSArseniy Krasnov 		fprintf(stderr, "unexpected send(2) result %zi\n", res);
10137e699d2aSArseniy Krasnov 		exit(EXIT_FAILURE);
10147e699d2aSArseniy Krasnov 	}
10157e699d2aSArseniy Krasnov 
10167e699d2aSArseniy Krasnov 	control_writeln("SENDDONE");
10177e699d2aSArseniy Krasnov 
10187e699d2aSArseniy Krasnov 	control_expectln("DONE");
10197e699d2aSArseniy Krasnov 
10207e699d2aSArseniy Krasnov 	close(fd);
10217e699d2aSArseniy Krasnov }
10227e699d2aSArseniy Krasnov 
10237e699d2aSArseniy Krasnov static void test_stream_inv_buf_client(const struct test_opts *opts)
10247e699d2aSArseniy Krasnov {
10257e699d2aSArseniy Krasnov 	test_inv_buf_client(opts, true);
10267e699d2aSArseniy Krasnov }
10277e699d2aSArseniy Krasnov 
10287e699d2aSArseniy Krasnov static void test_stream_inv_buf_server(const struct test_opts *opts)
10297e699d2aSArseniy Krasnov {
10307e699d2aSArseniy Krasnov 	test_inv_buf_server(opts, true);
10317e699d2aSArseniy Krasnov }
10327e699d2aSArseniy Krasnov 
10337e699d2aSArseniy Krasnov static void test_seqpacket_inv_buf_client(const struct test_opts *opts)
10347e699d2aSArseniy Krasnov {
10357e699d2aSArseniy Krasnov 	test_inv_buf_client(opts, false);
10367e699d2aSArseniy Krasnov }
10377e699d2aSArseniy Krasnov 
10387e699d2aSArseniy Krasnov static void test_seqpacket_inv_buf_server(const struct test_opts *opts)
10397e699d2aSArseniy Krasnov {
10407e699d2aSArseniy Krasnov 	test_inv_buf_server(opts, false);
10417e699d2aSArseniy Krasnov }
10427e699d2aSArseniy Krasnov 
104325209a32SArseniy Krasnov #define HELLO_STR "HELLO"
104425209a32SArseniy Krasnov #define WORLD_STR "WORLD"
104525209a32SArseniy Krasnov 
104625209a32SArseniy Krasnov static void test_stream_virtio_skb_merge_client(const struct test_opts *opts)
104725209a32SArseniy Krasnov {
104825209a32SArseniy Krasnov 	ssize_t res;
104925209a32SArseniy Krasnov 	int fd;
105025209a32SArseniy Krasnov 
105125209a32SArseniy Krasnov 	fd = vsock_stream_connect(opts->peer_cid, 1234);
105225209a32SArseniy Krasnov 	if (fd < 0) {
105325209a32SArseniy Krasnov 		perror("connect");
105425209a32SArseniy Krasnov 		exit(EXIT_FAILURE);
105525209a32SArseniy Krasnov 	}
105625209a32SArseniy Krasnov 
105725209a32SArseniy Krasnov 	/* Send first skbuff. */
105825209a32SArseniy Krasnov 	res = send(fd, HELLO_STR, strlen(HELLO_STR), 0);
105925209a32SArseniy Krasnov 	if (res != strlen(HELLO_STR)) {
106025209a32SArseniy Krasnov 		fprintf(stderr, "unexpected send(2) result %zi\n", res);
106125209a32SArseniy Krasnov 		exit(EXIT_FAILURE);
106225209a32SArseniy Krasnov 	}
106325209a32SArseniy Krasnov 
106425209a32SArseniy Krasnov 	control_writeln("SEND0");
106525209a32SArseniy Krasnov 	/* Peer reads part of first skbuff. */
106625209a32SArseniy Krasnov 	control_expectln("REPLY0");
106725209a32SArseniy Krasnov 
106825209a32SArseniy Krasnov 	/* Send second skbuff, it will be appended to the first. */
106925209a32SArseniy Krasnov 	res = send(fd, WORLD_STR, strlen(WORLD_STR), 0);
107025209a32SArseniy Krasnov 	if (res != strlen(WORLD_STR)) {
107125209a32SArseniy Krasnov 		fprintf(stderr, "unexpected send(2) result %zi\n", res);
107225209a32SArseniy Krasnov 		exit(EXIT_FAILURE);
107325209a32SArseniy Krasnov 	}
107425209a32SArseniy Krasnov 
107525209a32SArseniy Krasnov 	control_writeln("SEND1");
107625209a32SArseniy Krasnov 	/* Peer reads merged skbuff packet. */
107725209a32SArseniy Krasnov 	control_expectln("REPLY1");
107825209a32SArseniy Krasnov 
107925209a32SArseniy Krasnov 	close(fd);
108025209a32SArseniy Krasnov }
108125209a32SArseniy Krasnov 
108225209a32SArseniy Krasnov static void test_stream_virtio_skb_merge_server(const struct test_opts *opts)
108325209a32SArseniy Krasnov {
108425209a32SArseniy Krasnov 	unsigned char buf[64];
108525209a32SArseniy Krasnov 	ssize_t res;
108625209a32SArseniy Krasnov 	int fd;
108725209a32SArseniy Krasnov 
108825209a32SArseniy Krasnov 	fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
108925209a32SArseniy Krasnov 	if (fd < 0) {
109025209a32SArseniy Krasnov 		perror("accept");
109125209a32SArseniy Krasnov 		exit(EXIT_FAILURE);
109225209a32SArseniy Krasnov 	}
109325209a32SArseniy Krasnov 
109425209a32SArseniy Krasnov 	control_expectln("SEND0");
109525209a32SArseniy Krasnov 
109625209a32SArseniy Krasnov 	/* Read skbuff partially. */
109725209a32SArseniy Krasnov 	res = recv(fd, buf, 2, 0);
109825209a32SArseniy Krasnov 	if (res != 2) {
109925209a32SArseniy Krasnov 		fprintf(stderr, "expected recv(2) returns 2 bytes, got %zi\n", res);
110025209a32SArseniy Krasnov 		exit(EXIT_FAILURE);
110125209a32SArseniy Krasnov 	}
110225209a32SArseniy Krasnov 
110325209a32SArseniy Krasnov 	control_writeln("REPLY0");
110425209a32SArseniy Krasnov 	control_expectln("SEND1");
110525209a32SArseniy Krasnov 
110625209a32SArseniy Krasnov 	res = recv(fd, buf + 2, sizeof(buf) - 2, 0);
110725209a32SArseniy Krasnov 	if (res != 8) {
110825209a32SArseniy Krasnov 		fprintf(stderr, "expected recv(2) returns 8 bytes, got %zi\n", res);
110925209a32SArseniy Krasnov 		exit(EXIT_FAILURE);
111025209a32SArseniy Krasnov 	}
111125209a32SArseniy Krasnov 
111225209a32SArseniy Krasnov 	res = recv(fd, buf, sizeof(buf) - 8 - 2, MSG_DONTWAIT);
111325209a32SArseniy Krasnov 	if (res != -1) {
111425209a32SArseniy Krasnov 		fprintf(stderr, "expected recv(2) failure, got %zi\n", res);
111525209a32SArseniy Krasnov 		exit(EXIT_FAILURE);
111625209a32SArseniy Krasnov 	}
111725209a32SArseniy Krasnov 
111825209a32SArseniy Krasnov 	if (memcmp(buf, HELLO_STR WORLD_STR, strlen(HELLO_STR WORLD_STR))) {
111925209a32SArseniy Krasnov 		fprintf(stderr, "pattern mismatch\n");
112025209a32SArseniy Krasnov 		exit(EXIT_FAILURE);
112125209a32SArseniy Krasnov 	}
112225209a32SArseniy Krasnov 
112325209a32SArseniy Krasnov 	control_writeln("REPLY1");
112425209a32SArseniy Krasnov 
112525209a32SArseniy Krasnov 	close(fd);
112625209a32SArseniy Krasnov }
112725209a32SArseniy Krasnov 
1128cdbcc18dSStefan Hajnoczi static struct test_case test_cases[] = {
1129cdbcc18dSStefan Hajnoczi 	{
1130cdbcc18dSStefan Hajnoczi 		.name = "SOCK_STREAM connection reset",
1131cdbcc18dSStefan Hajnoczi 		.run_client = test_stream_connection_reset,
1132cdbcc18dSStefan Hajnoczi 	},
1133cdbcc18dSStefan Hajnoczi 	{
11349de9f7d1SSebastien Boeuf 		.name = "SOCK_STREAM bind only",
11359de9f7d1SSebastien Boeuf 		.run_client = test_stream_bind_only_client,
11369de9f7d1SSebastien Boeuf 		.run_server = test_stream_bind_only_server,
11379de9f7d1SSebastien Boeuf 	},
11389de9f7d1SSebastien Boeuf 	{
1139cdbcc18dSStefan Hajnoczi 		.name = "SOCK_STREAM client close",
1140cdbcc18dSStefan Hajnoczi 		.run_client = test_stream_client_close_client,
1141cdbcc18dSStefan Hajnoczi 		.run_server = test_stream_client_close_server,
1142cdbcc18dSStefan Hajnoczi 	},
1143cdbcc18dSStefan Hajnoczi 	{
1144cdbcc18dSStefan Hajnoczi 		.name = "SOCK_STREAM server close",
1145cdbcc18dSStefan Hajnoczi 		.run_client = test_stream_server_close_client,
1146cdbcc18dSStefan Hajnoczi 		.run_server = test_stream_server_close_server,
1147cdbcc18dSStefan Hajnoczi 	},
1148cdbcc18dSStefan Hajnoczi 	{
1149cdbcc18dSStefan Hajnoczi 		.name = "SOCK_STREAM multiple connections",
1150cdbcc18dSStefan Hajnoczi 		.run_client = test_stream_multiconn_client,
1151cdbcc18dSStefan Hajnoczi 		.run_server = test_stream_multiconn_server,
1152cdbcc18dSStefan Hajnoczi 	},
1153d6269a93SStefano Garzarella 	{
1154d6269a93SStefano Garzarella 		.name = "SOCK_STREAM MSG_PEEK",
1155d6269a93SStefano Garzarella 		.run_client = test_stream_msg_peek_client,
1156d6269a93SStefano Garzarella 		.run_server = test_stream_msg_peek_server,
1157d6269a93SStefano Garzarella 	},
115841b792d7SArseny Krasnov 	{
115941b792d7SArseny Krasnov 		.name = "SOCK_SEQPACKET msg bounds",
116041b792d7SArseny Krasnov 		.run_client = test_seqpacket_msg_bounds_client,
116141b792d7SArseny Krasnov 		.run_server = test_seqpacket_msg_bounds_server,
116241b792d7SArseny Krasnov 	},
116341b792d7SArseny Krasnov 	{
116441b792d7SArseny Krasnov 		.name = "SOCK_SEQPACKET MSG_TRUNC flag",
116541b792d7SArseny Krasnov 		.run_client = test_seqpacket_msg_trunc_client,
116641b792d7SArseny Krasnov 		.run_server = test_seqpacket_msg_trunc_server,
116741b792d7SArseny Krasnov 	},
1168efb3719fSKrasnov Arseniy Vladimirovich 	{
1169efb3719fSKrasnov Arseniy Vladimirovich 		.name = "SOCK_SEQPACKET timeout",
1170efb3719fSKrasnov Arseniy Vladimirovich 		.run_client = test_seqpacket_timeout_client,
1171efb3719fSKrasnov Arseniy Vladimirovich 		.run_server = test_seqpacket_timeout_server,
1172efb3719fSKrasnov Arseniy Vladimirovich 	},
1173e89600ebSKrasnov Arseniy Vladimirovich 	{
1174e89600ebSKrasnov Arseniy Vladimirovich 		.name = "SOCK_SEQPACKET invalid receive buffer",
1175e89600ebSKrasnov Arseniy Vladimirovich 		.run_client = test_seqpacket_invalid_rec_buffer_client,
1176e89600ebSKrasnov Arseniy Vladimirovich 		.run_server = test_seqpacket_invalid_rec_buffer_server,
1177e89600ebSKrasnov Arseniy Vladimirovich 	},
1178b1346338SArseniy Krasnov 	{
1179b1346338SArseniy Krasnov 		.name = "SOCK_STREAM poll() + SO_RCVLOWAT",
1180b1346338SArseniy Krasnov 		.run_client = test_stream_poll_rcvlowat_client,
1181b1346338SArseniy Krasnov 		.run_server = test_stream_poll_rcvlowat_server,
1182b1346338SArseniy Krasnov 	},
1183685a21c3SArseniy Krasnov 	{
1184685a21c3SArseniy Krasnov 		.name = "SOCK_SEQPACKET big message",
1185685a21c3SArseniy Krasnov 		.run_client = test_seqpacket_bigmsg_client,
1186685a21c3SArseniy Krasnov 		.run_server = test_seqpacket_bigmsg_server,
1187685a21c3SArseniy Krasnov 	},
11887e699d2aSArseniy Krasnov 	{
11897e699d2aSArseniy Krasnov 		.name = "SOCK_STREAM test invalid buffer",
11907e699d2aSArseniy Krasnov 		.run_client = test_stream_inv_buf_client,
11917e699d2aSArseniy Krasnov 		.run_server = test_stream_inv_buf_server,
11927e699d2aSArseniy Krasnov 	},
11937e699d2aSArseniy Krasnov 	{
11947e699d2aSArseniy Krasnov 		.name = "SOCK_SEQPACKET test invalid buffer",
11957e699d2aSArseniy Krasnov 		.run_client = test_seqpacket_inv_buf_client,
11967e699d2aSArseniy Krasnov 		.run_server = test_seqpacket_inv_buf_server,
11977e699d2aSArseniy Krasnov 	},
119825209a32SArseniy Krasnov 	{
119925209a32SArseniy Krasnov 		.name = "SOCK_STREAM virtio skb merge",
120025209a32SArseniy Krasnov 		.run_client = test_stream_virtio_skb_merge_client,
120125209a32SArseniy Krasnov 		.run_server = test_stream_virtio_skb_merge_server,
120225209a32SArseniy Krasnov 	},
1203cdbcc18dSStefan Hajnoczi 	{},
1204cdbcc18dSStefan Hajnoczi };
1205cdbcc18dSStefan Hajnoczi 
1206cdbcc18dSStefan Hajnoczi static const char optstring[] = "";
1207cdbcc18dSStefan Hajnoczi static const struct option longopts[] = {
1208cdbcc18dSStefan Hajnoczi 	{
1209cdbcc18dSStefan Hajnoczi 		.name = "control-host",
1210cdbcc18dSStefan Hajnoczi 		.has_arg = required_argument,
1211cdbcc18dSStefan Hajnoczi 		.val = 'H',
1212cdbcc18dSStefan Hajnoczi 	},
1213cdbcc18dSStefan Hajnoczi 	{
1214cdbcc18dSStefan Hajnoczi 		.name = "control-port",
1215cdbcc18dSStefan Hajnoczi 		.has_arg = required_argument,
1216cdbcc18dSStefan Hajnoczi 		.val = 'P',
1217cdbcc18dSStefan Hajnoczi 	},
1218cdbcc18dSStefan Hajnoczi 	{
1219cdbcc18dSStefan Hajnoczi 		.name = "mode",
1220cdbcc18dSStefan Hajnoczi 		.has_arg = required_argument,
1221cdbcc18dSStefan Hajnoczi 		.val = 'm',
1222cdbcc18dSStefan Hajnoczi 	},
1223cdbcc18dSStefan Hajnoczi 	{
1224cdbcc18dSStefan Hajnoczi 		.name = "peer-cid",
1225cdbcc18dSStefan Hajnoczi 		.has_arg = required_argument,
1226cdbcc18dSStefan Hajnoczi 		.val = 'p',
1227cdbcc18dSStefan Hajnoczi 	},
1228cdbcc18dSStefan Hajnoczi 	{
12295a2b2425SStefano Garzarella 		.name = "list",
12305a2b2425SStefano Garzarella 		.has_arg = no_argument,
12315a2b2425SStefano Garzarella 		.val = 'l',
12325a2b2425SStefano Garzarella 	},
12335a2b2425SStefano Garzarella 	{
12345a2b2425SStefano Garzarella 		.name = "skip",
12355a2b2425SStefano Garzarella 		.has_arg = required_argument,
12365a2b2425SStefano Garzarella 		.val = 's',
12375a2b2425SStefano Garzarella 	},
12385a2b2425SStefano Garzarella 	{
1239cdbcc18dSStefan Hajnoczi 		.name = "help",
1240cdbcc18dSStefan Hajnoczi 		.has_arg = no_argument,
1241cdbcc18dSStefan Hajnoczi 		.val = '?',
1242cdbcc18dSStefan Hajnoczi 	},
1243cdbcc18dSStefan Hajnoczi 	{},
1244cdbcc18dSStefan Hajnoczi };
1245cdbcc18dSStefan Hajnoczi 
1246cdbcc18dSStefan Hajnoczi static void usage(void)
1247cdbcc18dSStefan Hajnoczi {
12485a2b2425SStefano Garzarella 	fprintf(stderr, "Usage: vsock_test [--help] [--control-host=<host>] --control-port=<port> --mode=client|server --peer-cid=<cid> [--list] [--skip=<test_id>]\n"
1249cdbcc18dSStefan Hajnoczi 		"\n"
1250cdbcc18dSStefan Hajnoczi 		"  Server: vsock_test --control-port=1234 --mode=server --peer-cid=3\n"
1251cdbcc18dSStefan Hajnoczi 		"  Client: vsock_test --control-host=192.168.0.1 --control-port=1234 --mode=client --peer-cid=2\n"
1252cdbcc18dSStefan Hajnoczi 		"\n"
1253cdbcc18dSStefan Hajnoczi 		"Run vsock.ko tests.  Must be launched in both guest\n"
1254cdbcc18dSStefan Hajnoczi 		"and host.  One side must use --mode=client and\n"
1255cdbcc18dSStefan Hajnoczi 		"the other side must use --mode=server.\n"
1256cdbcc18dSStefan Hajnoczi 		"\n"
1257cdbcc18dSStefan Hajnoczi 		"A TCP control socket connection is used to coordinate tests\n"
1258cdbcc18dSStefan Hajnoczi 		"between the client and the server.  The server requires a\n"
1259cdbcc18dSStefan Hajnoczi 		"listen address and the client requires an address to\n"
1260cdbcc18dSStefan Hajnoczi 		"connect to.\n"
1261cdbcc18dSStefan Hajnoczi 		"\n"
12628d00b93fSStefano Garzarella 		"The CID of the other side must be given with --peer-cid=<cid>.\n"
12638d00b93fSStefano Garzarella 		"\n"
12648d00b93fSStefano Garzarella 		"Options:\n"
12658d00b93fSStefano Garzarella 		"  --help                 This help message\n"
12668d00b93fSStefano Garzarella 		"  --control-host <host>  Server IP address to connect to\n"
12678d00b93fSStefano Garzarella 		"  --control-port <port>  Server port to listen on/connect to\n"
12688d00b93fSStefano Garzarella 		"  --mode client|server   Server or client mode\n"
12698d00b93fSStefano Garzarella 		"  --peer-cid <cid>       CID of the other side\n"
12708d00b93fSStefano Garzarella 		"  --list                 List of tests that will be executed\n"
12718d00b93fSStefano Garzarella 		"  --skip <test_id>       Test ID to skip;\n"
12728d00b93fSStefano Garzarella 		"                         use multiple --skip options to skip more tests\n"
12738d00b93fSStefano Garzarella 		);
1274cdbcc18dSStefan Hajnoczi 	exit(EXIT_FAILURE);
1275cdbcc18dSStefan Hajnoczi }
1276cdbcc18dSStefan Hajnoczi 
1277cdbcc18dSStefan Hajnoczi int main(int argc, char **argv)
1278cdbcc18dSStefan Hajnoczi {
1279cdbcc18dSStefan Hajnoczi 	const char *control_host = NULL;
1280cdbcc18dSStefan Hajnoczi 	const char *control_port = NULL;
1281cdbcc18dSStefan Hajnoczi 	struct test_opts opts = {
1282cdbcc18dSStefan Hajnoczi 		.mode = TEST_MODE_UNSET,
1283cdbcc18dSStefan Hajnoczi 		.peer_cid = VMADDR_CID_ANY,
1284cdbcc18dSStefan Hajnoczi 	};
1285cdbcc18dSStefan Hajnoczi 
12865c338112SArseniy Krasnov 	srand(time(NULL));
1287cdbcc18dSStefan Hajnoczi 	init_signals();
1288cdbcc18dSStefan Hajnoczi 
1289cdbcc18dSStefan Hajnoczi 	for (;;) {
1290cdbcc18dSStefan Hajnoczi 		int opt = getopt_long(argc, argv, optstring, longopts, NULL);
1291cdbcc18dSStefan Hajnoczi 
1292cdbcc18dSStefan Hajnoczi 		if (opt == -1)
1293cdbcc18dSStefan Hajnoczi 			break;
1294cdbcc18dSStefan Hajnoczi 
1295cdbcc18dSStefan Hajnoczi 		switch (opt) {
1296cdbcc18dSStefan Hajnoczi 		case 'H':
1297cdbcc18dSStefan Hajnoczi 			control_host = optarg;
1298cdbcc18dSStefan Hajnoczi 			break;
1299cdbcc18dSStefan Hajnoczi 		case 'm':
1300cdbcc18dSStefan Hajnoczi 			if (strcmp(optarg, "client") == 0)
1301cdbcc18dSStefan Hajnoczi 				opts.mode = TEST_MODE_CLIENT;
1302cdbcc18dSStefan Hajnoczi 			else if (strcmp(optarg, "server") == 0)
1303cdbcc18dSStefan Hajnoczi 				opts.mode = TEST_MODE_SERVER;
1304cdbcc18dSStefan Hajnoczi 			else {
1305cdbcc18dSStefan Hajnoczi 				fprintf(stderr, "--mode must be \"client\" or \"server\"\n");
1306cdbcc18dSStefan Hajnoczi 				return EXIT_FAILURE;
1307cdbcc18dSStefan Hajnoczi 			}
1308cdbcc18dSStefan Hajnoczi 			break;
1309cdbcc18dSStefan Hajnoczi 		case 'p':
1310cdbcc18dSStefan Hajnoczi 			opts.peer_cid = parse_cid(optarg);
1311cdbcc18dSStefan Hajnoczi 			break;
1312cdbcc18dSStefan Hajnoczi 		case 'P':
1313cdbcc18dSStefan Hajnoczi 			control_port = optarg;
1314cdbcc18dSStefan Hajnoczi 			break;
13155a2b2425SStefano Garzarella 		case 'l':
13165a2b2425SStefano Garzarella 			list_tests(test_cases);
13175a2b2425SStefano Garzarella 			break;
13185a2b2425SStefano Garzarella 		case 's':
13195a2b2425SStefano Garzarella 			skip_test(test_cases, ARRAY_SIZE(test_cases) - 1,
13205a2b2425SStefano Garzarella 				  optarg);
13215a2b2425SStefano Garzarella 			break;
1322cdbcc18dSStefan Hajnoczi 		case '?':
1323cdbcc18dSStefan Hajnoczi 		default:
1324cdbcc18dSStefan Hajnoczi 			usage();
1325cdbcc18dSStefan Hajnoczi 		}
1326cdbcc18dSStefan Hajnoczi 	}
1327cdbcc18dSStefan Hajnoczi 
1328cdbcc18dSStefan Hajnoczi 	if (!control_port)
1329cdbcc18dSStefan Hajnoczi 		usage();
1330cdbcc18dSStefan Hajnoczi 	if (opts.mode == TEST_MODE_UNSET)
1331cdbcc18dSStefan Hajnoczi 		usage();
1332cdbcc18dSStefan Hajnoczi 	if (opts.peer_cid == VMADDR_CID_ANY)
1333cdbcc18dSStefan Hajnoczi 		usage();
1334cdbcc18dSStefan Hajnoczi 
1335cdbcc18dSStefan Hajnoczi 	if (!control_host) {
1336cdbcc18dSStefan Hajnoczi 		if (opts.mode != TEST_MODE_SERVER)
1337cdbcc18dSStefan Hajnoczi 			usage();
1338cdbcc18dSStefan Hajnoczi 		control_host = "0.0.0.0";
1339cdbcc18dSStefan Hajnoczi 	}
1340cdbcc18dSStefan Hajnoczi 
1341cdbcc18dSStefan Hajnoczi 	control_init(control_host, control_port,
1342cdbcc18dSStefan Hajnoczi 		     opts.mode == TEST_MODE_SERVER);
1343cdbcc18dSStefan Hajnoczi 
1344cdbcc18dSStefan Hajnoczi 	run_tests(test_cases, &opts);
1345cdbcc18dSStefan Hajnoczi 
1346cdbcc18dSStefan Hajnoczi 	control_cleanup();
1347cdbcc18dSStefan Hajnoczi 	return EXIT_SUCCESS;
1348cdbcc18dSStefan Hajnoczi }
1349