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