blob: c7cec6f68c0e5317aee96234c11e2e44d6958406 [file] [log] [blame]
Willy Tarreau9557bac2016-11-12 17:53:16 +01001/*
2 * TCP client and server for bug hunting
3 *
4 * Copyright (C) 2016 Willy Tarreau <w@1wt.eu>
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be
15 * included in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24 * OTHER DEALINGS IN THE SOFTWARE.
25 */
26
Willy Tarreau84393aa2016-11-12 11:29:46 +010027#include <sys/resource.h>
28#include <sys/select.h>
29#include <sys/types.h>
30#include <sys/socket.h>
31#include <sys/stat.h>
32#include <sys/time.h>
33#include <sys/ioctl.h>
Willy Tarreau95a6b782016-11-12 13:25:53 +010034#include <sys/wait.h>
Willy Tarreau84393aa2016-11-12 11:29:46 +010035#include <arpa/inet.h>
36#include <netinet/in.h>
37#include <netinet/tcp.h>
38
39#include <ctype.h>
40#include <errno.h>
41#include <fcntl.h>
Willy Tarreau5cd60672016-12-16 08:02:21 +010042#include <limits.h>
Willy Tarreau84393aa2016-11-12 11:29:46 +010043#include <netdb.h>
44#include <poll.h>
45#include <signal.h>
46#include <stdarg.h>
47#include <stdio.h>
48#include <stdlib.h>
49#include <string.h>
50#include <time.h>
51#include <unistd.h>
52
Willy Tarreau0c0c0a62017-03-14 14:36:26 +010053#ifndef MSG_MORE
54#define MSG_MORE 0
55#endif
Willy Tarreau84393aa2016-11-12 11:29:46 +010056
57struct err_msg {
58 int size;
59 int len;
60 char msg[0];
61};
62
63const int zero = 0;
64const int one = 1;
65const struct linger nolinger = { .l_onoff = 1, .l_linger = 0 };
66
67#define TRASH_SIZE 65536
68static char trash[TRASH_SIZE];
69
Willy Tarreau95a6b782016-11-12 13:25:53 +010070volatile int nbproc = 0;
Willy Tarreau869c7592016-11-12 17:50:57 +010071static struct timeval start_time;
72static int showtime;
73static int verbose;
74static int pid;
75
Willy Tarreau95a6b782016-11-12 13:25:53 +010076
Willy Tarreau84393aa2016-11-12 11:29:46 +010077/* display the message and exit with the code */
78__attribute__((noreturn)) void die(int code, const char *format, ...)
79{
80 va_list args;
81
Willy Tarreau1973e812016-11-12 18:45:42 +010082 if (format) {
83 va_start(args, format);
84 vfprintf(stderr, format, args);
85 va_end(args);
86 }
Willy Tarreau84393aa2016-11-12 11:29:46 +010087 exit(code);
88}
89
90/* display the usage message and exit with the code */
91__attribute__((noreturn)) void usage(int code, const char *arg0)
92{
Willy Tarreau9557bac2016-11-12 17:53:16 +010093 die(code,
94 "Usage : %s [options]* [<ip>:]port [<action>*]\n"
95 "\n"
96 "options :\n"
97 " -v : verbose\n"
98 " -t|-tt|-ttt : show time (msec / relative / absolute)\n"
99 "actions :\n"
100 " L[<backlog>] : Listens to ip:port and optionally sets backlog\n"
101 " Note: fd=socket,bind(fd),listen(fd)\n"
102 " C : Connects to ip:port\n"
103 " Note: fd=socket,connect(fd)\n"
Willy Tarreau2e065cb2020-10-14 08:09:48 +0200104 " D : Disconnect (connect to AF_UNSPEC)\n"
Willy Tarreau9557bac2016-11-12 17:53:16 +0100105 " A[<count>] : Accepts <count> incoming sockets and closes count-1\n"
106 " Note: fd=accept(fd)\n"
Willy Tarreau29cc11c2016-11-12 18:54:20 +0100107 " J : Jump back to oldest post-fork/post-accept action\n"
Willy Tarreaubcd817e2017-03-14 14:44:06 +0100108 " K : kill the connection and go on with next operation\n"
Willy Tarreau9557bac2016-11-12 17:53:16 +0100109 " G : disable lingering\n"
110 " T : set TCP_NODELAY\n"
111 " Q : disable TCP Quick-ack\n"
112 " R[<size>] : Read this amount of bytes. 0=infinite. unset=any amount.\n"
113 " S[<size>] : Send this amount of bytes. 0=infinite. unset=any amount.\n"
Willy Tarreau59623e02016-11-12 18:25:45 +0100114 " S:<string> : Send this exact string. \\r, \\n, \\t, \\\\ supported.\n"
Willy Tarreau9557bac2016-11-12 17:53:16 +0100115 " E[<size>] : Echo this amount of bytes. 0=infinite. unset=any amount.\n"
116 " W[<time>] : Wait for any event on the socket, maximum <time> ms\n"
117 " P[<time>] : Pause for <time> ms (100 by default)\n"
118 " I : wait for Input data to be present (POLLIN)\n"
119 " O : wait for Output queue to be empty (POLLOUT + TIOCOUTQ)\n"
120 " F : FIN : shutdown(SHUT_WR)\n"
Willy Tarreauc3890e52017-10-05 06:31:10 +0200121 " r : shutr : shutdown(SHUT_RD) (pauses a listener or ends recv)\n"
Willy Tarreau9557bac2016-11-12 17:53:16 +0100122 " N<max> : fork New process, limited to <max> concurrent (default 1)\n"
Willy Tarreaub7a6d0d2017-05-02 22:14:59 +0200123 " X[i|o|e]* ** : execvp() next args passing socket as stdin/stdout/stderr.\n"
124 " If i/o/e present, only stdin/out/err are mapped to socket.\n"
Willy Tarreau9557bac2016-11-12 17:53:16 +0100125 "\n"
126 "It's important to note that a single FD is used at once and that Accept\n"
127 "replaces the listening FD with the accepted one. Thus always do it after\n"
128 "a fork if other connections have to be accepted.\n"
129 "\n"
130 "After a fork, we loop back to the beginning and silently skip L/C if the\n"
131 "main socket already exists.\n"
132 "\n"
133 "Example dummy HTTP request drain server :\n"
134 " tcploop 8001 L W N20 A R S10 [ F K ]\n"
135 "\n"
136 "Example large bandwidth HTTP request drain server :\n"
137 " tcploop 8001 L W N20 A R S0 [ F K ]\n"
138 "\n"
139 "Example TCP client with pauses at each step :\n"
140 " tcploop 8001 C T W P100 S10 O P100 R S10 O R G K\n"
Willy Tarreaub7a6d0d2017-05-02 22:14:59 +0200141 "\n"
142 "Simple chargen server :\n"
143 " tcploop 8001 L A Xo cat /dev/zero\n"
144 "\n"
145 "Simple telnet server :\n"
146 " tcploop 8001 L W N A X /usr/sbin/in.telnetd\n"
Willy Tarreau9557bac2016-11-12 17:53:16 +0100147 "", arg0);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100148}
149
Willy Tarreau869c7592016-11-12 17:50:57 +0100150void dolog(const char *format, ...)
151{
152 struct timeval date, tv;
153 int delay;
154 va_list args;
155
156 if (!verbose)
157 return;
158
159 if (showtime) {
160 gettimeofday(&date, NULL);
161 switch (showtime) {
162 case 1: // [msec] relative
163 delay = (date.tv_sec - start_time.tv_sec) * 1000000 + date.tv_usec - start_time.tv_usec;
164 fprintf(stderr, "[%d] ", delay / 1000);
165 break;
166 case 2: // [sec.usec] relative
167 tv.tv_usec = date.tv_usec - start_time.tv_usec;
168 tv.tv_sec = date.tv_sec - start_time.tv_sec;
169 if ((signed)tv.tv_sec > 0) {
170 if ((signed)tv.tv_usec < 0) {
171 tv.tv_usec += 1000000;
172 tv.tv_sec--;
173 }
174 } else if (tv.tv_sec == 0) {
175 if ((signed)tv.tv_usec < 0)
176 tv.tv_usec = 0;
177 } else {
178 tv.tv_sec = 0;
179 tv.tv_usec = 0;
180 }
Willy Tarreau752cc492017-03-14 14:37:13 +0100181 fprintf(stderr, "[%d.%06d] ", (int)tv.tv_sec, (int)tv.tv_usec);
Willy Tarreau869c7592016-11-12 17:50:57 +0100182 break;
183 default: // [sec.usec] absolute
Willy Tarreau752cc492017-03-14 14:37:13 +0100184 fprintf(stderr, "[%d.%06d] ", (int)date.tv_sec, (int)date.tv_usec);
Willy Tarreau869c7592016-11-12 17:50:57 +0100185 break;
186 }
187 }
188
189 fprintf(stderr, "%5d ", pid);
190
191 va_start(args, format);
192 vfprintf(stderr, format, args);
193 va_end(args);
194}
195
Willy Tarreau59623e02016-11-12 18:25:45 +0100196/* convert '\n', '\t', '\r', '\\' to their respective characters */
197int unescape(char *out, int size, const char *in)
198{
199 int len;
200
201 for (len = 0; len < size && *in; in++, out++, len++) {
202 if (*in == '\\') {
203 switch (in[1]) {
204 case 'n' : *out = '\n'; in++; continue;
205 case 't' : *out = '\t'; in++; continue;
206 case 'r' : *out = '\r'; in++; continue;
207 case '\\' : *out = '\\'; in++; continue;
208 default : break;
209 }
210 }
211 *out = *in;
212 }
213 return len;
214}
215
Willy Tarreau84393aa2016-11-12 11:29:46 +0100216struct err_msg *alloc_err_msg(int size)
217{
218 struct err_msg *err;
219
220 err = malloc(sizeof(*err) + size);
221 if (err) {
222 err->len = 0;
223 err->size = size;
224 }
225 return err;
226}
227
Willy Tarreau95a6b782016-11-12 13:25:53 +0100228void sig_handler(int sig)
229{
230 if (sig == SIGCHLD) {
231 while (waitpid(-1, NULL, WNOHANG) > 0)
232 __sync_sub_and_fetch(&nbproc, 1);
233 }
234}
Willy Tarreau84393aa2016-11-12 11:29:46 +0100235
236/* converts str in the form [[<ipv4>|<ipv6>|<hostname>]:]port to struct sockaddr_storage.
237 * Returns < 0 with err set in case of error.
238 */
239int addr_to_ss(char *str, struct sockaddr_storage *ss, struct err_msg *err)
240{
241 char *port_str;
242 int port;
243
244 memset(ss, 0, sizeof(*ss));
245
246 /* look for the addr/port delimiter, it's the last colon. If there's no
247 * colon, it's 0:<port>.
248 */
249 if ((port_str = strrchr(str, ':')) == NULL) {
250 port = atoi(str);
251 if (port <= 0 || port > 65535) {
252 err->len = snprintf(err->msg, err->size, "Missing/invalid port number: '%s'\n", str);
253 return -1;
254 }
255
256 ss->ss_family = AF_INET;
257 ((struct sockaddr_in *)ss)->sin_port = htons(port);
258 ((struct sockaddr_in *)ss)->sin_addr.s_addr = INADDR_ANY;
259 return 0;
260 }
261
262 *port_str++ = 0;
263
264 if (strrchr(str, ':') != NULL) {
265 /* IPv6 address contains ':' */
266 ss->ss_family = AF_INET6;
267 ((struct sockaddr_in6 *)ss)->sin6_port = htons(atoi(port_str));
268
269 if (!inet_pton(ss->ss_family, str, &((struct sockaddr_in6 *)ss)->sin6_addr)) {
270 err->len = snprintf(err->msg, err->size, "Invalid server address: '%s'\n", str);
271 return -1;
272 }
273 }
274 else {
275 ss->ss_family = AF_INET;
276 ((struct sockaddr_in *)ss)->sin_port = htons(atoi(port_str));
277
278 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
279 ((struct sockaddr_in *)ss)->sin_addr.s_addr = INADDR_ANY;
280 return 0;
281 }
282
283 if (!inet_pton(ss->ss_family, str, &((struct sockaddr_in *)ss)->sin_addr)) {
284 struct hostent *he = gethostbyname(str);
285
286 if (he == NULL) {
287 err->len = snprintf(err->msg, err->size, "Invalid server name: '%s'\n", str);
288 return -1;
289 }
290 ((struct sockaddr_in *)ss)->sin_addr = *(struct in_addr *) *(he->h_addr_list);
291 }
292 }
293
294 return 0;
295}
296
297/* waits up to one second on fd <fd> for events <events> (POLLIN|POLLOUT).
298 * returns poll's status.
299 */
300int wait_on_fd(int fd, int events)
301{
302 struct pollfd pollfd;
303 int ret;
304
305 do {
306 pollfd.fd = fd;
307 pollfd.events = events;
308 ret = poll(&pollfd, 1, 1000);
309 } while (ret == -1 && errno == EINTR);
310
311 return ret;
312}
313
314int tcp_set_nodelay(int sock, const char *arg)
315{
Willy Tarreau4bfc6632021-03-31 08:45:47 +0200316 return setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one));
Willy Tarreau84393aa2016-11-12 11:29:46 +0100317}
318
319int tcp_set_nolinger(int sock, const char *arg)
320{
321 return setsockopt(sock, SOL_SOCKET, SO_LINGER, (struct linger *) &nolinger, sizeof(struct linger));
322}
323
324int tcp_set_noquickack(int sock, const char *arg)
325{
Willy Tarreau0c0c0a62017-03-14 14:36:26 +0100326#ifdef TCP_QUICKACK
Willy Tarreau84393aa2016-11-12 11:29:46 +0100327 /* warning: do not use during connect if nothing is to be sent! */
Willy Tarreau4bfc6632021-03-31 08:45:47 +0200328 return setsockopt(sock, IPPROTO_TCP, TCP_QUICKACK, &zero, sizeof(zero));
Willy Tarreau0c0c0a62017-03-14 14:36:26 +0100329#else
330 return 0;
331#endif
Willy Tarreau84393aa2016-11-12 11:29:46 +0100332}
333
334/* Try to listen to address <sa>. Return the fd or -1 in case of error */
335int tcp_listen(const struct sockaddr_storage *sa, const char *arg)
336{
337 int sock;
338 int backlog;
339
340 if (arg[1])
341 backlog = atoi(arg + 1);
342 else
343 backlog = 1000;
344
345 if (backlog < 0 || backlog > 65535) {
346 fprintf(stderr, "backlog must be between 0 and 65535 inclusive (was %d)\n", backlog);
347 return -1;
348 }
349
350 sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
351 if (sock < 0) {
352 perror("socket()");
353 return -1;
354 }
355
356 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) == -1) {
357 perror("setsockopt(SO_REUSEADDR)");
358 goto fail;
359 }
360
361#ifdef SO_REUSEPORT
362 if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (char *) &one, sizeof(one)) == -1) {
363 perror("setsockopt(SO_REUSEPORT)");
364 goto fail;
365 }
366#endif
367 if (bind(sock, (struct sockaddr *)sa, sa->ss_family == AF_INET6 ?
368 sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) == -1) {
369 perror("bind");
370 goto fail;
371 }
372
373 if (listen(sock, backlog) == -1) {
374 perror("listen");
375 goto fail;
376 }
377
378 return sock;
379 fail:
380 close(sock);
381 return -1;
382}
383
384/* accepts a socket from listening socket <sock>, and returns it (or -1 in case of error) */
385int tcp_accept(int sock, const char *arg)
386{
387 int count;
388 int newsock;
389
390 if (arg[1])
391 count = atoi(arg + 1);
392 else
393 count = 1;
394
395 if (count <= 0) {
396 fprintf(stderr, "accept count must be > 0 or unset (was %d)\n", count);
397 return -1;
398 }
399
400 do {
401 newsock = accept(sock, NULL, NULL);
402 if (newsock < 0) { // TODO: improve error handling
403 if (errno == EINTR || errno == EAGAIN || errno == ECONNABORTED)
404 continue;
405 perror("accept()");
406 break;
407 }
408
409 if (count > 1)
410 close(newsock);
411 count--;
412 } while (count > 0);
413
414 fcntl(newsock, F_SETFL, O_NONBLOCK);
415 return newsock;
416}
417
418/* Try to establish a new connection to <sa>. Return the fd or -1 in case of error */
419int tcp_connect(const struct sockaddr_storage *sa, const char *arg)
420{
421 int sock;
422
423 sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
424 if (sock < 0)
425 return -1;
426
427 if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1)
428 goto fail;
429
430 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) == -1)
431 goto fail;
432
Willy Tarreau24d41b92017-03-14 14:50:05 +0100433 if (connect(sock, (const struct sockaddr *)sa, sizeof(struct sockaddr_in)) < 0) {
Willy Tarreau84393aa2016-11-12 11:29:46 +0100434 if (errno != EINPROGRESS)
435 goto fail;
436 }
437
438 return sock;
439 fail:
440 close(sock);
441 return -1;
442}
443
Willy Tarreau2e065cb2020-10-14 08:09:48 +0200444/* Try to disconnect by connecting to AF_UNSPEC. Return >=0 on success, -1 in case of error */
445int tcp_disconnect(int sock)
446{
447 const struct sockaddr sa = { .sa_family = AF_UNSPEC };
448
449 return connect(sock, &sa, sizeof(sa));
450}
451
Willy Tarreau1973e812016-11-12 18:45:42 +0100452/* receives N bytes from the socket and returns 0 (or -1 in case of a recv
453 * error, or -2 in case of an argument error). When no arg is passed, receives
454 * anything and stops. Otherwise reads the requested amount of data. 0 means
455 * read as much as possible.
Willy Tarreau84393aa2016-11-12 11:29:46 +0100456 */
457int tcp_recv(int sock, const char *arg)
458{
459 int count = -1; // stop at first read
460 int ret;
Willy Tarreaua84a2db2017-03-14 14:50:52 +0100461 int max;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100462
463 if (arg[1]) {
464 count = atoi(arg + 1);
465 if (count < 0) {
466 fprintf(stderr, "recv count must be >= 0 or unset (was %d)\n", count);
Willy Tarreau1973e812016-11-12 18:45:42 +0100467 return -2;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100468 }
469 }
470
471 while (1) {
Willy Tarreaua84a2db2017-03-14 14:50:52 +0100472 max = (count > 0) ? count : INT_MAX;
473 if (max > sizeof(trash))
474 max = sizeof(trash);
475 ret = recv(sock, trash, max, MSG_NOSIGNAL | MSG_TRUNC);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100476 if (ret < 0) {
477 if (errno == EINTR)
478 continue;
Willy Tarreau869c7592016-11-12 17:50:57 +0100479 if (errno != EAGAIN) {
480 dolog("recv %d\n", ret);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100481 return -1;
Willy Tarreau869c7592016-11-12 17:50:57 +0100482 }
Willy Tarreau84393aa2016-11-12 11:29:46 +0100483 while (!wait_on_fd(sock, POLLIN));
484 continue;
485 }
Willy Tarreau869c7592016-11-12 17:50:57 +0100486 dolog("recv %d\n", ret);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100487 if (!ret)
488 break;
489
490 if (!count)
491 continue;
492 else if (count > 0)
493 count -= ret;
494
495 if (count <= 0)
496 break;
497 }
498
499 return 0;
500}
501
Willy Tarreau1973e812016-11-12 18:45:42 +0100502/* Sends N bytes to the socket and returns 0 (or -1 in case of send error, -2
503 * in case of an argument error. If the byte count is not set, sends only one
504 * block. Sending zero means try to send forever. If the argument starts with
505 * ':' then whatever follows is interpreted as the payload to be sent as-is.
506 * Escaped characters '\r', '\n', '\t' and '\\' are detected and converted. In
Willy Tarreau59623e02016-11-12 18:25:45 +0100507 * this case, blocks must be small so that send() doesn't fragment them, as
508 * they will be put into the trash and expected to be sent at once.
Willy Tarreau84393aa2016-11-12 11:29:46 +0100509 */
510int tcp_send(int sock, const char *arg)
511{
512 int count = -1; // stop after first block
513 int ret;
514
Willy Tarreau59623e02016-11-12 18:25:45 +0100515 if (arg[1] == ':') {
516 count = unescape(trash, sizeof(trash), arg + 2);
517 } else if (arg[1]) {
Willy Tarreau84393aa2016-11-12 11:29:46 +0100518 count = atoi(arg + 1);
Willy Tarreau869c7592016-11-12 17:50:57 +0100519 if (count < 0) {
Willy Tarreau84393aa2016-11-12 11:29:46 +0100520 fprintf(stderr, "send count must be >= 0 or unset (was %d)\n", count);
Willy Tarreau1973e812016-11-12 18:45:42 +0100521 return -2;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100522 }
523 }
524
525 while (1) {
526 ret = send(sock, trash,
527 (count > 0) && (count < sizeof(trash)) ? count : sizeof(trash),
528 MSG_NOSIGNAL | ((count > sizeof(trash)) ? MSG_MORE : 0));
529 if (ret < 0) {
530 if (errno == EINTR)
531 continue;
Willy Tarreau869c7592016-11-12 17:50:57 +0100532 if (errno != EAGAIN) {
533 dolog("send %d\n", ret);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100534 return -1;
Willy Tarreau869c7592016-11-12 17:50:57 +0100535 }
Willy Tarreau84393aa2016-11-12 11:29:46 +0100536 while (!wait_on_fd(sock, POLLOUT));
537 continue;
538 }
Willy Tarreau869c7592016-11-12 17:50:57 +0100539 dolog("send %d\n", ret);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100540 if (!count)
541 continue;
542 else if (count > 0)
543 count -= ret;
544
545 if (count <= 0)
546 break;
547 }
548
549 return 0;
550}
551
552/* echoes N bytes to the socket and returns 0 (or -1 in case of error). If not
553 * set, echoes only the first block. Zero means forward forever.
554 */
555int tcp_echo(int sock, const char *arg)
556{
557 int count = -1; // echo forever
558 int ret;
559 int rcvd;
560
561 if (arg[1]) {
562 count = atoi(arg + 1);
563 if (count < 0) {
564 fprintf(stderr, "send count must be >= 0 or unset (was %d)\n", count);
565 return -1;
566 }
567 }
568
569 rcvd = 0;
570 while (1) {
571 if (rcvd <= 0) {
572 /* no data pending */
573 rcvd = recv(sock, trash, (count > 0) && (count < sizeof(trash)) ? count : sizeof(trash), MSG_NOSIGNAL);
574 if (rcvd < 0) {
575 if (errno == EINTR)
576 continue;
Willy Tarreau869c7592016-11-12 17:50:57 +0100577 if (errno != EAGAIN) {
578 dolog("recv %d\n", rcvd);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100579 return -1;
Willy Tarreau869c7592016-11-12 17:50:57 +0100580 }
Willy Tarreau84393aa2016-11-12 11:29:46 +0100581 while (!wait_on_fd(sock, POLLIN));
582 continue;
583 }
Willy Tarreau869c7592016-11-12 17:50:57 +0100584 dolog("recv %d\n", rcvd);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100585 if (!rcvd)
586 break;
587 }
588 else {
589 /* some data still pending */
590 ret = send(sock, trash, rcvd, MSG_NOSIGNAL | ((count > rcvd) ? MSG_MORE : 0));
591 if (ret < 0) {
592 if (errno == EINTR)
593 continue;
Willy Tarreau869c7592016-11-12 17:50:57 +0100594 if (errno != EAGAIN) {
595 dolog("send %d\n", ret);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100596 return -1;
Willy Tarreau869c7592016-11-12 17:50:57 +0100597 }
Willy Tarreau84393aa2016-11-12 11:29:46 +0100598 while (!wait_on_fd(sock, POLLOUT));
599 continue;
600 }
Willy Tarreau869c7592016-11-12 17:50:57 +0100601 dolog("send %d\n", ret);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100602 rcvd -= ret;
603 if (rcvd)
604 continue;
605
606 if (!count)
607 continue;
608 else if (count > 0)
609 count -= ret;
610
611 if (count <= 0)
612 break;
613 }
614 }
615 return 0;
616}
617
618/* waits for an event on the socket, usually indicates an accept for a
619 * listening socket and a connect for an outgoing socket.
620 */
621int tcp_wait(int sock, const char *arg)
622{
623 struct pollfd pollfd;
624 int delay = -1; // wait forever
625 int ret;
626
627 if (arg[1]) {
628 delay = atoi(arg + 1);
629 if (delay < 0) {
630 fprintf(stderr, "wait time must be >= 0 or unset (was %d)\n", delay);
631 return -1;
632 }
633 }
634
635 /* FIXME: this doesn't take into account delivered signals */
636 do {
637 pollfd.fd = sock;
638 pollfd.events = POLLIN | POLLOUT;
639 ret = poll(&pollfd, 1, delay);
640 } while (ret == -1 && errno == EINTR);
641
Willy Tarreau869c7592016-11-12 17:50:57 +0100642 if (ret > 0 && pollfd.revents & POLLERR)
643 return -1;
644
Willy Tarreau84393aa2016-11-12 11:29:46 +0100645 return 0;
646}
647
648/* waits for the input data to be present */
649int tcp_wait_in(int sock, const char *arg)
650{
651 struct pollfd pollfd;
652 int ret;
653
654 do {
655 pollfd.fd = sock;
656 pollfd.events = POLLIN;
657 ret = poll(&pollfd, 1, 1000);
658 } while (ret == -1 && errno == EINTR);
Willy Tarreau869c7592016-11-12 17:50:57 +0100659
660 if (ret > 0 && pollfd.revents & POLLERR)
661 return -1;
662
Willy Tarreau84393aa2016-11-12 11:29:46 +0100663 return 0;
664}
665
666/* waits for the output queue to be empty */
667int tcp_wait_out(int sock, const char *arg)
668{
669 struct pollfd pollfd;
670 int ret;
671
672 do {
673 pollfd.fd = sock;
674 pollfd.events = POLLOUT;
675 ret = poll(&pollfd, 1, 1000);
676 } while (ret == -1 && errno == EINTR);
677
Willy Tarreau869c7592016-11-12 17:50:57 +0100678 if (ret > 0 && pollfd.revents & POLLERR)
679 return -1;
680
Willy Tarreau84393aa2016-11-12 11:29:46 +0100681 /* Now wait for data to leave the socket */
682 do {
683 if (ioctl(sock, TIOCOUTQ, &ret) < 0)
684 return -1;
685 } while (ret > 0);
686 return 0;
687}
688
689/* delays processing for <time> milliseconds, 100 by default */
690int tcp_pause(int sock, const char *arg)
691{
Willy Tarreau84393aa2016-11-12 11:29:46 +0100692 int delay = 100;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100693
694 if (arg[1]) {
695 delay = atoi(arg + 1);
696 if (delay < 0) {
697 fprintf(stderr, "wait time must be >= 0 or unset (was %d)\n", delay);
698 return -1;
699 }
700 }
701
702 usleep(delay * 1000);
703 return 0;
704}
705
Willy Tarreau95a6b782016-11-12 13:25:53 +0100706/* forks another process while respecting the limit imposed in argument (1 by
707 * default). Will wait for another process to exit before creating a new one.
708 * Returns the value of the fork() syscall, ie 0 for the child, non-zero for
709 * the parent, -1 for an error.
710 */
711int tcp_fork(int sock, const char *arg)
712{
713 int max = 1;
714 int ret;
715
716 if (arg[1]) {
717 max = atoi(arg + 1);
718 if (max <= 0) {
719 fprintf(stderr, "max process must be > 0 or unset (was %d)\n", max);
720 return -1;
721 }
722 }
723
724 while (nbproc >= max)
725 poll(NULL, 0, 1000);
726
727 ret = fork();
728 if (ret > 0)
729 __sync_add_and_fetch(&nbproc, 1);
730 return ret;
731}
732
Willy Tarreau84393aa2016-11-12 11:29:46 +0100733int main(int argc, char **argv)
734{
735 struct sockaddr_storage ss;
736 struct err_msg err;
737 const char *arg0;
Willy Tarreau29cc11c2016-11-12 18:54:20 +0100738 int loop_arg;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100739 int arg;
Willy Tarreau95a6b782016-11-12 13:25:53 +0100740 int ret;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100741 int sock;
Willy Tarreaub7a6d0d2017-05-02 22:14:59 +0200742 int errfd;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100743
744 arg0 = argv[0];
Willy Tarreau869c7592016-11-12 17:50:57 +0100745
746 while (argc > 1 && argv[1][0] == '-') {
747 argc--; argv++;
748 if (strcmp(argv[0], "-t") == 0)
749 showtime++;
750 else if (strcmp(argv[0], "-tt") == 0)
751 showtime += 2;
752 else if (strcmp(argv[0], "-ttt") == 0)
753 showtime += 3;
754 else if (strcmp(argv[0], "-v") == 0)
755 verbose ++;
756 else if (strcmp(argv[0], "--") == 0)
757 break;
758 else
759 usage(1, arg0);
760 }
761
Willy Tarreau84393aa2016-11-12 11:29:46 +0100762 if (argc < 2)
763 usage(1, arg0);
764
Willy Tarreau869c7592016-11-12 17:50:57 +0100765 pid = getpid();
Willy Tarreau95a6b782016-11-12 13:25:53 +0100766 signal(SIGCHLD, sig_handler);
767
Willy Tarreau84393aa2016-11-12 11:29:46 +0100768 if (addr_to_ss(argv[1], &ss, &err) < 0)
769 die(1, "%s\n", err.msg);
770
Willy Tarreau869c7592016-11-12 17:50:57 +0100771 gettimeofday(&start_time, NULL);
772
Willy Tarreau84393aa2016-11-12 11:29:46 +0100773 sock = -1;
Willy Tarreau29cc11c2016-11-12 18:54:20 +0100774 loop_arg = 2;
775 for (arg = loop_arg; arg < argc; arg++) {
Willy Tarreau84393aa2016-11-12 11:29:46 +0100776 switch (argv[arg][0]) {
777 case 'L':
778 /* silently ignore existing connections */
779 if (sock == -1)
780 sock = tcp_listen(&ss, argv[arg]);
781 if (sock < 0)
782 die(1, "Fatal: tcp_listen() failed.\n");
783 break;
784
785 case 'C':
786 /* silently ignore existing connections */
787 if (sock == -1)
788 sock = tcp_connect(&ss, argv[arg]);
789 if (sock < 0)
790 die(1, "Fatal: tcp_connect() failed.\n");
Willy Tarreau869c7592016-11-12 17:50:57 +0100791 dolog("connect\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100792 break;
793
Willy Tarreau2e065cb2020-10-14 08:09:48 +0200794 case 'D':
795 /* silently ignore non-existing connections */
796 if (sock >= 0 && tcp_disconnect(sock) < 0)
797 die(1, "Fatal: tcp_connect() failed.\n");
798 dolog("disconnect\n");
799 break;
800
Willy Tarreau84393aa2016-11-12 11:29:46 +0100801 case 'A':
802 if (sock < 0)
803 die(1, "Fatal: tcp_accept() on non-socket.\n");
804 sock = tcp_accept(sock, argv[arg]);
805 if (sock < 0)
806 die(1, "Fatal: tcp_accept() failed.\n");
Willy Tarreau869c7592016-11-12 17:50:57 +0100807 dolog("accept\n");
Willy Tarreau29cc11c2016-11-12 18:54:20 +0100808 loop_arg = arg + 1; // cannot loop before accept()
Willy Tarreau84393aa2016-11-12 11:29:46 +0100809 break;
810
811 case 'T':
812 if (sock < 0)
813 die(1, "Fatal: tcp_set_nodelay() on non-socket.\n");
814 if (tcp_set_nodelay(sock, argv[arg]) < 0)
815 die(1, "Fatal: tcp_set_nodelay() failed.\n");
816 break;
817
818 case 'G':
819 if (sock < 0)
820 die(1, "Fatal: tcp_set_nolinger() on non-socket.\n");
821 if (tcp_set_nolinger(sock, argv[arg]) < 0)
822 die(1, "Fatal: tcp_set_nolinger() failed.\n");
823 break;
824
825 case 'Q':
826 if (sock < 0)
827 die(1, "Fatal: tcp_set_noquickack() on non-socket.\n");
828 if (tcp_set_noquickack(sock, argv[arg]) < 0)
829 die(1, "Fatal: tcp_set_noquickack() failed.\n");
830 break;
831
832 case 'R':
833 if (sock < 0)
834 die(1, "Fatal: tcp_recv() on non-socket.\n");
Willy Tarreau1973e812016-11-12 18:45:42 +0100835 ret = tcp_recv(sock, argv[arg]);
836 if (ret < 0) {
837 if (ret == -1) // usually ECONNRESET, silently exit
838 die(0, NULL);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100839 die(1, "Fatal: tcp_recv() failed.\n");
Willy Tarreau1973e812016-11-12 18:45:42 +0100840 }
Willy Tarreau84393aa2016-11-12 11:29:46 +0100841 break;
842
843 case 'S':
844 if (sock < 0)
845 die(1, "Fatal: tcp_send() on non-socket.\n");
Willy Tarreau1973e812016-11-12 18:45:42 +0100846 ret = tcp_send(sock, argv[arg]);
847 if (ret < 0) {
848 if (ret == -1) // usually a broken pipe, silently exit
849 die(0, NULL);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100850 die(1, "Fatal: tcp_send() failed.\n");
Willy Tarreau1973e812016-11-12 18:45:42 +0100851 }
Willy Tarreau84393aa2016-11-12 11:29:46 +0100852 break;
853
854 case 'E':
855 if (sock < 0)
856 die(1, "Fatal: tcp_echo() on non-socket.\n");
857 if (tcp_echo(sock, argv[arg]) < 0)
858 die(1, "Fatal: tcp_echo() failed.\n");
859 break;
860
861 case 'P':
862 if (tcp_pause(sock, argv[arg]) < 0)
863 die(1, "Fatal: tcp_pause() failed.\n");
864 break;
865
866 case 'W':
867 if (sock < 0)
868 die(1, "Fatal: tcp_wait() on non-socket.\n");
869 if (tcp_wait(sock, argv[arg]) < 0)
870 die(1, "Fatal: tcp_wait() failed.\n");
Willy Tarreau869c7592016-11-12 17:50:57 +0100871 dolog("ready_any\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100872 break;
873
874 case 'I':
875 if (sock < 0)
876 die(1, "Fatal: tcp_wait_in() on non-socket.\n");
877 if (tcp_wait_in(sock, argv[arg]) < 0)
878 die(1, "Fatal: tcp_wait_in() failed.\n");
Willy Tarreau869c7592016-11-12 17:50:57 +0100879 dolog("ready_in\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100880 break;
881
882 case 'O':
883 if (sock < 0)
884 die(1, "Fatal: tcp_wait_out() on non-socket.\n");
885 if (tcp_wait_out(sock, argv[arg]) < 0)
886 die(1, "Fatal: tcp_wait_out() failed.\n");
Willy Tarreau869c7592016-11-12 17:50:57 +0100887 dolog("ready_out\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100888 break;
889
890 case 'K':
891 if (sock < 0 || close(sock) < 0)
892 die(1, "Fatal: close() on non-socket.\n");
Willy Tarreau869c7592016-11-12 17:50:57 +0100893 dolog("close\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100894 sock = -1;
895 break;
896
897 case 'F':
898 /* ignore errors on shutdown() as they are common */
899 if (sock >= 0)
900 shutdown(sock, SHUT_WR);
Willy Tarreauc3890e52017-10-05 06:31:10 +0200901 dolog("shutdown(w)\n");
902 break;
903
904 case 'r':
905 /* ignore errors on shutdown() as they are common */
906 if (sock >= 0)
907 shutdown(sock, SHUT_RD);
908 dolog("shutdown(r)\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100909 break;
910
Willy Tarreau95a6b782016-11-12 13:25:53 +0100911 case 'N':
912 ret = tcp_fork(sock, argv[arg]);
913 if (ret < 0)
914 die(1, "Fatal: fork() failed.\n");
915 if (ret > 0) {
916 /* loop back to first arg */
Willy Tarreau29cc11c2016-11-12 18:54:20 +0100917 arg = loop_arg - 1;
Willy Tarreau95a6b782016-11-12 13:25:53 +0100918 continue;
919 }
920 /* OK we're in the child, let's continue */
Willy Tarreau869c7592016-11-12 17:50:57 +0100921 pid = getpid();
Willy Tarreau29cc11c2016-11-12 18:54:20 +0100922 loop_arg = arg + 1;
Willy Tarreau95a6b782016-11-12 13:25:53 +0100923 break;
Willy Tarreau29cc11c2016-11-12 18:54:20 +0100924
925 case 'J': // jump back to oldest post-fork action
926 arg = loop_arg - 1;
927 continue;
928
Willy Tarreaub7a6d0d2017-05-02 22:14:59 +0200929 case 'X': // execute command. Optionally supports redirecting only i/o/e
930 if (arg + 1 >= argc)
931 die(1, "Fatal: missing argument after %s\n", argv[arg]);
932
933 errfd = dup(2);
934 fcntl(errfd, F_SETFD, fcntl(errfd, F_GETFD, FD_CLOEXEC) | FD_CLOEXEC);
935 fcntl(sock, F_SETFL, fcntl(sock, F_GETFL, O_NONBLOCK) & ~O_NONBLOCK);
936 if (!argv[arg][1] || strchr(argv[arg], 'i'))
937 dup2(sock, 0);
938 if (!argv[arg][1] || strchr(argv[arg], 'o'))
939 dup2(sock, 1);
940 if (!argv[arg][1] || strchr(argv[arg], 'e'))
941 dup2(sock, 2);
942 argv += arg + 1;
943 if (execvp(argv[0], argv) == -1) {
944 int e = errno;
945
946 dup2(errfd, 2); // restore original stderr
947 close(errfd);
948 die(1, "Fatal: execvp(%s) failed : %s\n", argv[0], strerror(e));
949 }
950 break;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100951 default:
952 usage(1, arg0);
953 }
954 }
955 return 0;
956}