xref: /OK3568_Linux_fs/kernel/tools/testing/vsock/control.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /* Control socket for client/server test execution
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Copyright (C) 2017 Red Hat, Inc.
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * Author: Stefan Hajnoczi <stefanha@redhat.com>
7*4882a593Smuzhiyun  */
8*4882a593Smuzhiyun 
9*4882a593Smuzhiyun /* The client and server may need to coordinate to avoid race conditions like
10*4882a593Smuzhiyun  * the client attempting to connect to a socket that the server is not
11*4882a593Smuzhiyun  * listening on yet.  The control socket offers a communications channel for
12*4882a593Smuzhiyun  * such coordination tasks.
13*4882a593Smuzhiyun  *
14*4882a593Smuzhiyun  * If the client calls control_expectln("LISTENING"), then it will block until
15*4882a593Smuzhiyun  * the server calls control_writeln("LISTENING").  This provides a simple
16*4882a593Smuzhiyun  * mechanism for coordinating between the client and the server.
17*4882a593Smuzhiyun  */
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun #include <errno.h>
20*4882a593Smuzhiyun #include <netdb.h>
21*4882a593Smuzhiyun #include <stdio.h>
22*4882a593Smuzhiyun #include <stdlib.h>
23*4882a593Smuzhiyun #include <string.h>
24*4882a593Smuzhiyun #include <unistd.h>
25*4882a593Smuzhiyun #include <sys/types.h>
26*4882a593Smuzhiyun #include <sys/socket.h>
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun #include "timeout.h"
29*4882a593Smuzhiyun #include "control.h"
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun static int control_fd = -1;
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun /* Open the control socket, either in server or client mode */
control_init(const char * control_host,const char * control_port,bool server)34*4882a593Smuzhiyun void control_init(const char *control_host,
35*4882a593Smuzhiyun 		  const char *control_port,
36*4882a593Smuzhiyun 		  bool server)
37*4882a593Smuzhiyun {
38*4882a593Smuzhiyun 	struct addrinfo hints = {
39*4882a593Smuzhiyun 		.ai_socktype = SOCK_STREAM,
40*4882a593Smuzhiyun 	};
41*4882a593Smuzhiyun 	struct addrinfo *result = NULL;
42*4882a593Smuzhiyun 	struct addrinfo *ai;
43*4882a593Smuzhiyun 	int ret;
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun 	ret = getaddrinfo(control_host, control_port, &hints, &result);
46*4882a593Smuzhiyun 	if (ret != 0) {
47*4882a593Smuzhiyun 		fprintf(stderr, "%s\n", gai_strerror(ret));
48*4882a593Smuzhiyun 		exit(EXIT_FAILURE);
49*4882a593Smuzhiyun 	}
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun 	for (ai = result; ai; ai = ai->ai_next) {
52*4882a593Smuzhiyun 		int fd;
53*4882a593Smuzhiyun 		int val = 1;
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun 		fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
56*4882a593Smuzhiyun 		if (fd < 0)
57*4882a593Smuzhiyun 			continue;
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun 		if (!server) {
60*4882a593Smuzhiyun 			if (connect(fd, ai->ai_addr, ai->ai_addrlen) < 0)
61*4882a593Smuzhiyun 				goto next;
62*4882a593Smuzhiyun 			control_fd = fd;
63*4882a593Smuzhiyun 			printf("Control socket connected to %s:%s.\n",
64*4882a593Smuzhiyun 			       control_host, control_port);
65*4882a593Smuzhiyun 			break;
66*4882a593Smuzhiyun 		}
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun 		if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
69*4882a593Smuzhiyun 			       &val, sizeof(val)) < 0) {
70*4882a593Smuzhiyun 			perror("setsockopt");
71*4882a593Smuzhiyun 			exit(EXIT_FAILURE);
72*4882a593Smuzhiyun 		}
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun 		if (bind(fd, ai->ai_addr, ai->ai_addrlen) < 0)
75*4882a593Smuzhiyun 			goto next;
76*4882a593Smuzhiyun 		if (listen(fd, 1) < 0)
77*4882a593Smuzhiyun 			goto next;
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun 		printf("Control socket listening on %s:%s\n",
80*4882a593Smuzhiyun 		       control_host, control_port);
81*4882a593Smuzhiyun 		fflush(stdout);
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun 		control_fd = accept(fd, NULL, 0);
84*4882a593Smuzhiyun 		close(fd);
85*4882a593Smuzhiyun 
86*4882a593Smuzhiyun 		if (control_fd < 0) {
87*4882a593Smuzhiyun 			perror("accept");
88*4882a593Smuzhiyun 			exit(EXIT_FAILURE);
89*4882a593Smuzhiyun 		}
90*4882a593Smuzhiyun 		printf("Control socket connection accepted...\n");
91*4882a593Smuzhiyun 		break;
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun next:
94*4882a593Smuzhiyun 		close(fd);
95*4882a593Smuzhiyun 	}
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun 	if (control_fd < 0) {
98*4882a593Smuzhiyun 		fprintf(stderr, "Control socket initialization failed.  Invalid address %s:%s?\n",
99*4882a593Smuzhiyun 			control_host, control_port);
100*4882a593Smuzhiyun 		exit(EXIT_FAILURE);
101*4882a593Smuzhiyun 	}
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun 	freeaddrinfo(result);
104*4882a593Smuzhiyun }
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun /* Free resources */
control_cleanup(void)107*4882a593Smuzhiyun void control_cleanup(void)
108*4882a593Smuzhiyun {
109*4882a593Smuzhiyun 	close(control_fd);
110*4882a593Smuzhiyun 	control_fd = -1;
111*4882a593Smuzhiyun }
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun /* Write a line to the control socket */
control_writeln(const char * str)114*4882a593Smuzhiyun void control_writeln(const char *str)
115*4882a593Smuzhiyun {
116*4882a593Smuzhiyun 	ssize_t len = strlen(str);
117*4882a593Smuzhiyun 	ssize_t ret;
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun 	timeout_begin(TIMEOUT);
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun 	do {
122*4882a593Smuzhiyun 		ret = send(control_fd, str, len, MSG_MORE);
123*4882a593Smuzhiyun 		timeout_check("send");
124*4882a593Smuzhiyun 	} while (ret < 0 && errno == EINTR);
125*4882a593Smuzhiyun 
126*4882a593Smuzhiyun 	if (ret != len) {
127*4882a593Smuzhiyun 		perror("send");
128*4882a593Smuzhiyun 		exit(EXIT_FAILURE);
129*4882a593Smuzhiyun 	}
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun 	do {
132*4882a593Smuzhiyun 		ret = send(control_fd, "\n", 1, 0);
133*4882a593Smuzhiyun 		timeout_check("send");
134*4882a593Smuzhiyun 	} while (ret < 0 && errno == EINTR);
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun 	if (ret != 1) {
137*4882a593Smuzhiyun 		perror("send");
138*4882a593Smuzhiyun 		exit(EXIT_FAILURE);
139*4882a593Smuzhiyun 	}
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun 	timeout_end();
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun /* Return the next line from the control socket (without the trailing newline).
145*4882a593Smuzhiyun  *
146*4882a593Smuzhiyun  * The program terminates if a timeout occurs.
147*4882a593Smuzhiyun  *
148*4882a593Smuzhiyun  * The caller must free() the returned string.
149*4882a593Smuzhiyun  */
control_readln(void)150*4882a593Smuzhiyun char *control_readln(void)
151*4882a593Smuzhiyun {
152*4882a593Smuzhiyun 	char *buf = NULL;
153*4882a593Smuzhiyun 	size_t idx = 0;
154*4882a593Smuzhiyun 	size_t buflen = 0;
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun 	timeout_begin(TIMEOUT);
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun 	for (;;) {
159*4882a593Smuzhiyun 		ssize_t ret;
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun 		if (idx >= buflen) {
162*4882a593Smuzhiyun 			char *new_buf;
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun 			new_buf = realloc(buf, buflen + 80);
165*4882a593Smuzhiyun 			if (!new_buf) {
166*4882a593Smuzhiyun 				perror("realloc");
167*4882a593Smuzhiyun 				exit(EXIT_FAILURE);
168*4882a593Smuzhiyun 			}
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun 			buf = new_buf;
171*4882a593Smuzhiyun 			buflen += 80;
172*4882a593Smuzhiyun 		}
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun 		do {
175*4882a593Smuzhiyun 			ret = recv(control_fd, &buf[idx], 1, 0);
176*4882a593Smuzhiyun 			timeout_check("recv");
177*4882a593Smuzhiyun 		} while (ret < 0 && errno == EINTR);
178*4882a593Smuzhiyun 
179*4882a593Smuzhiyun 		if (ret == 0) {
180*4882a593Smuzhiyun 			fprintf(stderr, "unexpected EOF on control socket\n");
181*4882a593Smuzhiyun 			exit(EXIT_FAILURE);
182*4882a593Smuzhiyun 		}
183*4882a593Smuzhiyun 
184*4882a593Smuzhiyun 		if (ret != 1) {
185*4882a593Smuzhiyun 			perror("recv");
186*4882a593Smuzhiyun 			exit(EXIT_FAILURE);
187*4882a593Smuzhiyun 		}
188*4882a593Smuzhiyun 
189*4882a593Smuzhiyun 		if (buf[idx] == '\n') {
190*4882a593Smuzhiyun 			buf[idx] = '\0';
191*4882a593Smuzhiyun 			break;
192*4882a593Smuzhiyun 		}
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun 		idx++;
195*4882a593Smuzhiyun 	}
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun 	timeout_end();
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun 	return buf;
200*4882a593Smuzhiyun }
201*4882a593Smuzhiyun 
202*4882a593Smuzhiyun /* Wait until a given line is received or a timeout occurs */
control_expectln(const char * str)203*4882a593Smuzhiyun void control_expectln(const char *str)
204*4882a593Smuzhiyun {
205*4882a593Smuzhiyun 	char *line;
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun 	line = control_readln();
208*4882a593Smuzhiyun 
209*4882a593Smuzhiyun 	control_cmpln(line, str, true);
210*4882a593Smuzhiyun 
211*4882a593Smuzhiyun 	free(line);
212*4882a593Smuzhiyun }
213*4882a593Smuzhiyun 
control_cmpln(char * line,const char * str,bool fail)214*4882a593Smuzhiyun bool control_cmpln(char *line, const char *str, bool fail)
215*4882a593Smuzhiyun {
216*4882a593Smuzhiyun 	if (strcmp(str, line) == 0)
217*4882a593Smuzhiyun 		return true;
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun 	if (fail) {
220*4882a593Smuzhiyun 		fprintf(stderr, "expected \"%s\" on control socket, got \"%s\"\n",
221*4882a593Smuzhiyun 			str, line);
222*4882a593Smuzhiyun 		exit(EXIT_FAILURE);
223*4882a593Smuzhiyun 	}
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun 	return false;
226*4882a593Smuzhiyun }
227