xref: /openbmc/linux/tools/testing/vsock/util.c (revision 092f32ae)
1df7e0e0dSStefan Hajnoczi // SPDX-License-Identifier: GPL-2.0-only
2df7e0e0dSStefan Hajnoczi /*
3df7e0e0dSStefan Hajnoczi  * vsock test utilities
4df7e0e0dSStefan Hajnoczi  *
5df7e0e0dSStefan Hajnoczi  * Copyright (C) 2017 Red Hat, Inc.
6df7e0e0dSStefan Hajnoczi  *
7df7e0e0dSStefan Hajnoczi  * Author: Stefan Hajnoczi <stefanha@redhat.com>
8df7e0e0dSStefan Hajnoczi  */
9df7e0e0dSStefan Hajnoczi 
10df7e0e0dSStefan Hajnoczi #include <errno.h>
11df7e0e0dSStefan Hajnoczi #include <stdio.h>
12092f32aeSStefan Hajnoczi #include <stdint.h>
13df7e0e0dSStefan Hajnoczi #include <stdlib.h>
14df7e0e0dSStefan Hajnoczi #include <signal.h>
159bb8a29dSStefan Hajnoczi #include <unistd.h>
16df7e0e0dSStefan Hajnoczi 
17df7e0e0dSStefan Hajnoczi #include "timeout.h"
189bb8a29dSStefan Hajnoczi #include "control.h"
19df7e0e0dSStefan Hajnoczi #include "util.h"
20df7e0e0dSStefan Hajnoczi 
21df7e0e0dSStefan Hajnoczi /* Install signal handlers */
22df7e0e0dSStefan Hajnoczi void init_signals(void)
23df7e0e0dSStefan Hajnoczi {
24df7e0e0dSStefan Hajnoczi 	struct sigaction act = {
25df7e0e0dSStefan Hajnoczi 		.sa_handler = sigalrm,
26df7e0e0dSStefan Hajnoczi 	};
27df7e0e0dSStefan Hajnoczi 
28df7e0e0dSStefan Hajnoczi 	sigaction(SIGALRM, &act, NULL);
29df7e0e0dSStefan Hajnoczi 	signal(SIGPIPE, SIG_IGN);
30df7e0e0dSStefan Hajnoczi }
31df7e0e0dSStefan Hajnoczi 
32df7e0e0dSStefan Hajnoczi /* Parse a CID in string representation */
33df7e0e0dSStefan Hajnoczi unsigned int parse_cid(const char *str)
34df7e0e0dSStefan Hajnoczi {
35df7e0e0dSStefan Hajnoczi 	char *endptr = NULL;
36df7e0e0dSStefan Hajnoczi 	unsigned long n;
37df7e0e0dSStefan Hajnoczi 
38df7e0e0dSStefan Hajnoczi 	errno = 0;
39df7e0e0dSStefan Hajnoczi 	n = strtoul(str, &endptr, 10);
40df7e0e0dSStefan Hajnoczi 	if (errno || *endptr != '\0') {
41df7e0e0dSStefan Hajnoczi 		fprintf(stderr, "malformed CID \"%s\"\n", str);
42df7e0e0dSStefan Hajnoczi 		exit(EXIT_FAILURE);
43df7e0e0dSStefan Hajnoczi 	}
44df7e0e0dSStefan Hajnoczi 	return n;
45df7e0e0dSStefan Hajnoczi }
46df7e0e0dSStefan Hajnoczi 
479bb8a29dSStefan Hajnoczi /* Connect to <cid, port> and return the file descriptor. */
489bb8a29dSStefan Hajnoczi int vsock_stream_connect(unsigned int cid, unsigned int port)
499bb8a29dSStefan Hajnoczi {
509bb8a29dSStefan Hajnoczi 	union {
519bb8a29dSStefan Hajnoczi 		struct sockaddr sa;
529bb8a29dSStefan Hajnoczi 		struct sockaddr_vm svm;
539bb8a29dSStefan Hajnoczi 	} addr = {
549bb8a29dSStefan Hajnoczi 		.svm = {
559bb8a29dSStefan Hajnoczi 			.svm_family = AF_VSOCK,
569bb8a29dSStefan Hajnoczi 			.svm_port = port,
579bb8a29dSStefan Hajnoczi 			.svm_cid = cid,
589bb8a29dSStefan Hajnoczi 		},
599bb8a29dSStefan Hajnoczi 	};
609bb8a29dSStefan Hajnoczi 	int ret;
619bb8a29dSStefan Hajnoczi 	int fd;
629bb8a29dSStefan Hajnoczi 
639bb8a29dSStefan Hajnoczi 	control_expectln("LISTENING");
649bb8a29dSStefan Hajnoczi 
659bb8a29dSStefan Hajnoczi 	fd = socket(AF_VSOCK, SOCK_STREAM, 0);
669bb8a29dSStefan Hajnoczi 
679bb8a29dSStefan Hajnoczi 	timeout_begin(TIMEOUT);
689bb8a29dSStefan Hajnoczi 	do {
699bb8a29dSStefan Hajnoczi 		ret = connect(fd, &addr.sa, sizeof(addr.svm));
709bb8a29dSStefan Hajnoczi 		timeout_check("connect");
719bb8a29dSStefan Hajnoczi 	} while (ret < 0 && errno == EINTR);
729bb8a29dSStefan Hajnoczi 	timeout_end();
739bb8a29dSStefan Hajnoczi 
749bb8a29dSStefan Hajnoczi 	if (ret < 0) {
759bb8a29dSStefan Hajnoczi 		int old_errno = errno;
769bb8a29dSStefan Hajnoczi 
779bb8a29dSStefan Hajnoczi 		close(fd);
789bb8a29dSStefan Hajnoczi 		fd = -1;
799bb8a29dSStefan Hajnoczi 		errno = old_errno;
809bb8a29dSStefan Hajnoczi 	}
819bb8a29dSStefan Hajnoczi 	return fd;
829bb8a29dSStefan Hajnoczi }
839bb8a29dSStefan Hajnoczi 
849bb8a29dSStefan Hajnoczi /* Listen on <cid, port> and return the first incoming connection.  The remote
859bb8a29dSStefan Hajnoczi  * address is stored to clientaddrp.  clientaddrp may be NULL.
869bb8a29dSStefan Hajnoczi  */
879bb8a29dSStefan Hajnoczi int vsock_stream_accept(unsigned int cid, unsigned int port,
889bb8a29dSStefan Hajnoczi 			struct sockaddr_vm *clientaddrp)
899bb8a29dSStefan Hajnoczi {
909bb8a29dSStefan Hajnoczi 	union {
919bb8a29dSStefan Hajnoczi 		struct sockaddr sa;
929bb8a29dSStefan Hajnoczi 		struct sockaddr_vm svm;
939bb8a29dSStefan Hajnoczi 	} addr = {
949bb8a29dSStefan Hajnoczi 		.svm = {
959bb8a29dSStefan Hajnoczi 			.svm_family = AF_VSOCK,
969bb8a29dSStefan Hajnoczi 			.svm_port = port,
979bb8a29dSStefan Hajnoczi 			.svm_cid = cid,
989bb8a29dSStefan Hajnoczi 		},
999bb8a29dSStefan Hajnoczi 	};
1009bb8a29dSStefan Hajnoczi 	union {
1019bb8a29dSStefan Hajnoczi 		struct sockaddr sa;
1029bb8a29dSStefan Hajnoczi 		struct sockaddr_vm svm;
1039bb8a29dSStefan Hajnoczi 	} clientaddr;
1049bb8a29dSStefan Hajnoczi 	socklen_t clientaddr_len = sizeof(clientaddr.svm);
1059bb8a29dSStefan Hajnoczi 	int fd;
1069bb8a29dSStefan Hajnoczi 	int client_fd;
1079bb8a29dSStefan Hajnoczi 	int old_errno;
1089bb8a29dSStefan Hajnoczi 
1099bb8a29dSStefan Hajnoczi 	fd = socket(AF_VSOCK, SOCK_STREAM, 0);
1109bb8a29dSStefan Hajnoczi 
1119bb8a29dSStefan Hajnoczi 	if (bind(fd, &addr.sa, sizeof(addr.svm)) < 0) {
1129bb8a29dSStefan Hajnoczi 		perror("bind");
1139bb8a29dSStefan Hajnoczi 		exit(EXIT_FAILURE);
1149bb8a29dSStefan Hajnoczi 	}
1159bb8a29dSStefan Hajnoczi 
1169bb8a29dSStefan Hajnoczi 	if (listen(fd, 1) < 0) {
1179bb8a29dSStefan Hajnoczi 		perror("listen");
1189bb8a29dSStefan Hajnoczi 		exit(EXIT_FAILURE);
1199bb8a29dSStefan Hajnoczi 	}
1209bb8a29dSStefan Hajnoczi 
1219bb8a29dSStefan Hajnoczi 	control_writeln("LISTENING");
1229bb8a29dSStefan Hajnoczi 
1239bb8a29dSStefan Hajnoczi 	timeout_begin(TIMEOUT);
1249bb8a29dSStefan Hajnoczi 	do {
1259bb8a29dSStefan Hajnoczi 		client_fd = accept(fd, &clientaddr.sa, &clientaddr_len);
1269bb8a29dSStefan Hajnoczi 		timeout_check("accept");
1279bb8a29dSStefan Hajnoczi 	} while (client_fd < 0 && errno == EINTR);
1289bb8a29dSStefan Hajnoczi 	timeout_end();
1299bb8a29dSStefan Hajnoczi 
1309bb8a29dSStefan Hajnoczi 	old_errno = errno;
1319bb8a29dSStefan Hajnoczi 	close(fd);
1329bb8a29dSStefan Hajnoczi 	errno = old_errno;
1339bb8a29dSStefan Hajnoczi 
1349bb8a29dSStefan Hajnoczi 	if (client_fd < 0)
1359bb8a29dSStefan Hajnoczi 		return client_fd;
1369bb8a29dSStefan Hajnoczi 
1379bb8a29dSStefan Hajnoczi 	if (clientaddr_len != sizeof(clientaddr.svm)) {
1389bb8a29dSStefan Hajnoczi 		fprintf(stderr, "unexpected addrlen from accept(2), %zu\n",
1399bb8a29dSStefan Hajnoczi 			(size_t)clientaddr_len);
1409bb8a29dSStefan Hajnoczi 		exit(EXIT_FAILURE);
1419bb8a29dSStefan Hajnoczi 	}
1429bb8a29dSStefan Hajnoczi 	if (clientaddr.sa.sa_family != AF_VSOCK) {
1439bb8a29dSStefan Hajnoczi 		fprintf(stderr, "expected AF_VSOCK from accept(2), got %d\n",
1449bb8a29dSStefan Hajnoczi 			clientaddr.sa.sa_family);
1459bb8a29dSStefan Hajnoczi 		exit(EXIT_FAILURE);
1469bb8a29dSStefan Hajnoczi 	}
1479bb8a29dSStefan Hajnoczi 
1489bb8a29dSStefan Hajnoczi 	if (clientaddrp)
1499bb8a29dSStefan Hajnoczi 		*clientaddrp = clientaddr.svm;
1509bb8a29dSStefan Hajnoczi 	return client_fd;
1519bb8a29dSStefan Hajnoczi }
1529bb8a29dSStefan Hajnoczi 
153092f32aeSStefan Hajnoczi /* Transmit one byte and check the return value.
154092f32aeSStefan Hajnoczi  *
155092f32aeSStefan Hajnoczi  * expected_ret:
156092f32aeSStefan Hajnoczi  *  <0 Negative errno (for testing errors)
157092f32aeSStefan Hajnoczi  *   0 End-of-file
158092f32aeSStefan Hajnoczi  *   1 Success
159092f32aeSStefan Hajnoczi  */
160092f32aeSStefan Hajnoczi void send_byte(int fd, int expected_ret, int flags)
161092f32aeSStefan Hajnoczi {
162092f32aeSStefan Hajnoczi 	const uint8_t byte = 'A';
163092f32aeSStefan Hajnoczi 	ssize_t nwritten;
164092f32aeSStefan Hajnoczi 
165092f32aeSStefan Hajnoczi 	timeout_begin(TIMEOUT);
166092f32aeSStefan Hajnoczi 	do {
167092f32aeSStefan Hajnoczi 		nwritten = send(fd, &byte, sizeof(byte), flags);
168092f32aeSStefan Hajnoczi 		timeout_check("write");
169092f32aeSStefan Hajnoczi 	} while (nwritten < 0 && errno == EINTR);
170092f32aeSStefan Hajnoczi 	timeout_end();
171092f32aeSStefan Hajnoczi 
172092f32aeSStefan Hajnoczi 	if (expected_ret < 0) {
173092f32aeSStefan Hajnoczi 		if (nwritten != -1) {
174092f32aeSStefan Hajnoczi 			fprintf(stderr, "bogus send(2) return value %zd\n",
175092f32aeSStefan Hajnoczi 				nwritten);
176092f32aeSStefan Hajnoczi 			exit(EXIT_FAILURE);
177092f32aeSStefan Hajnoczi 		}
178092f32aeSStefan Hajnoczi 		if (errno != -expected_ret) {
179092f32aeSStefan Hajnoczi 			perror("write");
180092f32aeSStefan Hajnoczi 			exit(EXIT_FAILURE);
181092f32aeSStefan Hajnoczi 		}
182092f32aeSStefan Hajnoczi 		return;
183092f32aeSStefan Hajnoczi 	}
184092f32aeSStefan Hajnoczi 
185092f32aeSStefan Hajnoczi 	if (nwritten < 0) {
186092f32aeSStefan Hajnoczi 		perror("write");
187092f32aeSStefan Hajnoczi 		exit(EXIT_FAILURE);
188092f32aeSStefan Hajnoczi 	}
189092f32aeSStefan Hajnoczi 	if (nwritten == 0) {
190092f32aeSStefan Hajnoczi 		if (expected_ret == 0)
191092f32aeSStefan Hajnoczi 			return;
192092f32aeSStefan Hajnoczi 
193092f32aeSStefan Hajnoczi 		fprintf(stderr, "unexpected EOF while sending byte\n");
194092f32aeSStefan Hajnoczi 		exit(EXIT_FAILURE);
195092f32aeSStefan Hajnoczi 	}
196092f32aeSStefan Hajnoczi 	if (nwritten != sizeof(byte)) {
197092f32aeSStefan Hajnoczi 		fprintf(stderr, "bogus send(2) return value %zd\n", nwritten);
198092f32aeSStefan Hajnoczi 		exit(EXIT_FAILURE);
199092f32aeSStefan Hajnoczi 	}
200092f32aeSStefan Hajnoczi }
201092f32aeSStefan Hajnoczi 
202092f32aeSStefan Hajnoczi /* Receive one byte and check the return value.
203092f32aeSStefan Hajnoczi  *
204092f32aeSStefan Hajnoczi  * expected_ret:
205092f32aeSStefan Hajnoczi  *  <0 Negative errno (for testing errors)
206092f32aeSStefan Hajnoczi  *   0 End-of-file
207092f32aeSStefan Hajnoczi  *   1 Success
208092f32aeSStefan Hajnoczi  */
209092f32aeSStefan Hajnoczi void recv_byte(int fd, int expected_ret, int flags)
210092f32aeSStefan Hajnoczi {
211092f32aeSStefan Hajnoczi 	uint8_t byte;
212092f32aeSStefan Hajnoczi 	ssize_t nread;
213092f32aeSStefan Hajnoczi 
214092f32aeSStefan Hajnoczi 	timeout_begin(TIMEOUT);
215092f32aeSStefan Hajnoczi 	do {
216092f32aeSStefan Hajnoczi 		nread = recv(fd, &byte, sizeof(byte), flags);
217092f32aeSStefan Hajnoczi 		timeout_check("read");
218092f32aeSStefan Hajnoczi 	} while (nread < 0 && errno == EINTR);
219092f32aeSStefan Hajnoczi 	timeout_end();
220092f32aeSStefan Hajnoczi 
221092f32aeSStefan Hajnoczi 	if (expected_ret < 0) {
222092f32aeSStefan Hajnoczi 		if (nread != -1) {
223092f32aeSStefan Hajnoczi 			fprintf(stderr, "bogus recv(2) return value %zd\n",
224092f32aeSStefan Hajnoczi 				nread);
225092f32aeSStefan Hajnoczi 			exit(EXIT_FAILURE);
226092f32aeSStefan Hajnoczi 		}
227092f32aeSStefan Hajnoczi 		if (errno != -expected_ret) {
228092f32aeSStefan Hajnoczi 			perror("read");
229092f32aeSStefan Hajnoczi 			exit(EXIT_FAILURE);
230092f32aeSStefan Hajnoczi 		}
231092f32aeSStefan Hajnoczi 		return;
232092f32aeSStefan Hajnoczi 	}
233092f32aeSStefan Hajnoczi 
234092f32aeSStefan Hajnoczi 	if (nread < 0) {
235092f32aeSStefan Hajnoczi 		perror("read");
236092f32aeSStefan Hajnoczi 		exit(EXIT_FAILURE);
237092f32aeSStefan Hajnoczi 	}
238092f32aeSStefan Hajnoczi 	if (nread == 0) {
239092f32aeSStefan Hajnoczi 		if (expected_ret == 0)
240092f32aeSStefan Hajnoczi 			return;
241092f32aeSStefan Hajnoczi 
242092f32aeSStefan Hajnoczi 		fprintf(stderr, "unexpected EOF while receiving byte\n");
243092f32aeSStefan Hajnoczi 		exit(EXIT_FAILURE);
244092f32aeSStefan Hajnoczi 	}
245092f32aeSStefan Hajnoczi 	if (nread != sizeof(byte)) {
246092f32aeSStefan Hajnoczi 		fprintf(stderr, "bogus recv(2) return value %zd\n", nread);
247092f32aeSStefan Hajnoczi 		exit(EXIT_FAILURE);
248092f32aeSStefan Hajnoczi 	}
249092f32aeSStefan Hajnoczi 	if (byte != 'A') {
250092f32aeSStefan Hajnoczi 		fprintf(stderr, "unexpected byte read %c\n", byte);
251092f32aeSStefan Hajnoczi 		exit(EXIT_FAILURE);
252092f32aeSStefan Hajnoczi 	}
253092f32aeSStefan Hajnoczi }
254092f32aeSStefan Hajnoczi 
255df7e0e0dSStefan Hajnoczi /* Run test cases.  The program terminates if a failure occurs. */
256df7e0e0dSStefan Hajnoczi void run_tests(const struct test_case *test_cases,
257df7e0e0dSStefan Hajnoczi 	       const struct test_opts *opts)
258df7e0e0dSStefan Hajnoczi {
259df7e0e0dSStefan Hajnoczi 	int i;
260df7e0e0dSStefan Hajnoczi 
261df7e0e0dSStefan Hajnoczi 	for (i = 0; test_cases[i].name; i++) {
262df7e0e0dSStefan Hajnoczi 		void (*run)(const struct test_opts *opts);
263df7e0e0dSStefan Hajnoczi 
264df7e0e0dSStefan Hajnoczi 		printf("%s...", test_cases[i].name);
265df7e0e0dSStefan Hajnoczi 		fflush(stdout);
266df7e0e0dSStefan Hajnoczi 
2672f65b44eSStefan Hajnoczi 		if (opts->mode == TEST_MODE_CLIENT) {
2682f65b44eSStefan Hajnoczi 			/* Full barrier before executing the next test.  This
2692f65b44eSStefan Hajnoczi 			 * ensures that client and server are executing the
2702f65b44eSStefan Hajnoczi 			 * same test case.  In particular, it means whoever is
2712f65b44eSStefan Hajnoczi 			 * faster will not see the peer still executing the
2722f65b44eSStefan Hajnoczi 			 * last test.  This is important because port numbers
2732f65b44eSStefan Hajnoczi 			 * can be used by multiple test cases.
2742f65b44eSStefan Hajnoczi 			 */
2752f65b44eSStefan Hajnoczi 			control_expectln("NEXT");
2762f65b44eSStefan Hajnoczi 			control_writeln("NEXT");
2772f65b44eSStefan Hajnoczi 
278df7e0e0dSStefan Hajnoczi 			run = test_cases[i].run_client;
2792f65b44eSStefan Hajnoczi 		} else {
2802f65b44eSStefan Hajnoczi 			control_writeln("NEXT");
2812f65b44eSStefan Hajnoczi 			control_expectln("NEXT");
2822f65b44eSStefan Hajnoczi 
283df7e0e0dSStefan Hajnoczi 			run = test_cases[i].run_server;
2842f65b44eSStefan Hajnoczi 		}
285df7e0e0dSStefan Hajnoczi 
286df7e0e0dSStefan Hajnoczi 		if (run)
287df7e0e0dSStefan Hajnoczi 			run(opts);
288df7e0e0dSStefan Hajnoczi 
289df7e0e0dSStefan Hajnoczi 		printf("ok\n");
290df7e0e0dSStefan Hajnoczi 	}
291df7e0e0dSStefan Hajnoczi }
292