blob: 7786494caf22065e70e54ac77c626be5537d2fcd [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 SOL_TCP
54#define SOL_TCP IPPROTO_TCP
55#endif
56
57#ifndef MSG_MORE
58#define MSG_MORE 0
59#endif
Willy Tarreau84393aa2016-11-12 11:29:46 +010060
61struct err_msg {
62 int size;
63 int len;
64 char msg[0];
65};
66
67const int zero = 0;
68const int one = 1;
69const struct linger nolinger = { .l_onoff = 1, .l_linger = 0 };
70
71#define TRASH_SIZE 65536
72static char trash[TRASH_SIZE];
73
Willy Tarreau95a6b782016-11-12 13:25:53 +010074volatile int nbproc = 0;
Willy Tarreau869c7592016-11-12 17:50:57 +010075static struct timeval start_time;
76static int showtime;
77static int verbose;
78static int pid;
79
Willy Tarreau95a6b782016-11-12 13:25:53 +010080
Willy Tarreau84393aa2016-11-12 11:29:46 +010081/* display the message and exit with the code */
82__attribute__((noreturn)) void die(int code, const char *format, ...)
83{
84 va_list args;
85
Willy Tarreau1973e812016-11-12 18:45:42 +010086 if (format) {
87 va_start(args, format);
88 vfprintf(stderr, format, args);
89 va_end(args);
90 }
Willy Tarreau84393aa2016-11-12 11:29:46 +010091 exit(code);
92}
93
94/* display the usage message and exit with the code */
95__attribute__((noreturn)) void usage(int code, const char *arg0)
96{
Willy Tarreau9557bac2016-11-12 17:53:16 +010097 die(code,
98 "Usage : %s [options]* [<ip>:]port [<action>*]\n"
99 "\n"
100 "options :\n"
101 " -v : verbose\n"
102 " -t|-tt|-ttt : show time (msec / relative / absolute)\n"
103 "actions :\n"
104 " L[<backlog>] : Listens to ip:port and optionally sets backlog\n"
105 " Note: fd=socket,bind(fd),listen(fd)\n"
106 " C : Connects to ip:port\n"
107 " Note: fd=socket,connect(fd)\n"
Willy Tarreau2e065cb2020-10-14 08:09:48 +0200108 " D : Disconnect (connect to AF_UNSPEC)\n"
Willy Tarreau9557bac2016-11-12 17:53:16 +0100109 " A[<count>] : Accepts <count> incoming sockets and closes count-1\n"
110 " Note: fd=accept(fd)\n"
Willy Tarreau29cc11c2016-11-12 18:54:20 +0100111 " J : Jump back to oldest post-fork/post-accept action\n"
Willy Tarreaubcd817e2017-03-14 14:44:06 +0100112 " K : kill the connection and go on with next operation\n"
Willy Tarreau9557bac2016-11-12 17:53:16 +0100113 " G : disable lingering\n"
114 " T : set TCP_NODELAY\n"
115 " Q : disable TCP Quick-ack\n"
116 " R[<size>] : Read this amount of bytes. 0=infinite. unset=any amount.\n"
117 " S[<size>] : Send this amount of bytes. 0=infinite. unset=any amount.\n"
Willy Tarreau59623e02016-11-12 18:25:45 +0100118 " S:<string> : Send this exact string. \\r, \\n, \\t, \\\\ supported.\n"
Willy Tarreau9557bac2016-11-12 17:53:16 +0100119 " E[<size>] : Echo this amount of bytes. 0=infinite. unset=any amount.\n"
120 " W[<time>] : Wait for any event on the socket, maximum <time> ms\n"
121 " P[<time>] : Pause for <time> ms (100 by default)\n"
122 " I : wait for Input data to be present (POLLIN)\n"
123 " O : wait for Output queue to be empty (POLLOUT + TIOCOUTQ)\n"
124 " F : FIN : shutdown(SHUT_WR)\n"
125 " N<max> : fork New process, limited to <max> concurrent (default 1)\n"
Willy Tarreaub7a6d0d2017-05-02 22:14:59 +0200126 " X[i|o|e]* ** : execvp() next args passing socket as stdin/stdout/stderr.\n"
127 " If i/o/e present, only stdin/out/err are mapped to socket.\n"
Willy Tarreau9557bac2016-11-12 17:53:16 +0100128 "\n"
129 "It's important to note that a single FD is used at once and that Accept\n"
130 "replaces the listening FD with the accepted one. Thus always do it after\n"
131 "a fork if other connections have to be accepted.\n"
132 "\n"
133 "After a fork, we loop back to the beginning and silently skip L/C if the\n"
134 "main socket already exists.\n"
135 "\n"
136 "Example dummy HTTP request drain server :\n"
137 " tcploop 8001 L W N20 A R S10 [ F K ]\n"
138 "\n"
139 "Example large bandwidth HTTP request drain server :\n"
140 " tcploop 8001 L W N20 A R S0 [ F K ]\n"
141 "\n"
142 "Example TCP client with pauses at each step :\n"
143 " tcploop 8001 C T W P100 S10 O P100 R S10 O R G K\n"
Willy Tarreaub7a6d0d2017-05-02 22:14:59 +0200144 "\n"
145 "Simple chargen server :\n"
146 " tcploop 8001 L A Xo cat /dev/zero\n"
147 "\n"
148 "Simple telnet server :\n"
149 " tcploop 8001 L W N A X /usr/sbin/in.telnetd\n"
Willy Tarreau9557bac2016-11-12 17:53:16 +0100150 "", arg0);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100151}
152
Willy Tarreau869c7592016-11-12 17:50:57 +0100153void dolog(const char *format, ...)
154{
155 struct timeval date, tv;
156 int delay;
157 va_list args;
158
159 if (!verbose)
160 return;
161
162 if (showtime) {
163 gettimeofday(&date, NULL);
164 switch (showtime) {
165 case 1: // [msec] relative
166 delay = (date.tv_sec - start_time.tv_sec) * 1000000 + date.tv_usec - start_time.tv_usec;
167 fprintf(stderr, "[%d] ", delay / 1000);
168 break;
169 case 2: // [sec.usec] relative
170 tv.tv_usec = date.tv_usec - start_time.tv_usec;
171 tv.tv_sec = date.tv_sec - start_time.tv_sec;
172 if ((signed)tv.tv_sec > 0) {
173 if ((signed)tv.tv_usec < 0) {
174 tv.tv_usec += 1000000;
175 tv.tv_sec--;
176 }
177 } else if (tv.tv_sec == 0) {
178 if ((signed)tv.tv_usec < 0)
179 tv.tv_usec = 0;
180 } else {
181 tv.tv_sec = 0;
182 tv.tv_usec = 0;
183 }
Willy Tarreau752cc492017-03-14 14:37:13 +0100184 fprintf(stderr, "[%d.%06d] ", (int)tv.tv_sec, (int)tv.tv_usec);
Willy Tarreau869c7592016-11-12 17:50:57 +0100185 break;
186 default: // [sec.usec] absolute
Willy Tarreau752cc492017-03-14 14:37:13 +0100187 fprintf(stderr, "[%d.%06d] ", (int)date.tv_sec, (int)date.tv_usec);
Willy Tarreau869c7592016-11-12 17:50:57 +0100188 break;
189 }
190 }
191
192 fprintf(stderr, "%5d ", pid);
193
194 va_start(args, format);
195 vfprintf(stderr, format, args);
196 va_end(args);
197}
198
Willy Tarreau59623e02016-11-12 18:25:45 +0100199/* convert '\n', '\t', '\r', '\\' to their respective characters */
200int unescape(char *out, int size, const char *in)
201{
202 int len;
203
204 for (len = 0; len < size && *in; in++, out++, len++) {
205 if (*in == '\\') {
206 switch (in[1]) {
207 case 'n' : *out = '\n'; in++; continue;
208 case 't' : *out = '\t'; in++; continue;
209 case 'r' : *out = '\r'; in++; continue;
210 case '\\' : *out = '\\'; in++; continue;
211 default : break;
212 }
213 }
214 *out = *in;
215 }
216 return len;
217}
218
Willy Tarreau84393aa2016-11-12 11:29:46 +0100219struct err_msg *alloc_err_msg(int size)
220{
221 struct err_msg *err;
222
223 err = malloc(sizeof(*err) + size);
224 if (err) {
225 err->len = 0;
226 err->size = size;
227 }
228 return err;
229}
230
Willy Tarreau95a6b782016-11-12 13:25:53 +0100231void sig_handler(int sig)
232{
233 if (sig == SIGCHLD) {
234 while (waitpid(-1, NULL, WNOHANG) > 0)
235 __sync_sub_and_fetch(&nbproc, 1);
236 }
237}
Willy Tarreau84393aa2016-11-12 11:29:46 +0100238
239/* converts str in the form [[<ipv4>|<ipv6>|<hostname>]:]port to struct sockaddr_storage.
240 * Returns < 0 with err set in case of error.
241 */
242int addr_to_ss(char *str, struct sockaddr_storage *ss, struct err_msg *err)
243{
244 char *port_str;
245 int port;
246
247 memset(ss, 0, sizeof(*ss));
248
249 /* look for the addr/port delimiter, it's the last colon. If there's no
250 * colon, it's 0:<port>.
251 */
252 if ((port_str = strrchr(str, ':')) == NULL) {
253 port = atoi(str);
254 if (port <= 0 || port > 65535) {
255 err->len = snprintf(err->msg, err->size, "Missing/invalid port number: '%s'\n", str);
256 return -1;
257 }
258
259 ss->ss_family = AF_INET;
260 ((struct sockaddr_in *)ss)->sin_port = htons(port);
261 ((struct sockaddr_in *)ss)->sin_addr.s_addr = INADDR_ANY;
262 return 0;
263 }
264
265 *port_str++ = 0;
266
267 if (strrchr(str, ':') != NULL) {
268 /* IPv6 address contains ':' */
269 ss->ss_family = AF_INET6;
270 ((struct sockaddr_in6 *)ss)->sin6_port = htons(atoi(port_str));
271
272 if (!inet_pton(ss->ss_family, str, &((struct sockaddr_in6 *)ss)->sin6_addr)) {
273 err->len = snprintf(err->msg, err->size, "Invalid server address: '%s'\n", str);
274 return -1;
275 }
276 }
277 else {
278 ss->ss_family = AF_INET;
279 ((struct sockaddr_in *)ss)->sin_port = htons(atoi(port_str));
280
281 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
282 ((struct sockaddr_in *)ss)->sin_addr.s_addr = INADDR_ANY;
283 return 0;
284 }
285
286 if (!inet_pton(ss->ss_family, str, &((struct sockaddr_in *)ss)->sin_addr)) {
287 struct hostent *he = gethostbyname(str);
288
289 if (he == NULL) {
290 err->len = snprintf(err->msg, err->size, "Invalid server name: '%s'\n", str);
291 return -1;
292 }
293 ((struct sockaddr_in *)ss)->sin_addr = *(struct in_addr *) *(he->h_addr_list);
294 }
295 }
296
297 return 0;
298}
299
300/* waits up to one second on fd <fd> for events <events> (POLLIN|POLLOUT).
301 * returns poll's status.
302 */
303int wait_on_fd(int fd, int events)
304{
305 struct pollfd pollfd;
306 int ret;
307
308 do {
309 pollfd.fd = fd;
310 pollfd.events = events;
311 ret = poll(&pollfd, 1, 1000);
312 } while (ret == -1 && errno == EINTR);
313
314 return ret;
315}
316
317int tcp_set_nodelay(int sock, const char *arg)
318{
319 return setsockopt(sock, SOL_TCP, TCP_NODELAY, &one, sizeof(one));
320}
321
322int tcp_set_nolinger(int sock, const char *arg)
323{
324 return setsockopt(sock, SOL_SOCKET, SO_LINGER, (struct linger *) &nolinger, sizeof(struct linger));
325}
326
327int tcp_set_noquickack(int sock, const char *arg)
328{
Willy Tarreau0c0c0a62017-03-14 14:36:26 +0100329#ifdef TCP_QUICKACK
Willy Tarreau84393aa2016-11-12 11:29:46 +0100330 /* warning: do not use during connect if nothing is to be sent! */
331 return setsockopt(sock, SOL_TCP, TCP_QUICKACK, &zero, sizeof(zero));
Willy Tarreau0c0c0a62017-03-14 14:36:26 +0100332#else
333 return 0;
334#endif
Willy Tarreau84393aa2016-11-12 11:29:46 +0100335}
336
337/* Try to listen to address <sa>. Return the fd or -1 in case of error */
338int tcp_listen(const struct sockaddr_storage *sa, const char *arg)
339{
340 int sock;
341 int backlog;
342
343 if (arg[1])
344 backlog = atoi(arg + 1);
345 else
346 backlog = 1000;
347
348 if (backlog < 0 || backlog > 65535) {
349 fprintf(stderr, "backlog must be between 0 and 65535 inclusive (was %d)\n", backlog);
350 return -1;
351 }
352
353 sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
354 if (sock < 0) {
355 perror("socket()");
356 return -1;
357 }
358
359 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) == -1) {
360 perror("setsockopt(SO_REUSEADDR)");
361 goto fail;
362 }
363
364#ifdef SO_REUSEPORT
365 if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (char *) &one, sizeof(one)) == -1) {
366 perror("setsockopt(SO_REUSEPORT)");
367 goto fail;
368 }
369#endif
370 if (bind(sock, (struct sockaddr *)sa, sa->ss_family == AF_INET6 ?
371 sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) == -1) {
372 perror("bind");
373 goto fail;
374 }
375
376 if (listen(sock, backlog) == -1) {
377 perror("listen");
378 goto fail;
379 }
380
381 return sock;
382 fail:
383 close(sock);
384 return -1;
385}
386
387/* accepts a socket from listening socket <sock>, and returns it (or -1 in case of error) */
388int tcp_accept(int sock, const char *arg)
389{
390 int count;
391 int newsock;
392
393 if (arg[1])
394 count = atoi(arg + 1);
395 else
396 count = 1;
397
398 if (count <= 0) {
399 fprintf(stderr, "accept count must be > 0 or unset (was %d)\n", count);
400 return -1;
401 }
402
403 do {
404 newsock = accept(sock, NULL, NULL);
405 if (newsock < 0) { // TODO: improve error handling
406 if (errno == EINTR || errno == EAGAIN || errno == ECONNABORTED)
407 continue;
408 perror("accept()");
409 break;
410 }
411
412 if (count > 1)
413 close(newsock);
414 count--;
415 } while (count > 0);
416
417 fcntl(newsock, F_SETFL, O_NONBLOCK);
418 return newsock;
419}
420
421/* Try to establish a new connection to <sa>. Return the fd or -1 in case of error */
422int tcp_connect(const struct sockaddr_storage *sa, const char *arg)
423{
424 int sock;
425
426 sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
427 if (sock < 0)
428 return -1;
429
430 if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1)
431 goto fail;
432
433 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) == -1)
434 goto fail;
435
Willy Tarreau24d41b92017-03-14 14:50:05 +0100436 if (connect(sock, (const struct sockaddr *)sa, sizeof(struct sockaddr_in)) < 0) {
Willy Tarreau84393aa2016-11-12 11:29:46 +0100437 if (errno != EINPROGRESS)
438 goto fail;
439 }
440
441 return sock;
442 fail:
443 close(sock);
444 return -1;
445}
446
Willy Tarreau2e065cb2020-10-14 08:09:48 +0200447/* Try to disconnect by connecting to AF_UNSPEC. Return >=0 on success, -1 in case of error */
448int tcp_disconnect(int sock)
449{
450 const struct sockaddr sa = { .sa_family = AF_UNSPEC };
451
452 return connect(sock, &sa, sizeof(sa));
453}
454
Willy Tarreau1973e812016-11-12 18:45:42 +0100455/* receives N bytes from the socket and returns 0 (or -1 in case of a recv
456 * error, or -2 in case of an argument error). When no arg is passed, receives
457 * anything and stops. Otherwise reads the requested amount of data. 0 means
458 * read as much as possible.
Willy Tarreau84393aa2016-11-12 11:29:46 +0100459 */
460int tcp_recv(int sock, const char *arg)
461{
462 int count = -1; // stop at first read
463 int ret;
Willy Tarreaua84a2db2017-03-14 14:50:52 +0100464 int max;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100465
466 if (arg[1]) {
467 count = atoi(arg + 1);
468 if (count < 0) {
469 fprintf(stderr, "recv count must be >= 0 or unset (was %d)\n", count);
Willy Tarreau1973e812016-11-12 18:45:42 +0100470 return -2;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100471 }
472 }
473
474 while (1) {
Willy Tarreaua84a2db2017-03-14 14:50:52 +0100475 max = (count > 0) ? count : INT_MAX;
476 if (max > sizeof(trash))
477 max = sizeof(trash);
478 ret = recv(sock, trash, max, MSG_NOSIGNAL | MSG_TRUNC);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100479 if (ret < 0) {
480 if (errno == EINTR)
481 continue;
Willy Tarreau869c7592016-11-12 17:50:57 +0100482 if (errno != EAGAIN) {
483 dolog("recv %d\n", ret);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100484 return -1;
Willy Tarreau869c7592016-11-12 17:50:57 +0100485 }
Willy Tarreau84393aa2016-11-12 11:29:46 +0100486 while (!wait_on_fd(sock, POLLIN));
487 continue;
488 }
Willy Tarreau869c7592016-11-12 17:50:57 +0100489 dolog("recv %d\n", ret);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100490 if (!ret)
491 break;
492
493 if (!count)
494 continue;
495 else if (count > 0)
496 count -= ret;
497
498 if (count <= 0)
499 break;
500 }
501
502 return 0;
503}
504
Willy Tarreau1973e812016-11-12 18:45:42 +0100505/* Sends N bytes to the socket and returns 0 (or -1 in case of send error, -2
506 * in case of an argument error. If the byte count is not set, sends only one
507 * block. Sending zero means try to send forever. If the argument starts with
508 * ':' then whatever follows is interpreted as the payload to be sent as-is.
509 * Escaped characters '\r', '\n', '\t' and '\\' are detected and converted. In
Willy Tarreau59623e02016-11-12 18:25:45 +0100510 * this case, blocks must be small so that send() doesn't fragment them, as
511 * they will be put into the trash and expected to be sent at once.
Willy Tarreau84393aa2016-11-12 11:29:46 +0100512 */
513int tcp_send(int sock, const char *arg)
514{
515 int count = -1; // stop after first block
516 int ret;
517
Willy Tarreau59623e02016-11-12 18:25:45 +0100518 if (arg[1] == ':') {
519 count = unescape(trash, sizeof(trash), arg + 2);
520 } else if (arg[1]) {
Willy Tarreau84393aa2016-11-12 11:29:46 +0100521 count = atoi(arg + 1);
Willy Tarreau869c7592016-11-12 17:50:57 +0100522 if (count < 0) {
Willy Tarreau84393aa2016-11-12 11:29:46 +0100523 fprintf(stderr, "send count must be >= 0 or unset (was %d)\n", count);
Willy Tarreau1973e812016-11-12 18:45:42 +0100524 return -2;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100525 }
526 }
527
528 while (1) {
529 ret = send(sock, trash,
530 (count > 0) && (count < sizeof(trash)) ? count : sizeof(trash),
531 MSG_NOSIGNAL | ((count > sizeof(trash)) ? MSG_MORE : 0));
532 if (ret < 0) {
533 if (errno == EINTR)
534 continue;
Willy Tarreau869c7592016-11-12 17:50:57 +0100535 if (errno != EAGAIN) {
536 dolog("send %d\n", ret);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100537 return -1;
Willy Tarreau869c7592016-11-12 17:50:57 +0100538 }
Willy Tarreau84393aa2016-11-12 11:29:46 +0100539 while (!wait_on_fd(sock, POLLOUT));
540 continue;
541 }
Willy Tarreau869c7592016-11-12 17:50:57 +0100542 dolog("send %d\n", ret);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100543 if (!count)
544 continue;
545 else if (count > 0)
546 count -= ret;
547
548 if (count <= 0)
549 break;
550 }
551
552 return 0;
553}
554
555/* echoes N bytes to the socket and returns 0 (or -1 in case of error). If not
556 * set, echoes only the first block. Zero means forward forever.
557 */
558int tcp_echo(int sock, const char *arg)
559{
560 int count = -1; // echo forever
561 int ret;
562 int rcvd;
563
564 if (arg[1]) {
565 count = atoi(arg + 1);
566 if (count < 0) {
567 fprintf(stderr, "send count must be >= 0 or unset (was %d)\n", count);
568 return -1;
569 }
570 }
571
572 rcvd = 0;
573 while (1) {
574 if (rcvd <= 0) {
575 /* no data pending */
576 rcvd = recv(sock, trash, (count > 0) && (count < sizeof(trash)) ? count : sizeof(trash), MSG_NOSIGNAL);
577 if (rcvd < 0) {
578 if (errno == EINTR)
579 continue;
Willy Tarreau869c7592016-11-12 17:50:57 +0100580 if (errno != EAGAIN) {
581 dolog("recv %d\n", rcvd);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100582 return -1;
Willy Tarreau869c7592016-11-12 17:50:57 +0100583 }
Willy Tarreau84393aa2016-11-12 11:29:46 +0100584 while (!wait_on_fd(sock, POLLIN));
585 continue;
586 }
Willy Tarreau869c7592016-11-12 17:50:57 +0100587 dolog("recv %d\n", rcvd);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100588 if (!rcvd)
589 break;
590 }
591 else {
592 /* some data still pending */
593 ret = send(sock, trash, rcvd, MSG_NOSIGNAL | ((count > rcvd) ? MSG_MORE : 0));
594 if (ret < 0) {
595 if (errno == EINTR)
596 continue;
Willy Tarreau869c7592016-11-12 17:50:57 +0100597 if (errno != EAGAIN) {
598 dolog("send %d\n", ret);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100599 return -1;
Willy Tarreau869c7592016-11-12 17:50:57 +0100600 }
Willy Tarreau84393aa2016-11-12 11:29:46 +0100601 while (!wait_on_fd(sock, POLLOUT));
602 continue;
603 }
Willy Tarreau869c7592016-11-12 17:50:57 +0100604 dolog("send %d\n", ret);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100605 rcvd -= ret;
606 if (rcvd)
607 continue;
608
609 if (!count)
610 continue;
611 else if (count > 0)
612 count -= ret;
613
614 if (count <= 0)
615 break;
616 }
617 }
618 return 0;
619}
620
621/* waits for an event on the socket, usually indicates an accept for a
622 * listening socket and a connect for an outgoing socket.
623 */
624int tcp_wait(int sock, const char *arg)
625{
626 struct pollfd pollfd;
627 int delay = -1; // wait forever
628 int ret;
629
630 if (arg[1]) {
631 delay = atoi(arg + 1);
632 if (delay < 0) {
633 fprintf(stderr, "wait time must be >= 0 or unset (was %d)\n", delay);
634 return -1;
635 }
636 }
637
638 /* FIXME: this doesn't take into account delivered signals */
639 do {
640 pollfd.fd = sock;
641 pollfd.events = POLLIN | POLLOUT;
642 ret = poll(&pollfd, 1, delay);
643 } while (ret == -1 && errno == EINTR);
644
Willy Tarreau869c7592016-11-12 17:50:57 +0100645 if (ret > 0 && pollfd.revents & POLLERR)
646 return -1;
647
Willy Tarreau84393aa2016-11-12 11:29:46 +0100648 return 0;
649}
650
651/* waits for the input data to be present */
652int tcp_wait_in(int sock, const char *arg)
653{
654 struct pollfd pollfd;
655 int ret;
656
657 do {
658 pollfd.fd = sock;
659 pollfd.events = POLLIN;
660 ret = poll(&pollfd, 1, 1000);
661 } while (ret == -1 && errno == EINTR);
Willy Tarreau869c7592016-11-12 17:50:57 +0100662
663 if (ret > 0 && pollfd.revents & POLLERR)
664 return -1;
665
Willy Tarreau84393aa2016-11-12 11:29:46 +0100666 return 0;
667}
668
669/* waits for the output queue to be empty */
670int tcp_wait_out(int sock, const char *arg)
671{
672 struct pollfd pollfd;
673 int ret;
674
675 do {
676 pollfd.fd = sock;
677 pollfd.events = POLLOUT;
678 ret = poll(&pollfd, 1, 1000);
679 } while (ret == -1 && errno == EINTR);
680
Willy Tarreau869c7592016-11-12 17:50:57 +0100681 if (ret > 0 && pollfd.revents & POLLERR)
682 return -1;
683
Willy Tarreau84393aa2016-11-12 11:29:46 +0100684 /* Now wait for data to leave the socket */
685 do {
686 if (ioctl(sock, TIOCOUTQ, &ret) < 0)
687 return -1;
688 } while (ret > 0);
689 return 0;
690}
691
692/* delays processing for <time> milliseconds, 100 by default */
693int tcp_pause(int sock, const char *arg)
694{
Willy Tarreau84393aa2016-11-12 11:29:46 +0100695 int delay = 100;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100696
697 if (arg[1]) {
698 delay = atoi(arg + 1);
699 if (delay < 0) {
700 fprintf(stderr, "wait time must be >= 0 or unset (was %d)\n", delay);
701 return -1;
702 }
703 }
704
705 usleep(delay * 1000);
706 return 0;
707}
708
Willy Tarreau95a6b782016-11-12 13:25:53 +0100709/* forks another process while respecting the limit imposed in argument (1 by
710 * default). Will wait for another process to exit before creating a new one.
711 * Returns the value of the fork() syscall, ie 0 for the child, non-zero for
712 * the parent, -1 for an error.
713 */
714int tcp_fork(int sock, const char *arg)
715{
716 int max = 1;
717 int ret;
718
719 if (arg[1]) {
720 max = atoi(arg + 1);
721 if (max <= 0) {
722 fprintf(stderr, "max process must be > 0 or unset (was %d)\n", max);
723 return -1;
724 }
725 }
726
727 while (nbproc >= max)
728 poll(NULL, 0, 1000);
729
730 ret = fork();
731 if (ret > 0)
732 __sync_add_and_fetch(&nbproc, 1);
733 return ret;
734}
735
Willy Tarreau84393aa2016-11-12 11:29:46 +0100736int main(int argc, char **argv)
737{
738 struct sockaddr_storage ss;
739 struct err_msg err;
740 const char *arg0;
Willy Tarreau29cc11c2016-11-12 18:54:20 +0100741 int loop_arg;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100742 int arg;
Willy Tarreau95a6b782016-11-12 13:25:53 +0100743 int ret;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100744 int sock;
Willy Tarreaub7a6d0d2017-05-02 22:14:59 +0200745 int errfd;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100746
747 arg0 = argv[0];
Willy Tarreau869c7592016-11-12 17:50:57 +0100748
749 while (argc > 1 && argv[1][0] == '-') {
750 argc--; argv++;
751 if (strcmp(argv[0], "-t") == 0)
752 showtime++;
753 else if (strcmp(argv[0], "-tt") == 0)
754 showtime += 2;
755 else if (strcmp(argv[0], "-ttt") == 0)
756 showtime += 3;
757 else if (strcmp(argv[0], "-v") == 0)
758 verbose ++;
759 else if (strcmp(argv[0], "--") == 0)
760 break;
761 else
762 usage(1, arg0);
763 }
764
Willy Tarreau84393aa2016-11-12 11:29:46 +0100765 if (argc < 2)
766 usage(1, arg0);
767
Willy Tarreau869c7592016-11-12 17:50:57 +0100768 pid = getpid();
Willy Tarreau95a6b782016-11-12 13:25:53 +0100769 signal(SIGCHLD, sig_handler);
770
Willy Tarreau84393aa2016-11-12 11:29:46 +0100771 if (addr_to_ss(argv[1], &ss, &err) < 0)
772 die(1, "%s\n", err.msg);
773
Willy Tarreau869c7592016-11-12 17:50:57 +0100774 gettimeofday(&start_time, NULL);
775
Willy Tarreau84393aa2016-11-12 11:29:46 +0100776 sock = -1;
Willy Tarreau29cc11c2016-11-12 18:54:20 +0100777 loop_arg = 2;
778 for (arg = loop_arg; arg < argc; arg++) {
Willy Tarreau84393aa2016-11-12 11:29:46 +0100779 switch (argv[arg][0]) {
780 case 'L':
781 /* silently ignore existing connections */
782 if (sock == -1)
783 sock = tcp_listen(&ss, argv[arg]);
784 if (sock < 0)
785 die(1, "Fatal: tcp_listen() failed.\n");
786 break;
787
788 case 'C':
789 /* silently ignore existing connections */
790 if (sock == -1)
791 sock = tcp_connect(&ss, argv[arg]);
792 if (sock < 0)
793 die(1, "Fatal: tcp_connect() failed.\n");
Willy Tarreau869c7592016-11-12 17:50:57 +0100794 dolog("connect\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100795 break;
796
Willy Tarreau2e065cb2020-10-14 08:09:48 +0200797 case 'D':
798 /* silently ignore non-existing connections */
799 if (sock >= 0 && tcp_disconnect(sock) < 0)
800 die(1, "Fatal: tcp_connect() failed.\n");
801 dolog("disconnect\n");
802 break;
803
Willy Tarreau84393aa2016-11-12 11:29:46 +0100804 case 'A':
805 if (sock < 0)
806 die(1, "Fatal: tcp_accept() on non-socket.\n");
807 sock = tcp_accept(sock, argv[arg]);
808 if (sock < 0)
809 die(1, "Fatal: tcp_accept() failed.\n");
Willy Tarreau869c7592016-11-12 17:50:57 +0100810 dolog("accept\n");
Willy Tarreau29cc11c2016-11-12 18:54:20 +0100811 loop_arg = arg + 1; // cannot loop before accept()
Willy Tarreau84393aa2016-11-12 11:29:46 +0100812 break;
813
814 case 'T':
815 if (sock < 0)
816 die(1, "Fatal: tcp_set_nodelay() on non-socket.\n");
817 if (tcp_set_nodelay(sock, argv[arg]) < 0)
818 die(1, "Fatal: tcp_set_nodelay() failed.\n");
819 break;
820
821 case 'G':
822 if (sock < 0)
823 die(1, "Fatal: tcp_set_nolinger() on non-socket.\n");
824 if (tcp_set_nolinger(sock, argv[arg]) < 0)
825 die(1, "Fatal: tcp_set_nolinger() failed.\n");
826 break;
827
828 case 'Q':
829 if (sock < 0)
830 die(1, "Fatal: tcp_set_noquickack() on non-socket.\n");
831 if (tcp_set_noquickack(sock, argv[arg]) < 0)
832 die(1, "Fatal: tcp_set_noquickack() failed.\n");
833 break;
834
835 case 'R':
836 if (sock < 0)
837 die(1, "Fatal: tcp_recv() on non-socket.\n");
Willy Tarreau1973e812016-11-12 18:45:42 +0100838 ret = tcp_recv(sock, argv[arg]);
839 if (ret < 0) {
840 if (ret == -1) // usually ECONNRESET, silently exit
841 die(0, NULL);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100842 die(1, "Fatal: tcp_recv() failed.\n");
Willy Tarreau1973e812016-11-12 18:45:42 +0100843 }
Willy Tarreau84393aa2016-11-12 11:29:46 +0100844 break;
845
846 case 'S':
847 if (sock < 0)
848 die(1, "Fatal: tcp_send() on non-socket.\n");
Willy Tarreau1973e812016-11-12 18:45:42 +0100849 ret = tcp_send(sock, argv[arg]);
850 if (ret < 0) {
851 if (ret == -1) // usually a broken pipe, silently exit
852 die(0, NULL);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100853 die(1, "Fatal: tcp_send() failed.\n");
Willy Tarreau1973e812016-11-12 18:45:42 +0100854 }
Willy Tarreau84393aa2016-11-12 11:29:46 +0100855 break;
856
857 case 'E':
858 if (sock < 0)
859 die(1, "Fatal: tcp_echo() on non-socket.\n");
860 if (tcp_echo(sock, argv[arg]) < 0)
861 die(1, "Fatal: tcp_echo() failed.\n");
862 break;
863
864 case 'P':
865 if (tcp_pause(sock, argv[arg]) < 0)
866 die(1, "Fatal: tcp_pause() failed.\n");
867 break;
868
869 case 'W':
870 if (sock < 0)
871 die(1, "Fatal: tcp_wait() on non-socket.\n");
872 if (tcp_wait(sock, argv[arg]) < 0)
873 die(1, "Fatal: tcp_wait() failed.\n");
Willy Tarreau869c7592016-11-12 17:50:57 +0100874 dolog("ready_any\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100875 break;
876
877 case 'I':
878 if (sock < 0)
879 die(1, "Fatal: tcp_wait_in() on non-socket.\n");
880 if (tcp_wait_in(sock, argv[arg]) < 0)
881 die(1, "Fatal: tcp_wait_in() failed.\n");
Willy Tarreau869c7592016-11-12 17:50:57 +0100882 dolog("ready_in\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100883 break;
884
885 case 'O':
886 if (sock < 0)
887 die(1, "Fatal: tcp_wait_out() on non-socket.\n");
888 if (tcp_wait_out(sock, argv[arg]) < 0)
889 die(1, "Fatal: tcp_wait_out() failed.\n");
Willy Tarreau869c7592016-11-12 17:50:57 +0100890 dolog("ready_out\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100891 break;
892
893 case 'K':
894 if (sock < 0 || close(sock) < 0)
895 die(1, "Fatal: close() on non-socket.\n");
Willy Tarreau869c7592016-11-12 17:50:57 +0100896 dolog("close\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100897 sock = -1;
898 break;
899
900 case 'F':
901 /* ignore errors on shutdown() as they are common */
902 if (sock >= 0)
903 shutdown(sock, SHUT_WR);
Willy Tarreau869c7592016-11-12 17:50:57 +0100904 dolog("shutdown\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100905 break;
906
Willy Tarreau95a6b782016-11-12 13:25:53 +0100907 case 'N':
908 ret = tcp_fork(sock, argv[arg]);
909 if (ret < 0)
910 die(1, "Fatal: fork() failed.\n");
911 if (ret > 0) {
912 /* loop back to first arg */
Willy Tarreau29cc11c2016-11-12 18:54:20 +0100913 arg = loop_arg - 1;
Willy Tarreau95a6b782016-11-12 13:25:53 +0100914 continue;
915 }
916 /* OK we're in the child, let's continue */
Willy Tarreau869c7592016-11-12 17:50:57 +0100917 pid = getpid();
Willy Tarreau29cc11c2016-11-12 18:54:20 +0100918 loop_arg = arg + 1;
Willy Tarreau95a6b782016-11-12 13:25:53 +0100919 break;
Willy Tarreau29cc11c2016-11-12 18:54:20 +0100920
921 case 'J': // jump back to oldest post-fork action
922 arg = loop_arg - 1;
923 continue;
924
Willy Tarreaub7a6d0d2017-05-02 22:14:59 +0200925 case 'X': // execute command. Optionally supports redirecting only i/o/e
926 if (arg + 1 >= argc)
927 die(1, "Fatal: missing argument after %s\n", argv[arg]);
928
929 errfd = dup(2);
930 fcntl(errfd, F_SETFD, fcntl(errfd, F_GETFD, FD_CLOEXEC) | FD_CLOEXEC);
931 fcntl(sock, F_SETFL, fcntl(sock, F_GETFL, O_NONBLOCK) & ~O_NONBLOCK);
932 if (!argv[arg][1] || strchr(argv[arg], 'i'))
933 dup2(sock, 0);
934 if (!argv[arg][1] || strchr(argv[arg], 'o'))
935 dup2(sock, 1);
936 if (!argv[arg][1] || strchr(argv[arg], 'e'))
937 dup2(sock, 2);
938 argv += arg + 1;
939 if (execvp(argv[0], argv) == -1) {
940 int e = errno;
941
942 dup2(errfd, 2); // restore original stderr
943 close(errfd);
944 die(1, "Fatal: execvp(%s) failed : %s\n", argv[0], strerror(e));
945 }
946 break;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100947 default:
948 usage(1, arg0);
949 }
950 }
951 return 0;
952}