blob: 55b79365890f25cbed8c55b011c9692fc8a44071 [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{
695 struct pollfd pollfd;
696 int delay = 100;
697 int ret;
698
699 if (arg[1]) {
700 delay = atoi(arg + 1);
701 if (delay < 0) {
702 fprintf(stderr, "wait time must be >= 0 or unset (was %d)\n", delay);
703 return -1;
704 }
705 }
706
707 usleep(delay * 1000);
708 return 0;
709}
710
Willy Tarreau95a6b782016-11-12 13:25:53 +0100711/* forks another process while respecting the limit imposed in argument (1 by
712 * default). Will wait for another process to exit before creating a new one.
713 * Returns the value of the fork() syscall, ie 0 for the child, non-zero for
714 * the parent, -1 for an error.
715 */
716int tcp_fork(int sock, const char *arg)
717{
718 int max = 1;
719 int ret;
720
721 if (arg[1]) {
722 max = atoi(arg + 1);
723 if (max <= 0) {
724 fprintf(stderr, "max process must be > 0 or unset (was %d)\n", max);
725 return -1;
726 }
727 }
728
729 while (nbproc >= max)
730 poll(NULL, 0, 1000);
731
732 ret = fork();
733 if (ret > 0)
734 __sync_add_and_fetch(&nbproc, 1);
735 return ret;
736}
737
Willy Tarreau84393aa2016-11-12 11:29:46 +0100738int main(int argc, char **argv)
739{
740 struct sockaddr_storage ss;
741 struct err_msg err;
742 const char *arg0;
Willy Tarreau29cc11c2016-11-12 18:54:20 +0100743 int loop_arg;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100744 int arg;
Willy Tarreau95a6b782016-11-12 13:25:53 +0100745 int ret;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100746 int sock;
Willy Tarreaub7a6d0d2017-05-02 22:14:59 +0200747 int errfd;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100748
749 arg0 = argv[0];
Willy Tarreau869c7592016-11-12 17:50:57 +0100750
751 while (argc > 1 && argv[1][0] == '-') {
752 argc--; argv++;
753 if (strcmp(argv[0], "-t") == 0)
754 showtime++;
755 else if (strcmp(argv[0], "-tt") == 0)
756 showtime += 2;
757 else if (strcmp(argv[0], "-ttt") == 0)
758 showtime += 3;
759 else if (strcmp(argv[0], "-v") == 0)
760 verbose ++;
761 else if (strcmp(argv[0], "--") == 0)
762 break;
763 else
764 usage(1, arg0);
765 }
766
Willy Tarreau84393aa2016-11-12 11:29:46 +0100767 if (argc < 2)
768 usage(1, arg0);
769
Willy Tarreau869c7592016-11-12 17:50:57 +0100770 pid = getpid();
Willy Tarreau95a6b782016-11-12 13:25:53 +0100771 signal(SIGCHLD, sig_handler);
772
Willy Tarreau84393aa2016-11-12 11:29:46 +0100773 if (addr_to_ss(argv[1], &ss, &err) < 0)
774 die(1, "%s\n", err.msg);
775
Willy Tarreau869c7592016-11-12 17:50:57 +0100776 gettimeofday(&start_time, NULL);
777
Willy Tarreau84393aa2016-11-12 11:29:46 +0100778 sock = -1;
Willy Tarreau29cc11c2016-11-12 18:54:20 +0100779 loop_arg = 2;
780 for (arg = loop_arg; arg < argc; arg++) {
Willy Tarreau84393aa2016-11-12 11:29:46 +0100781 switch (argv[arg][0]) {
782 case 'L':
783 /* silently ignore existing connections */
784 if (sock == -1)
785 sock = tcp_listen(&ss, argv[arg]);
786 if (sock < 0)
787 die(1, "Fatal: tcp_listen() failed.\n");
788 break;
789
790 case 'C':
791 /* silently ignore existing connections */
792 if (sock == -1)
793 sock = tcp_connect(&ss, argv[arg]);
794 if (sock < 0)
795 die(1, "Fatal: tcp_connect() failed.\n");
Willy Tarreau869c7592016-11-12 17:50:57 +0100796 dolog("connect\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100797 break;
798
Willy Tarreau2e065cb2020-10-14 08:09:48 +0200799 case 'D':
800 /* silently ignore non-existing connections */
801 if (sock >= 0 && tcp_disconnect(sock) < 0)
802 die(1, "Fatal: tcp_connect() failed.\n");
803 dolog("disconnect\n");
804 break;
805
Willy Tarreau84393aa2016-11-12 11:29:46 +0100806 case 'A':
807 if (sock < 0)
808 die(1, "Fatal: tcp_accept() on non-socket.\n");
809 sock = tcp_accept(sock, argv[arg]);
810 if (sock < 0)
811 die(1, "Fatal: tcp_accept() failed.\n");
Willy Tarreau869c7592016-11-12 17:50:57 +0100812 dolog("accept\n");
Willy Tarreau29cc11c2016-11-12 18:54:20 +0100813 loop_arg = arg + 1; // cannot loop before accept()
Willy Tarreau84393aa2016-11-12 11:29:46 +0100814 break;
815
816 case 'T':
817 if (sock < 0)
818 die(1, "Fatal: tcp_set_nodelay() on non-socket.\n");
819 if (tcp_set_nodelay(sock, argv[arg]) < 0)
820 die(1, "Fatal: tcp_set_nodelay() failed.\n");
821 break;
822
823 case 'G':
824 if (sock < 0)
825 die(1, "Fatal: tcp_set_nolinger() on non-socket.\n");
826 if (tcp_set_nolinger(sock, argv[arg]) < 0)
827 die(1, "Fatal: tcp_set_nolinger() failed.\n");
828 break;
829
830 case 'Q':
831 if (sock < 0)
832 die(1, "Fatal: tcp_set_noquickack() on non-socket.\n");
833 if (tcp_set_noquickack(sock, argv[arg]) < 0)
834 die(1, "Fatal: tcp_set_noquickack() failed.\n");
835 break;
836
837 case 'R':
838 if (sock < 0)
839 die(1, "Fatal: tcp_recv() on non-socket.\n");
Willy Tarreau1973e812016-11-12 18:45:42 +0100840 ret = tcp_recv(sock, argv[arg]);
841 if (ret < 0) {
842 if (ret == -1) // usually ECONNRESET, silently exit
843 die(0, NULL);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100844 die(1, "Fatal: tcp_recv() failed.\n");
Willy Tarreau1973e812016-11-12 18:45:42 +0100845 }
Willy Tarreau84393aa2016-11-12 11:29:46 +0100846 break;
847
848 case 'S':
849 if (sock < 0)
850 die(1, "Fatal: tcp_send() on non-socket.\n");
Willy Tarreau1973e812016-11-12 18:45:42 +0100851 ret = tcp_send(sock, argv[arg]);
852 if (ret < 0) {
853 if (ret == -1) // usually a broken pipe, silently exit
854 die(0, NULL);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100855 die(1, "Fatal: tcp_send() failed.\n");
Willy Tarreau1973e812016-11-12 18:45:42 +0100856 }
Willy Tarreau84393aa2016-11-12 11:29:46 +0100857 break;
858
859 case 'E':
860 if (sock < 0)
861 die(1, "Fatal: tcp_echo() on non-socket.\n");
862 if (tcp_echo(sock, argv[arg]) < 0)
863 die(1, "Fatal: tcp_echo() failed.\n");
864 break;
865
866 case 'P':
867 if (tcp_pause(sock, argv[arg]) < 0)
868 die(1, "Fatal: tcp_pause() failed.\n");
869 break;
870
871 case 'W':
872 if (sock < 0)
873 die(1, "Fatal: tcp_wait() on non-socket.\n");
874 if (tcp_wait(sock, argv[arg]) < 0)
875 die(1, "Fatal: tcp_wait() failed.\n");
Willy Tarreau869c7592016-11-12 17:50:57 +0100876 dolog("ready_any\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100877 break;
878
879 case 'I':
880 if (sock < 0)
881 die(1, "Fatal: tcp_wait_in() on non-socket.\n");
882 if (tcp_wait_in(sock, argv[arg]) < 0)
883 die(1, "Fatal: tcp_wait_in() failed.\n");
Willy Tarreau869c7592016-11-12 17:50:57 +0100884 dolog("ready_in\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100885 break;
886
887 case 'O':
888 if (sock < 0)
889 die(1, "Fatal: tcp_wait_out() on non-socket.\n");
890 if (tcp_wait_out(sock, argv[arg]) < 0)
891 die(1, "Fatal: tcp_wait_out() failed.\n");
Willy Tarreau869c7592016-11-12 17:50:57 +0100892 dolog("ready_out\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100893 break;
894
895 case 'K':
896 if (sock < 0 || close(sock) < 0)
897 die(1, "Fatal: close() on non-socket.\n");
Willy Tarreau869c7592016-11-12 17:50:57 +0100898 dolog("close\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100899 sock = -1;
900 break;
901
902 case 'F':
903 /* ignore errors on shutdown() as they are common */
904 if (sock >= 0)
905 shutdown(sock, SHUT_WR);
Willy Tarreau869c7592016-11-12 17:50:57 +0100906 dolog("shutdown\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100907 break;
908
Willy Tarreau95a6b782016-11-12 13:25:53 +0100909 case 'N':
910 ret = tcp_fork(sock, argv[arg]);
911 if (ret < 0)
912 die(1, "Fatal: fork() failed.\n");
913 if (ret > 0) {
914 /* loop back to first arg */
Willy Tarreau29cc11c2016-11-12 18:54:20 +0100915 arg = loop_arg - 1;
Willy Tarreau95a6b782016-11-12 13:25:53 +0100916 continue;
917 }
918 /* OK we're in the child, let's continue */
Willy Tarreau869c7592016-11-12 17:50:57 +0100919 pid = getpid();
Willy Tarreau29cc11c2016-11-12 18:54:20 +0100920 loop_arg = arg + 1;
Willy Tarreau95a6b782016-11-12 13:25:53 +0100921 break;
Willy Tarreau29cc11c2016-11-12 18:54:20 +0100922
923 case 'J': // jump back to oldest post-fork action
924 arg = loop_arg - 1;
925 continue;
926
Willy Tarreaub7a6d0d2017-05-02 22:14:59 +0200927 case 'X': // execute command. Optionally supports redirecting only i/o/e
928 if (arg + 1 >= argc)
929 die(1, "Fatal: missing argument after %s\n", argv[arg]);
930
931 errfd = dup(2);
932 fcntl(errfd, F_SETFD, fcntl(errfd, F_GETFD, FD_CLOEXEC) | FD_CLOEXEC);
933 fcntl(sock, F_SETFL, fcntl(sock, F_GETFL, O_NONBLOCK) & ~O_NONBLOCK);
934 if (!argv[arg][1] || strchr(argv[arg], 'i'))
935 dup2(sock, 0);
936 if (!argv[arg][1] || strchr(argv[arg], 'o'))
937 dup2(sock, 1);
938 if (!argv[arg][1] || strchr(argv[arg], 'e'))
939 dup2(sock, 2);
940 argv += arg + 1;
941 if (execvp(argv[0], argv) == -1) {
942 int e = errno;
943
944 dup2(errfd, 2); // restore original stderr
945 close(errfd);
946 die(1, "Fatal: execvp(%s) failed : %s\n", argv[0], strerror(e));
947 }
948 break;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100949 default:
950 usage(1, arg0);
951 }
952 }
953 return 0;
954}