xref: /OK3568_Linux_fs/kernel/tools/testing/vsock/vsock_test.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * vsock_test - vsock.ko test suite
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2017 Red Hat, Inc.
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * Author: Stefan Hajnoczi <stefanha@redhat.com>
8*4882a593Smuzhiyun  */
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun #include <getopt.h>
11*4882a593Smuzhiyun #include <stdio.h>
12*4882a593Smuzhiyun #include <stdlib.h>
13*4882a593Smuzhiyun #include <string.h>
14*4882a593Smuzhiyun #include <errno.h>
15*4882a593Smuzhiyun #include <unistd.h>
16*4882a593Smuzhiyun #include <linux/kernel.h>
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun #include "timeout.h"
19*4882a593Smuzhiyun #include "control.h"
20*4882a593Smuzhiyun #include "util.h"
21*4882a593Smuzhiyun 
test_stream_connection_reset(const struct test_opts * opts)22*4882a593Smuzhiyun static void test_stream_connection_reset(const struct test_opts *opts)
23*4882a593Smuzhiyun {
24*4882a593Smuzhiyun 	union {
25*4882a593Smuzhiyun 		struct sockaddr sa;
26*4882a593Smuzhiyun 		struct sockaddr_vm svm;
27*4882a593Smuzhiyun 	} addr = {
28*4882a593Smuzhiyun 		.svm = {
29*4882a593Smuzhiyun 			.svm_family = AF_VSOCK,
30*4882a593Smuzhiyun 			.svm_port = 1234,
31*4882a593Smuzhiyun 			.svm_cid = opts->peer_cid,
32*4882a593Smuzhiyun 		},
33*4882a593Smuzhiyun 	};
34*4882a593Smuzhiyun 	int ret;
35*4882a593Smuzhiyun 	int fd;
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun 	fd = socket(AF_VSOCK, SOCK_STREAM, 0);
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun 	timeout_begin(TIMEOUT);
40*4882a593Smuzhiyun 	do {
41*4882a593Smuzhiyun 		ret = connect(fd, &addr.sa, sizeof(addr.svm));
42*4882a593Smuzhiyun 		timeout_check("connect");
43*4882a593Smuzhiyun 	} while (ret < 0 && errno == EINTR);
44*4882a593Smuzhiyun 	timeout_end();
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun 	if (ret != -1) {
47*4882a593Smuzhiyun 		fprintf(stderr, "expected connect(2) failure, got %d\n", ret);
48*4882a593Smuzhiyun 		exit(EXIT_FAILURE);
49*4882a593Smuzhiyun 	}
50*4882a593Smuzhiyun 	if (errno != ECONNRESET) {
51*4882a593Smuzhiyun 		fprintf(stderr, "unexpected connect(2) errno %d\n", errno);
52*4882a593Smuzhiyun 		exit(EXIT_FAILURE);
53*4882a593Smuzhiyun 	}
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun 	close(fd);
56*4882a593Smuzhiyun }
57*4882a593Smuzhiyun 
test_stream_bind_only_client(const struct test_opts * opts)58*4882a593Smuzhiyun static void test_stream_bind_only_client(const struct test_opts *opts)
59*4882a593Smuzhiyun {
60*4882a593Smuzhiyun 	union {
61*4882a593Smuzhiyun 		struct sockaddr sa;
62*4882a593Smuzhiyun 		struct sockaddr_vm svm;
63*4882a593Smuzhiyun 	} addr = {
64*4882a593Smuzhiyun 		.svm = {
65*4882a593Smuzhiyun 			.svm_family = AF_VSOCK,
66*4882a593Smuzhiyun 			.svm_port = 1234,
67*4882a593Smuzhiyun 			.svm_cid = opts->peer_cid,
68*4882a593Smuzhiyun 		},
69*4882a593Smuzhiyun 	};
70*4882a593Smuzhiyun 	int ret;
71*4882a593Smuzhiyun 	int fd;
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun 	/* Wait for the server to be ready */
74*4882a593Smuzhiyun 	control_expectln("BIND");
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun 	fd = socket(AF_VSOCK, SOCK_STREAM, 0);
77*4882a593Smuzhiyun 
78*4882a593Smuzhiyun 	timeout_begin(TIMEOUT);
79*4882a593Smuzhiyun 	do {
80*4882a593Smuzhiyun 		ret = connect(fd, &addr.sa, sizeof(addr.svm));
81*4882a593Smuzhiyun 		timeout_check("connect");
82*4882a593Smuzhiyun 	} while (ret < 0 && errno == EINTR);
83*4882a593Smuzhiyun 	timeout_end();
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun 	if (ret != -1) {
86*4882a593Smuzhiyun 		fprintf(stderr, "expected connect(2) failure, got %d\n", ret);
87*4882a593Smuzhiyun 		exit(EXIT_FAILURE);
88*4882a593Smuzhiyun 	}
89*4882a593Smuzhiyun 	if (errno != ECONNRESET) {
90*4882a593Smuzhiyun 		fprintf(stderr, "unexpected connect(2) errno %d\n", errno);
91*4882a593Smuzhiyun 		exit(EXIT_FAILURE);
92*4882a593Smuzhiyun 	}
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun 	/* Notify the server that the client has finished */
95*4882a593Smuzhiyun 	control_writeln("DONE");
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun 	close(fd);
98*4882a593Smuzhiyun }
99*4882a593Smuzhiyun 
test_stream_bind_only_server(const struct test_opts * opts)100*4882a593Smuzhiyun static void test_stream_bind_only_server(const struct test_opts *opts)
101*4882a593Smuzhiyun {
102*4882a593Smuzhiyun 	union {
103*4882a593Smuzhiyun 		struct sockaddr sa;
104*4882a593Smuzhiyun 		struct sockaddr_vm svm;
105*4882a593Smuzhiyun 	} addr = {
106*4882a593Smuzhiyun 		.svm = {
107*4882a593Smuzhiyun 			.svm_family = AF_VSOCK,
108*4882a593Smuzhiyun 			.svm_port = 1234,
109*4882a593Smuzhiyun 			.svm_cid = VMADDR_CID_ANY,
110*4882a593Smuzhiyun 		},
111*4882a593Smuzhiyun 	};
112*4882a593Smuzhiyun 	int fd;
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun 	fd = socket(AF_VSOCK, SOCK_STREAM, 0);
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun 	if (bind(fd, &addr.sa, sizeof(addr.svm)) < 0) {
117*4882a593Smuzhiyun 		perror("bind");
118*4882a593Smuzhiyun 		exit(EXIT_FAILURE);
119*4882a593Smuzhiyun 	}
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun 	/* Notify the client that the server is ready */
122*4882a593Smuzhiyun 	control_writeln("BIND");
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun 	/* Wait for the client to finish */
125*4882a593Smuzhiyun 	control_expectln("DONE");
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun 	close(fd);
128*4882a593Smuzhiyun }
129*4882a593Smuzhiyun 
test_stream_client_close_client(const struct test_opts * opts)130*4882a593Smuzhiyun static void test_stream_client_close_client(const struct test_opts *opts)
131*4882a593Smuzhiyun {
132*4882a593Smuzhiyun 	int fd;
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun 	fd = vsock_stream_connect(opts->peer_cid, 1234);
135*4882a593Smuzhiyun 	if (fd < 0) {
136*4882a593Smuzhiyun 		perror("connect");
137*4882a593Smuzhiyun 		exit(EXIT_FAILURE);
138*4882a593Smuzhiyun 	}
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun 	send_byte(fd, 1, 0);
141*4882a593Smuzhiyun 	close(fd);
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun 
test_stream_client_close_server(const struct test_opts * opts)144*4882a593Smuzhiyun static void test_stream_client_close_server(const struct test_opts *opts)
145*4882a593Smuzhiyun {
146*4882a593Smuzhiyun 	int fd;
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun 	fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
149*4882a593Smuzhiyun 	if (fd < 0) {
150*4882a593Smuzhiyun 		perror("accept");
151*4882a593Smuzhiyun 		exit(EXIT_FAILURE);
152*4882a593Smuzhiyun 	}
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun 	/* Wait for the remote to close the connection, before check
155*4882a593Smuzhiyun 	 * -EPIPE error on send.
156*4882a593Smuzhiyun 	 */
157*4882a593Smuzhiyun 	vsock_wait_remote_close(fd);
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun 	send_byte(fd, -EPIPE, 0);
160*4882a593Smuzhiyun 	recv_byte(fd, 1, 0);
161*4882a593Smuzhiyun 	recv_byte(fd, 0, 0);
162*4882a593Smuzhiyun 	close(fd);
163*4882a593Smuzhiyun }
164*4882a593Smuzhiyun 
test_stream_server_close_client(const struct test_opts * opts)165*4882a593Smuzhiyun static void test_stream_server_close_client(const struct test_opts *opts)
166*4882a593Smuzhiyun {
167*4882a593Smuzhiyun 	int fd;
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun 	fd = vsock_stream_connect(opts->peer_cid, 1234);
170*4882a593Smuzhiyun 	if (fd < 0) {
171*4882a593Smuzhiyun 		perror("connect");
172*4882a593Smuzhiyun 		exit(EXIT_FAILURE);
173*4882a593Smuzhiyun 	}
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun 	/* Wait for the remote to close the connection, before check
176*4882a593Smuzhiyun 	 * -EPIPE error on send.
177*4882a593Smuzhiyun 	 */
178*4882a593Smuzhiyun 	vsock_wait_remote_close(fd);
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun 	send_byte(fd, -EPIPE, 0);
181*4882a593Smuzhiyun 	recv_byte(fd, 1, 0);
182*4882a593Smuzhiyun 	recv_byte(fd, 0, 0);
183*4882a593Smuzhiyun 	close(fd);
184*4882a593Smuzhiyun }
185*4882a593Smuzhiyun 
test_stream_server_close_server(const struct test_opts * opts)186*4882a593Smuzhiyun static void test_stream_server_close_server(const struct test_opts *opts)
187*4882a593Smuzhiyun {
188*4882a593Smuzhiyun 	int fd;
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun 	fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
191*4882a593Smuzhiyun 	if (fd < 0) {
192*4882a593Smuzhiyun 		perror("accept");
193*4882a593Smuzhiyun 		exit(EXIT_FAILURE);
194*4882a593Smuzhiyun 	}
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun 	send_byte(fd, 1, 0);
197*4882a593Smuzhiyun 	close(fd);
198*4882a593Smuzhiyun }
199*4882a593Smuzhiyun 
200*4882a593Smuzhiyun /* With the standard socket sizes, VMCI is able to support about 100
201*4882a593Smuzhiyun  * concurrent stream connections.
202*4882a593Smuzhiyun  */
203*4882a593Smuzhiyun #define MULTICONN_NFDS 100
204*4882a593Smuzhiyun 
test_stream_multiconn_client(const struct test_opts * opts)205*4882a593Smuzhiyun static void test_stream_multiconn_client(const struct test_opts *opts)
206*4882a593Smuzhiyun {
207*4882a593Smuzhiyun 	int fds[MULTICONN_NFDS];
208*4882a593Smuzhiyun 	int i;
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun 	for (i = 0; i < MULTICONN_NFDS; i++) {
211*4882a593Smuzhiyun 		fds[i] = vsock_stream_connect(opts->peer_cid, 1234);
212*4882a593Smuzhiyun 		if (fds[i] < 0) {
213*4882a593Smuzhiyun 			perror("connect");
214*4882a593Smuzhiyun 			exit(EXIT_FAILURE);
215*4882a593Smuzhiyun 		}
216*4882a593Smuzhiyun 	}
217*4882a593Smuzhiyun 
218*4882a593Smuzhiyun 	for (i = 0; i < MULTICONN_NFDS; i++) {
219*4882a593Smuzhiyun 		if (i % 2)
220*4882a593Smuzhiyun 			recv_byte(fds[i], 1, 0);
221*4882a593Smuzhiyun 		else
222*4882a593Smuzhiyun 			send_byte(fds[i], 1, 0);
223*4882a593Smuzhiyun 	}
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun 	for (i = 0; i < MULTICONN_NFDS; i++)
226*4882a593Smuzhiyun 		close(fds[i]);
227*4882a593Smuzhiyun }
228*4882a593Smuzhiyun 
test_stream_multiconn_server(const struct test_opts * opts)229*4882a593Smuzhiyun static void test_stream_multiconn_server(const struct test_opts *opts)
230*4882a593Smuzhiyun {
231*4882a593Smuzhiyun 	int fds[MULTICONN_NFDS];
232*4882a593Smuzhiyun 	int i;
233*4882a593Smuzhiyun 
234*4882a593Smuzhiyun 	for (i = 0; i < MULTICONN_NFDS; i++) {
235*4882a593Smuzhiyun 		fds[i] = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
236*4882a593Smuzhiyun 		if (fds[i] < 0) {
237*4882a593Smuzhiyun 			perror("accept");
238*4882a593Smuzhiyun 			exit(EXIT_FAILURE);
239*4882a593Smuzhiyun 		}
240*4882a593Smuzhiyun 	}
241*4882a593Smuzhiyun 
242*4882a593Smuzhiyun 	for (i = 0; i < MULTICONN_NFDS; i++) {
243*4882a593Smuzhiyun 		if (i % 2)
244*4882a593Smuzhiyun 			send_byte(fds[i], 1, 0);
245*4882a593Smuzhiyun 		else
246*4882a593Smuzhiyun 			recv_byte(fds[i], 1, 0);
247*4882a593Smuzhiyun 	}
248*4882a593Smuzhiyun 
249*4882a593Smuzhiyun 	for (i = 0; i < MULTICONN_NFDS; i++)
250*4882a593Smuzhiyun 		close(fds[i]);
251*4882a593Smuzhiyun }
252*4882a593Smuzhiyun 
test_stream_msg_peek_client(const struct test_opts * opts)253*4882a593Smuzhiyun static void test_stream_msg_peek_client(const struct test_opts *opts)
254*4882a593Smuzhiyun {
255*4882a593Smuzhiyun 	int fd;
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun 	fd = vsock_stream_connect(opts->peer_cid, 1234);
258*4882a593Smuzhiyun 	if (fd < 0) {
259*4882a593Smuzhiyun 		perror("connect");
260*4882a593Smuzhiyun 		exit(EXIT_FAILURE);
261*4882a593Smuzhiyun 	}
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun 	send_byte(fd, 1, 0);
264*4882a593Smuzhiyun 	close(fd);
265*4882a593Smuzhiyun }
266*4882a593Smuzhiyun 
test_stream_msg_peek_server(const struct test_opts * opts)267*4882a593Smuzhiyun static void test_stream_msg_peek_server(const struct test_opts *opts)
268*4882a593Smuzhiyun {
269*4882a593Smuzhiyun 	int fd;
270*4882a593Smuzhiyun 
271*4882a593Smuzhiyun 	fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
272*4882a593Smuzhiyun 	if (fd < 0) {
273*4882a593Smuzhiyun 		perror("accept");
274*4882a593Smuzhiyun 		exit(EXIT_FAILURE);
275*4882a593Smuzhiyun 	}
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun 	recv_byte(fd, 1, MSG_PEEK);
278*4882a593Smuzhiyun 	recv_byte(fd, 1, 0);
279*4882a593Smuzhiyun 	close(fd);
280*4882a593Smuzhiyun }
281*4882a593Smuzhiyun 
282*4882a593Smuzhiyun static struct test_case test_cases[] = {
283*4882a593Smuzhiyun 	{
284*4882a593Smuzhiyun 		.name = "SOCK_STREAM connection reset",
285*4882a593Smuzhiyun 		.run_client = test_stream_connection_reset,
286*4882a593Smuzhiyun 	},
287*4882a593Smuzhiyun 	{
288*4882a593Smuzhiyun 		.name = "SOCK_STREAM bind only",
289*4882a593Smuzhiyun 		.run_client = test_stream_bind_only_client,
290*4882a593Smuzhiyun 		.run_server = test_stream_bind_only_server,
291*4882a593Smuzhiyun 	},
292*4882a593Smuzhiyun 	{
293*4882a593Smuzhiyun 		.name = "SOCK_STREAM client close",
294*4882a593Smuzhiyun 		.run_client = test_stream_client_close_client,
295*4882a593Smuzhiyun 		.run_server = test_stream_client_close_server,
296*4882a593Smuzhiyun 	},
297*4882a593Smuzhiyun 	{
298*4882a593Smuzhiyun 		.name = "SOCK_STREAM server close",
299*4882a593Smuzhiyun 		.run_client = test_stream_server_close_client,
300*4882a593Smuzhiyun 		.run_server = test_stream_server_close_server,
301*4882a593Smuzhiyun 	},
302*4882a593Smuzhiyun 	{
303*4882a593Smuzhiyun 		.name = "SOCK_STREAM multiple connections",
304*4882a593Smuzhiyun 		.run_client = test_stream_multiconn_client,
305*4882a593Smuzhiyun 		.run_server = test_stream_multiconn_server,
306*4882a593Smuzhiyun 	},
307*4882a593Smuzhiyun 	{
308*4882a593Smuzhiyun 		.name = "SOCK_STREAM MSG_PEEK",
309*4882a593Smuzhiyun 		.run_client = test_stream_msg_peek_client,
310*4882a593Smuzhiyun 		.run_server = test_stream_msg_peek_server,
311*4882a593Smuzhiyun 	},
312*4882a593Smuzhiyun 	{},
313*4882a593Smuzhiyun };
314*4882a593Smuzhiyun 
315*4882a593Smuzhiyun static const char optstring[] = "";
316*4882a593Smuzhiyun static const struct option longopts[] = {
317*4882a593Smuzhiyun 	{
318*4882a593Smuzhiyun 		.name = "control-host",
319*4882a593Smuzhiyun 		.has_arg = required_argument,
320*4882a593Smuzhiyun 		.val = 'H',
321*4882a593Smuzhiyun 	},
322*4882a593Smuzhiyun 	{
323*4882a593Smuzhiyun 		.name = "control-port",
324*4882a593Smuzhiyun 		.has_arg = required_argument,
325*4882a593Smuzhiyun 		.val = 'P',
326*4882a593Smuzhiyun 	},
327*4882a593Smuzhiyun 	{
328*4882a593Smuzhiyun 		.name = "mode",
329*4882a593Smuzhiyun 		.has_arg = required_argument,
330*4882a593Smuzhiyun 		.val = 'm',
331*4882a593Smuzhiyun 	},
332*4882a593Smuzhiyun 	{
333*4882a593Smuzhiyun 		.name = "peer-cid",
334*4882a593Smuzhiyun 		.has_arg = required_argument,
335*4882a593Smuzhiyun 		.val = 'p',
336*4882a593Smuzhiyun 	},
337*4882a593Smuzhiyun 	{
338*4882a593Smuzhiyun 		.name = "list",
339*4882a593Smuzhiyun 		.has_arg = no_argument,
340*4882a593Smuzhiyun 		.val = 'l',
341*4882a593Smuzhiyun 	},
342*4882a593Smuzhiyun 	{
343*4882a593Smuzhiyun 		.name = "skip",
344*4882a593Smuzhiyun 		.has_arg = required_argument,
345*4882a593Smuzhiyun 		.val = 's',
346*4882a593Smuzhiyun 	},
347*4882a593Smuzhiyun 	{
348*4882a593Smuzhiyun 		.name = "help",
349*4882a593Smuzhiyun 		.has_arg = no_argument,
350*4882a593Smuzhiyun 		.val = '?',
351*4882a593Smuzhiyun 	},
352*4882a593Smuzhiyun 	{},
353*4882a593Smuzhiyun };
354*4882a593Smuzhiyun 
usage(void)355*4882a593Smuzhiyun static void usage(void)
356*4882a593Smuzhiyun {
357*4882a593Smuzhiyun 	fprintf(stderr, "Usage: vsock_test [--help] [--control-host=<host>] --control-port=<port> --mode=client|server --peer-cid=<cid> [--list] [--skip=<test_id>]\n"
358*4882a593Smuzhiyun 		"\n"
359*4882a593Smuzhiyun 		"  Server: vsock_test --control-port=1234 --mode=server --peer-cid=3\n"
360*4882a593Smuzhiyun 		"  Client: vsock_test --control-host=192.168.0.1 --control-port=1234 --mode=client --peer-cid=2\n"
361*4882a593Smuzhiyun 		"\n"
362*4882a593Smuzhiyun 		"Run vsock.ko tests.  Must be launched in both guest\n"
363*4882a593Smuzhiyun 		"and host.  One side must use --mode=client and\n"
364*4882a593Smuzhiyun 		"the other side must use --mode=server.\n"
365*4882a593Smuzhiyun 		"\n"
366*4882a593Smuzhiyun 		"A TCP control socket connection is used to coordinate tests\n"
367*4882a593Smuzhiyun 		"between the client and the server.  The server requires a\n"
368*4882a593Smuzhiyun 		"listen address and the client requires an address to\n"
369*4882a593Smuzhiyun 		"connect to.\n"
370*4882a593Smuzhiyun 		"\n"
371*4882a593Smuzhiyun 		"The CID of the other side must be given with --peer-cid=<cid>.\n"
372*4882a593Smuzhiyun 		"\n"
373*4882a593Smuzhiyun 		"Options:\n"
374*4882a593Smuzhiyun 		"  --help                 This help message\n"
375*4882a593Smuzhiyun 		"  --control-host <host>  Server IP address to connect to\n"
376*4882a593Smuzhiyun 		"  --control-port <port>  Server port to listen on/connect to\n"
377*4882a593Smuzhiyun 		"  --mode client|server   Server or client mode\n"
378*4882a593Smuzhiyun 		"  --peer-cid <cid>       CID of the other side\n"
379*4882a593Smuzhiyun 		"  --list                 List of tests that will be executed\n"
380*4882a593Smuzhiyun 		"  --skip <test_id>       Test ID to skip;\n"
381*4882a593Smuzhiyun 		"                         use multiple --skip options to skip more tests\n"
382*4882a593Smuzhiyun 		);
383*4882a593Smuzhiyun 	exit(EXIT_FAILURE);
384*4882a593Smuzhiyun }
385*4882a593Smuzhiyun 
main(int argc,char ** argv)386*4882a593Smuzhiyun int main(int argc, char **argv)
387*4882a593Smuzhiyun {
388*4882a593Smuzhiyun 	const char *control_host = NULL;
389*4882a593Smuzhiyun 	const char *control_port = NULL;
390*4882a593Smuzhiyun 	struct test_opts opts = {
391*4882a593Smuzhiyun 		.mode = TEST_MODE_UNSET,
392*4882a593Smuzhiyun 		.peer_cid = VMADDR_CID_ANY,
393*4882a593Smuzhiyun 	};
394*4882a593Smuzhiyun 
395*4882a593Smuzhiyun 	init_signals();
396*4882a593Smuzhiyun 
397*4882a593Smuzhiyun 	for (;;) {
398*4882a593Smuzhiyun 		int opt = getopt_long(argc, argv, optstring, longopts, NULL);
399*4882a593Smuzhiyun 
400*4882a593Smuzhiyun 		if (opt == -1)
401*4882a593Smuzhiyun 			break;
402*4882a593Smuzhiyun 
403*4882a593Smuzhiyun 		switch (opt) {
404*4882a593Smuzhiyun 		case 'H':
405*4882a593Smuzhiyun 			control_host = optarg;
406*4882a593Smuzhiyun 			break;
407*4882a593Smuzhiyun 		case 'm':
408*4882a593Smuzhiyun 			if (strcmp(optarg, "client") == 0)
409*4882a593Smuzhiyun 				opts.mode = TEST_MODE_CLIENT;
410*4882a593Smuzhiyun 			else if (strcmp(optarg, "server") == 0)
411*4882a593Smuzhiyun 				opts.mode = TEST_MODE_SERVER;
412*4882a593Smuzhiyun 			else {
413*4882a593Smuzhiyun 				fprintf(stderr, "--mode must be \"client\" or \"server\"\n");
414*4882a593Smuzhiyun 				return EXIT_FAILURE;
415*4882a593Smuzhiyun 			}
416*4882a593Smuzhiyun 			break;
417*4882a593Smuzhiyun 		case 'p':
418*4882a593Smuzhiyun 			opts.peer_cid = parse_cid(optarg);
419*4882a593Smuzhiyun 			break;
420*4882a593Smuzhiyun 		case 'P':
421*4882a593Smuzhiyun 			control_port = optarg;
422*4882a593Smuzhiyun 			break;
423*4882a593Smuzhiyun 		case 'l':
424*4882a593Smuzhiyun 			list_tests(test_cases);
425*4882a593Smuzhiyun 			break;
426*4882a593Smuzhiyun 		case 's':
427*4882a593Smuzhiyun 			skip_test(test_cases, ARRAY_SIZE(test_cases) - 1,
428*4882a593Smuzhiyun 				  optarg);
429*4882a593Smuzhiyun 			break;
430*4882a593Smuzhiyun 		case '?':
431*4882a593Smuzhiyun 		default:
432*4882a593Smuzhiyun 			usage();
433*4882a593Smuzhiyun 		}
434*4882a593Smuzhiyun 	}
435*4882a593Smuzhiyun 
436*4882a593Smuzhiyun 	if (!control_port)
437*4882a593Smuzhiyun 		usage();
438*4882a593Smuzhiyun 	if (opts.mode == TEST_MODE_UNSET)
439*4882a593Smuzhiyun 		usage();
440*4882a593Smuzhiyun 	if (opts.peer_cid == VMADDR_CID_ANY)
441*4882a593Smuzhiyun 		usage();
442*4882a593Smuzhiyun 
443*4882a593Smuzhiyun 	if (!control_host) {
444*4882a593Smuzhiyun 		if (opts.mode != TEST_MODE_SERVER)
445*4882a593Smuzhiyun 			usage();
446*4882a593Smuzhiyun 		control_host = "0.0.0.0";
447*4882a593Smuzhiyun 	}
448*4882a593Smuzhiyun 
449*4882a593Smuzhiyun 	control_init(control_host, control_port,
450*4882a593Smuzhiyun 		     opts.mode == TEST_MODE_SERVER);
451*4882a593Smuzhiyun 
452*4882a593Smuzhiyun 	run_tests(test_cases, &opts);
453*4882a593Smuzhiyun 
454*4882a593Smuzhiyun 	control_cleanup();
455*4882a593Smuzhiyun 	return EXIT_SUCCESS;
456*4882a593Smuzhiyun }
457