blob: 0571a6dfd7048d93f396b6c78aab93b16b26acc4 [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"
121 " N<max> : fork New process, limited to <max> concurrent (default 1)\n"
Willy Tarreaub7a6d0d2017-05-02 22:14:59 +0200122 " X[i|o|e]* ** : execvp() next args passing socket as stdin/stdout/stderr.\n"
123 " If i/o/e present, only stdin/out/err are mapped to socket.\n"
Willy Tarreau9557bac2016-11-12 17:53:16 +0100124 "\n"
125 "It's important to note that a single FD is used at once and that Accept\n"
126 "replaces the listening FD with the accepted one. Thus always do it after\n"
127 "a fork if other connections have to be accepted.\n"
128 "\n"
129 "After a fork, we loop back to the beginning and silently skip L/C if the\n"
130 "main socket already exists.\n"
131 "\n"
132 "Example dummy HTTP request drain server :\n"
133 " tcploop 8001 L W N20 A R S10 [ F K ]\n"
134 "\n"
135 "Example large bandwidth HTTP request drain server :\n"
136 " tcploop 8001 L W N20 A R S0 [ F K ]\n"
137 "\n"
138 "Example TCP client with pauses at each step :\n"
139 " tcploop 8001 C T W P100 S10 O P100 R S10 O R G K\n"
Willy Tarreaub7a6d0d2017-05-02 22:14:59 +0200140 "\n"
141 "Simple chargen server :\n"
142 " tcploop 8001 L A Xo cat /dev/zero\n"
143 "\n"
144 "Simple telnet server :\n"
145 " tcploop 8001 L W N A X /usr/sbin/in.telnetd\n"
Willy Tarreau9557bac2016-11-12 17:53:16 +0100146 "", arg0);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100147}
148
Willy Tarreau869c7592016-11-12 17:50:57 +0100149void dolog(const char *format, ...)
150{
151 struct timeval date, tv;
152 int delay;
153 va_list args;
154
155 if (!verbose)
156 return;
157
158 if (showtime) {
159 gettimeofday(&date, NULL);
160 switch (showtime) {
161 case 1: // [msec] relative
162 delay = (date.tv_sec - start_time.tv_sec) * 1000000 + date.tv_usec - start_time.tv_usec;
163 fprintf(stderr, "[%d] ", delay / 1000);
164 break;
165 case 2: // [sec.usec] relative
166 tv.tv_usec = date.tv_usec - start_time.tv_usec;
167 tv.tv_sec = date.tv_sec - start_time.tv_sec;
168 if ((signed)tv.tv_sec > 0) {
169 if ((signed)tv.tv_usec < 0) {
170 tv.tv_usec += 1000000;
171 tv.tv_sec--;
172 }
173 } else if (tv.tv_sec == 0) {
174 if ((signed)tv.tv_usec < 0)
175 tv.tv_usec = 0;
176 } else {
177 tv.tv_sec = 0;
178 tv.tv_usec = 0;
179 }
Willy Tarreau752cc492017-03-14 14:37:13 +0100180 fprintf(stderr, "[%d.%06d] ", (int)tv.tv_sec, (int)tv.tv_usec);
Willy Tarreau869c7592016-11-12 17:50:57 +0100181 break;
182 default: // [sec.usec] absolute
Willy Tarreau752cc492017-03-14 14:37:13 +0100183 fprintf(stderr, "[%d.%06d] ", (int)date.tv_sec, (int)date.tv_usec);
Willy Tarreau869c7592016-11-12 17:50:57 +0100184 break;
185 }
186 }
187
188 fprintf(stderr, "%5d ", pid);
189
190 va_start(args, format);
191 vfprintf(stderr, format, args);
192 va_end(args);
193}
194
Willy Tarreau59623e02016-11-12 18:25:45 +0100195/* convert '\n', '\t', '\r', '\\' to their respective characters */
196int unescape(char *out, int size, const char *in)
197{
198 int len;
199
200 for (len = 0; len < size && *in; in++, out++, len++) {
201 if (*in == '\\') {
202 switch (in[1]) {
203 case 'n' : *out = '\n'; in++; continue;
204 case 't' : *out = '\t'; in++; continue;
205 case 'r' : *out = '\r'; in++; continue;
206 case '\\' : *out = '\\'; in++; continue;
207 default : break;
208 }
209 }
210 *out = *in;
211 }
212 return len;
213}
214
Willy Tarreau84393aa2016-11-12 11:29:46 +0100215struct err_msg *alloc_err_msg(int size)
216{
217 struct err_msg *err;
218
219 err = malloc(sizeof(*err) + size);
220 if (err) {
221 err->len = 0;
222 err->size = size;
223 }
224 return err;
225}
226
Willy Tarreau95a6b782016-11-12 13:25:53 +0100227void sig_handler(int sig)
228{
229 if (sig == SIGCHLD) {
230 while (waitpid(-1, NULL, WNOHANG) > 0)
231 __sync_sub_and_fetch(&nbproc, 1);
232 }
233}
Willy Tarreau84393aa2016-11-12 11:29:46 +0100234
235/* converts str in the form [[<ipv4>|<ipv6>|<hostname>]:]port to struct sockaddr_storage.
236 * Returns < 0 with err set in case of error.
237 */
238int addr_to_ss(char *str, struct sockaddr_storage *ss, struct err_msg *err)
239{
240 char *port_str;
241 int port;
242
243 memset(ss, 0, sizeof(*ss));
244
245 /* look for the addr/port delimiter, it's the last colon. If there's no
246 * colon, it's 0:<port>.
247 */
248 if ((port_str = strrchr(str, ':')) == NULL) {
249 port = atoi(str);
250 if (port <= 0 || port > 65535) {
251 err->len = snprintf(err->msg, err->size, "Missing/invalid port number: '%s'\n", str);
252 return -1;
253 }
254
255 ss->ss_family = AF_INET;
256 ((struct sockaddr_in *)ss)->sin_port = htons(port);
257 ((struct sockaddr_in *)ss)->sin_addr.s_addr = INADDR_ANY;
258 return 0;
259 }
260
261 *port_str++ = 0;
262
263 if (strrchr(str, ':') != NULL) {
264 /* IPv6 address contains ':' */
265 ss->ss_family = AF_INET6;
266 ((struct sockaddr_in6 *)ss)->sin6_port = htons(atoi(port_str));
267
268 if (!inet_pton(ss->ss_family, str, &((struct sockaddr_in6 *)ss)->sin6_addr)) {
269 err->len = snprintf(err->msg, err->size, "Invalid server address: '%s'\n", str);
270 return -1;
271 }
272 }
273 else {
274 ss->ss_family = AF_INET;
275 ((struct sockaddr_in *)ss)->sin_port = htons(atoi(port_str));
276
277 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
278 ((struct sockaddr_in *)ss)->sin_addr.s_addr = INADDR_ANY;
279 return 0;
280 }
281
282 if (!inet_pton(ss->ss_family, str, &((struct sockaddr_in *)ss)->sin_addr)) {
283 struct hostent *he = gethostbyname(str);
284
285 if (he == NULL) {
286 err->len = snprintf(err->msg, err->size, "Invalid server name: '%s'\n", str);
287 return -1;
288 }
289 ((struct sockaddr_in *)ss)->sin_addr = *(struct in_addr *) *(he->h_addr_list);
290 }
291 }
292
293 return 0;
294}
295
296/* waits up to one second on fd <fd> for events <events> (POLLIN|POLLOUT).
297 * returns poll's status.
298 */
299int wait_on_fd(int fd, int events)
300{
301 struct pollfd pollfd;
302 int ret;
303
304 do {
305 pollfd.fd = fd;
306 pollfd.events = events;
307 ret = poll(&pollfd, 1, 1000);
308 } while (ret == -1 && errno == EINTR);
309
310 return ret;
311}
312
313int tcp_set_nodelay(int sock, const char *arg)
314{
Willy Tarreau4bfc6632021-03-31 08:45:47 +0200315 return setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one));
Willy Tarreau84393aa2016-11-12 11:29:46 +0100316}
317
318int tcp_set_nolinger(int sock, const char *arg)
319{
320 return setsockopt(sock, SOL_SOCKET, SO_LINGER, (struct linger *) &nolinger, sizeof(struct linger));
321}
322
323int tcp_set_noquickack(int sock, const char *arg)
324{
Willy Tarreau0c0c0a62017-03-14 14:36:26 +0100325#ifdef TCP_QUICKACK
Willy Tarreau84393aa2016-11-12 11:29:46 +0100326 /* warning: do not use during connect if nothing is to be sent! */
Willy Tarreau4bfc6632021-03-31 08:45:47 +0200327 return setsockopt(sock, IPPROTO_TCP, TCP_QUICKACK, &zero, sizeof(zero));
Willy Tarreau0c0c0a62017-03-14 14:36:26 +0100328#else
329 return 0;
330#endif
Willy Tarreau84393aa2016-11-12 11:29:46 +0100331}
332
333/* Try to listen to address <sa>. Return the fd or -1 in case of error */
334int tcp_listen(const struct sockaddr_storage *sa, const char *arg)
335{
336 int sock;
337 int backlog;
338
339 if (arg[1])
340 backlog = atoi(arg + 1);
341 else
342 backlog = 1000;
343
344 if (backlog < 0 || backlog > 65535) {
345 fprintf(stderr, "backlog must be between 0 and 65535 inclusive (was %d)\n", backlog);
346 return -1;
347 }
348
349 sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
350 if (sock < 0) {
351 perror("socket()");
352 return -1;
353 }
354
355 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) == -1) {
356 perror("setsockopt(SO_REUSEADDR)");
357 goto fail;
358 }
359
360#ifdef SO_REUSEPORT
361 if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (char *) &one, sizeof(one)) == -1) {
362 perror("setsockopt(SO_REUSEPORT)");
363 goto fail;
364 }
365#endif
366 if (bind(sock, (struct sockaddr *)sa, sa->ss_family == AF_INET6 ?
367 sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) == -1) {
368 perror("bind");
369 goto fail;
370 }
371
372 if (listen(sock, backlog) == -1) {
373 perror("listen");
374 goto fail;
375 }
376
377 return sock;
378 fail:
379 close(sock);
380 return -1;
381}
382
383/* accepts a socket from listening socket <sock>, and returns it (or -1 in case of error) */
384int tcp_accept(int sock, const char *arg)
385{
386 int count;
387 int newsock;
388
389 if (arg[1])
390 count = atoi(arg + 1);
391 else
392 count = 1;
393
394 if (count <= 0) {
395 fprintf(stderr, "accept count must be > 0 or unset (was %d)\n", count);
396 return -1;
397 }
398
399 do {
400 newsock = accept(sock, NULL, NULL);
401 if (newsock < 0) { // TODO: improve error handling
402 if (errno == EINTR || errno == EAGAIN || errno == ECONNABORTED)
403 continue;
404 perror("accept()");
405 break;
406 }
407
408 if (count > 1)
409 close(newsock);
410 count--;
411 } while (count > 0);
412
413 fcntl(newsock, F_SETFL, O_NONBLOCK);
414 return newsock;
415}
416
417/* Try to establish a new connection to <sa>. Return the fd or -1 in case of error */
418int tcp_connect(const struct sockaddr_storage *sa, const char *arg)
419{
420 int sock;
421
422 sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
423 if (sock < 0)
424 return -1;
425
426 if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1)
427 goto fail;
428
429 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) == -1)
430 goto fail;
431
Willy Tarreau24d41b92017-03-14 14:50:05 +0100432 if (connect(sock, (const struct sockaddr *)sa, sizeof(struct sockaddr_in)) < 0) {
Willy Tarreau84393aa2016-11-12 11:29:46 +0100433 if (errno != EINPROGRESS)
434 goto fail;
435 }
436
437 return sock;
438 fail:
439 close(sock);
440 return -1;
441}
442
Willy Tarreau2e065cb2020-10-14 08:09:48 +0200443/* Try to disconnect by connecting to AF_UNSPEC. Return >=0 on success, -1 in case of error */
444int tcp_disconnect(int sock)
445{
446 const struct sockaddr sa = { .sa_family = AF_UNSPEC };
447
448 return connect(sock, &sa, sizeof(sa));
449}
450
Willy Tarreau1973e812016-11-12 18:45:42 +0100451/* receives N bytes from the socket and returns 0 (or -1 in case of a recv
452 * error, or -2 in case of an argument error). When no arg is passed, receives
453 * anything and stops. Otherwise reads the requested amount of data. 0 means
454 * read as much as possible.
Willy Tarreau84393aa2016-11-12 11:29:46 +0100455 */
456int tcp_recv(int sock, const char *arg)
457{
458 int count = -1; // stop at first read
459 int ret;
Willy Tarreaua84a2db2017-03-14 14:50:52 +0100460 int max;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100461
462 if (arg[1]) {
463 count = atoi(arg + 1);
464 if (count < 0) {
465 fprintf(stderr, "recv count must be >= 0 or unset (was %d)\n", count);
Willy Tarreau1973e812016-11-12 18:45:42 +0100466 return -2;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100467 }
468 }
469
470 while (1) {
Willy Tarreaua84a2db2017-03-14 14:50:52 +0100471 max = (count > 0) ? count : INT_MAX;
472 if (max > sizeof(trash))
473 max = sizeof(trash);
474 ret = recv(sock, trash, max, MSG_NOSIGNAL | MSG_TRUNC);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100475 if (ret < 0) {
476 if (errno == EINTR)
477 continue;
Willy Tarreau869c7592016-11-12 17:50:57 +0100478 if (errno != EAGAIN) {
479 dolog("recv %d\n", ret);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100480 return -1;
Willy Tarreau869c7592016-11-12 17:50:57 +0100481 }
Willy Tarreau84393aa2016-11-12 11:29:46 +0100482 while (!wait_on_fd(sock, POLLIN));
483 continue;
484 }
Willy Tarreau869c7592016-11-12 17:50:57 +0100485 dolog("recv %d\n", ret);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100486 if (!ret)
487 break;
488
489 if (!count)
490 continue;
491 else if (count > 0)
492 count -= ret;
493
494 if (count <= 0)
495 break;
496 }
497
498 return 0;
499}
500
Willy Tarreau1973e812016-11-12 18:45:42 +0100501/* Sends N bytes to the socket and returns 0 (or -1 in case of send error, -2
502 * in case of an argument error. If the byte count is not set, sends only one
503 * block. Sending zero means try to send forever. If the argument starts with
504 * ':' then whatever follows is interpreted as the payload to be sent as-is.
505 * Escaped characters '\r', '\n', '\t' and '\\' are detected and converted. In
Willy Tarreau59623e02016-11-12 18:25:45 +0100506 * this case, blocks must be small so that send() doesn't fragment them, as
507 * they will be put into the trash and expected to be sent at once.
Willy Tarreau84393aa2016-11-12 11:29:46 +0100508 */
509int tcp_send(int sock, const char *arg)
510{
511 int count = -1; // stop after first block
512 int ret;
513
Willy Tarreau59623e02016-11-12 18:25:45 +0100514 if (arg[1] == ':') {
515 count = unescape(trash, sizeof(trash), arg + 2);
516 } else if (arg[1]) {
Willy Tarreau84393aa2016-11-12 11:29:46 +0100517 count = atoi(arg + 1);
Willy Tarreau869c7592016-11-12 17:50:57 +0100518 if (count < 0) {
Willy Tarreau84393aa2016-11-12 11:29:46 +0100519 fprintf(stderr, "send count must be >= 0 or unset (was %d)\n", count);
Willy Tarreau1973e812016-11-12 18:45:42 +0100520 return -2;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100521 }
522 }
523
524 while (1) {
525 ret = send(sock, trash,
526 (count > 0) && (count < sizeof(trash)) ? count : sizeof(trash),
527 MSG_NOSIGNAL | ((count > sizeof(trash)) ? MSG_MORE : 0));
528 if (ret < 0) {
529 if (errno == EINTR)
530 continue;
Willy Tarreau869c7592016-11-12 17:50:57 +0100531 if (errno != EAGAIN) {
532 dolog("send %d\n", ret);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100533 return -1;
Willy Tarreau869c7592016-11-12 17:50:57 +0100534 }
Willy Tarreau84393aa2016-11-12 11:29:46 +0100535 while (!wait_on_fd(sock, POLLOUT));
536 continue;
537 }
Willy Tarreau869c7592016-11-12 17:50:57 +0100538 dolog("send %d\n", ret);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100539 if (!count)
540 continue;
541 else if (count > 0)
542 count -= ret;
543
544 if (count <= 0)
545 break;
546 }
547
548 return 0;
549}
550
551/* echoes N bytes to the socket and returns 0 (or -1 in case of error). If not
552 * set, echoes only the first block. Zero means forward forever.
553 */
554int tcp_echo(int sock, const char *arg)
555{
556 int count = -1; // echo forever
557 int ret;
558 int rcvd;
559
560 if (arg[1]) {
561 count = atoi(arg + 1);
562 if (count < 0) {
563 fprintf(stderr, "send count must be >= 0 or unset (was %d)\n", count);
564 return -1;
565 }
566 }
567
568 rcvd = 0;
569 while (1) {
570 if (rcvd <= 0) {
571 /* no data pending */
572 rcvd = recv(sock, trash, (count > 0) && (count < sizeof(trash)) ? count : sizeof(trash), MSG_NOSIGNAL);
573 if (rcvd < 0) {
574 if (errno == EINTR)
575 continue;
Willy Tarreau869c7592016-11-12 17:50:57 +0100576 if (errno != EAGAIN) {
577 dolog("recv %d\n", rcvd);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100578 return -1;
Willy Tarreau869c7592016-11-12 17:50:57 +0100579 }
Willy Tarreau84393aa2016-11-12 11:29:46 +0100580 while (!wait_on_fd(sock, POLLIN));
581 continue;
582 }
Willy Tarreau869c7592016-11-12 17:50:57 +0100583 dolog("recv %d\n", rcvd);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100584 if (!rcvd)
585 break;
586 }
587 else {
588 /* some data still pending */
589 ret = send(sock, trash, rcvd, MSG_NOSIGNAL | ((count > rcvd) ? MSG_MORE : 0));
590 if (ret < 0) {
591 if (errno == EINTR)
592 continue;
Willy Tarreau869c7592016-11-12 17:50:57 +0100593 if (errno != EAGAIN) {
594 dolog("send %d\n", ret);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100595 return -1;
Willy Tarreau869c7592016-11-12 17:50:57 +0100596 }
Willy Tarreau84393aa2016-11-12 11:29:46 +0100597 while (!wait_on_fd(sock, POLLOUT));
598 continue;
599 }
Willy Tarreau869c7592016-11-12 17:50:57 +0100600 dolog("send %d\n", ret);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100601 rcvd -= ret;
602 if (rcvd)
603 continue;
604
605 if (!count)
606 continue;
607 else if (count > 0)
608 count -= ret;
609
610 if (count <= 0)
611 break;
612 }
613 }
614 return 0;
615}
616
617/* waits for an event on the socket, usually indicates an accept for a
618 * listening socket and a connect for an outgoing socket.
619 */
620int tcp_wait(int sock, const char *arg)
621{
622 struct pollfd pollfd;
623 int delay = -1; // wait forever
624 int ret;
625
626 if (arg[1]) {
627 delay = atoi(arg + 1);
628 if (delay < 0) {
629 fprintf(stderr, "wait time must be >= 0 or unset (was %d)\n", delay);
630 return -1;
631 }
632 }
633
634 /* FIXME: this doesn't take into account delivered signals */
635 do {
636 pollfd.fd = sock;
637 pollfd.events = POLLIN | POLLOUT;
638 ret = poll(&pollfd, 1, delay);
639 } while (ret == -1 && errno == EINTR);
640
Willy Tarreau869c7592016-11-12 17:50:57 +0100641 if (ret > 0 && pollfd.revents & POLLERR)
642 return -1;
643
Willy Tarreau84393aa2016-11-12 11:29:46 +0100644 return 0;
645}
646
647/* waits for the input data to be present */
648int tcp_wait_in(int sock, const char *arg)
649{
650 struct pollfd pollfd;
651 int ret;
652
653 do {
654 pollfd.fd = sock;
655 pollfd.events = POLLIN;
656 ret = poll(&pollfd, 1, 1000);
657 } while (ret == -1 && errno == EINTR);
Willy Tarreau869c7592016-11-12 17:50:57 +0100658
659 if (ret > 0 && pollfd.revents & POLLERR)
660 return -1;
661
Willy Tarreau84393aa2016-11-12 11:29:46 +0100662 return 0;
663}
664
665/* waits for the output queue to be empty */
666int tcp_wait_out(int sock, const char *arg)
667{
668 struct pollfd pollfd;
669 int ret;
670
671 do {
672 pollfd.fd = sock;
673 pollfd.events = POLLOUT;
674 ret = poll(&pollfd, 1, 1000);
675 } while (ret == -1 && errno == EINTR);
676
Willy Tarreau869c7592016-11-12 17:50:57 +0100677 if (ret > 0 && pollfd.revents & POLLERR)
678 return -1;
679
Willy Tarreau84393aa2016-11-12 11:29:46 +0100680 /* Now wait for data to leave the socket */
681 do {
682 if (ioctl(sock, TIOCOUTQ, &ret) < 0)
683 return -1;
684 } while (ret > 0);
685 return 0;
686}
687
688/* delays processing for <time> milliseconds, 100 by default */
689int tcp_pause(int sock, const char *arg)
690{
Willy Tarreau84393aa2016-11-12 11:29:46 +0100691 int delay = 100;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100692
693 if (arg[1]) {
694 delay = atoi(arg + 1);
695 if (delay < 0) {
696 fprintf(stderr, "wait time must be >= 0 or unset (was %d)\n", delay);
697 return -1;
698 }
699 }
700
701 usleep(delay * 1000);
702 return 0;
703}
704
Willy Tarreau95a6b782016-11-12 13:25:53 +0100705/* forks another process while respecting the limit imposed in argument (1 by
706 * default). Will wait for another process to exit before creating a new one.
707 * Returns the value of the fork() syscall, ie 0 for the child, non-zero for
708 * the parent, -1 for an error.
709 */
710int tcp_fork(int sock, const char *arg)
711{
712 int max = 1;
713 int ret;
714
715 if (arg[1]) {
716 max = atoi(arg + 1);
717 if (max <= 0) {
718 fprintf(stderr, "max process must be > 0 or unset (was %d)\n", max);
719 return -1;
720 }
721 }
722
723 while (nbproc >= max)
724 poll(NULL, 0, 1000);
725
726 ret = fork();
727 if (ret > 0)
728 __sync_add_and_fetch(&nbproc, 1);
729 return ret;
730}
731
Willy Tarreau84393aa2016-11-12 11:29:46 +0100732int main(int argc, char **argv)
733{
734 struct sockaddr_storage ss;
735 struct err_msg err;
736 const char *arg0;
Willy Tarreau29cc11c2016-11-12 18:54:20 +0100737 int loop_arg;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100738 int arg;
Willy Tarreau95a6b782016-11-12 13:25:53 +0100739 int ret;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100740 int sock;
Willy Tarreaub7a6d0d2017-05-02 22:14:59 +0200741 int errfd;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100742
743 arg0 = argv[0];
Willy Tarreau869c7592016-11-12 17:50:57 +0100744
745 while (argc > 1 && argv[1][0] == '-') {
746 argc--; argv++;
747 if (strcmp(argv[0], "-t") == 0)
748 showtime++;
749 else if (strcmp(argv[0], "-tt") == 0)
750 showtime += 2;
751 else if (strcmp(argv[0], "-ttt") == 0)
752 showtime += 3;
753 else if (strcmp(argv[0], "-v") == 0)
754 verbose ++;
755 else if (strcmp(argv[0], "--") == 0)
756 break;
757 else
758 usage(1, arg0);
759 }
760
Willy Tarreau84393aa2016-11-12 11:29:46 +0100761 if (argc < 2)
762 usage(1, arg0);
763
Willy Tarreau869c7592016-11-12 17:50:57 +0100764 pid = getpid();
Willy Tarreau95a6b782016-11-12 13:25:53 +0100765 signal(SIGCHLD, sig_handler);
766
Willy Tarreau84393aa2016-11-12 11:29:46 +0100767 if (addr_to_ss(argv[1], &ss, &err) < 0)
768 die(1, "%s\n", err.msg);
769
Willy Tarreau869c7592016-11-12 17:50:57 +0100770 gettimeofday(&start_time, NULL);
771
Willy Tarreau84393aa2016-11-12 11:29:46 +0100772 sock = -1;
Willy Tarreau29cc11c2016-11-12 18:54:20 +0100773 loop_arg = 2;
774 for (arg = loop_arg; arg < argc; arg++) {
Willy Tarreau84393aa2016-11-12 11:29:46 +0100775 switch (argv[arg][0]) {
776 case 'L':
777 /* silently ignore existing connections */
778 if (sock == -1)
779 sock = tcp_listen(&ss, argv[arg]);
780 if (sock < 0)
781 die(1, "Fatal: tcp_listen() failed.\n");
782 break;
783
784 case 'C':
785 /* silently ignore existing connections */
786 if (sock == -1)
787 sock = tcp_connect(&ss, argv[arg]);
788 if (sock < 0)
789 die(1, "Fatal: tcp_connect() failed.\n");
Willy Tarreau869c7592016-11-12 17:50:57 +0100790 dolog("connect\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100791 break;
792
Willy Tarreau2e065cb2020-10-14 08:09:48 +0200793 case 'D':
794 /* silently ignore non-existing connections */
795 if (sock >= 0 && tcp_disconnect(sock) < 0)
796 die(1, "Fatal: tcp_connect() failed.\n");
797 dolog("disconnect\n");
798 break;
799
Willy Tarreau84393aa2016-11-12 11:29:46 +0100800 case 'A':
801 if (sock < 0)
802 die(1, "Fatal: tcp_accept() on non-socket.\n");
803 sock = tcp_accept(sock, argv[arg]);
804 if (sock < 0)
805 die(1, "Fatal: tcp_accept() failed.\n");
Willy Tarreau869c7592016-11-12 17:50:57 +0100806 dolog("accept\n");
Willy Tarreau29cc11c2016-11-12 18:54:20 +0100807 loop_arg = arg + 1; // cannot loop before accept()
Willy Tarreau84393aa2016-11-12 11:29:46 +0100808 break;
809
810 case 'T':
811 if (sock < 0)
812 die(1, "Fatal: tcp_set_nodelay() on non-socket.\n");
813 if (tcp_set_nodelay(sock, argv[arg]) < 0)
814 die(1, "Fatal: tcp_set_nodelay() failed.\n");
815 break;
816
817 case 'G':
818 if (sock < 0)
819 die(1, "Fatal: tcp_set_nolinger() on non-socket.\n");
820 if (tcp_set_nolinger(sock, argv[arg]) < 0)
821 die(1, "Fatal: tcp_set_nolinger() failed.\n");
822 break;
823
824 case 'Q':
825 if (sock < 0)
826 die(1, "Fatal: tcp_set_noquickack() on non-socket.\n");
827 if (tcp_set_noquickack(sock, argv[arg]) < 0)
828 die(1, "Fatal: tcp_set_noquickack() failed.\n");
829 break;
830
831 case 'R':
832 if (sock < 0)
833 die(1, "Fatal: tcp_recv() on non-socket.\n");
Willy Tarreau1973e812016-11-12 18:45:42 +0100834 ret = tcp_recv(sock, argv[arg]);
835 if (ret < 0) {
836 if (ret == -1) // usually ECONNRESET, silently exit
837 die(0, NULL);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100838 die(1, "Fatal: tcp_recv() failed.\n");
Willy Tarreau1973e812016-11-12 18:45:42 +0100839 }
Willy Tarreau84393aa2016-11-12 11:29:46 +0100840 break;
841
842 case 'S':
843 if (sock < 0)
844 die(1, "Fatal: tcp_send() on non-socket.\n");
Willy Tarreau1973e812016-11-12 18:45:42 +0100845 ret = tcp_send(sock, argv[arg]);
846 if (ret < 0) {
847 if (ret == -1) // usually a broken pipe, silently exit
848 die(0, NULL);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100849 die(1, "Fatal: tcp_send() failed.\n");
Willy Tarreau1973e812016-11-12 18:45:42 +0100850 }
Willy Tarreau84393aa2016-11-12 11:29:46 +0100851 break;
852
853 case 'E':
854 if (sock < 0)
855 die(1, "Fatal: tcp_echo() on non-socket.\n");
856 if (tcp_echo(sock, argv[arg]) < 0)
857 die(1, "Fatal: tcp_echo() failed.\n");
858 break;
859
860 case 'P':
861 if (tcp_pause(sock, argv[arg]) < 0)
862 die(1, "Fatal: tcp_pause() failed.\n");
863 break;
864
865 case 'W':
866 if (sock < 0)
867 die(1, "Fatal: tcp_wait() on non-socket.\n");
868 if (tcp_wait(sock, argv[arg]) < 0)
869 die(1, "Fatal: tcp_wait() failed.\n");
Willy Tarreau869c7592016-11-12 17:50:57 +0100870 dolog("ready_any\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100871 break;
872
873 case 'I':
874 if (sock < 0)
875 die(1, "Fatal: tcp_wait_in() on non-socket.\n");
876 if (tcp_wait_in(sock, argv[arg]) < 0)
877 die(1, "Fatal: tcp_wait_in() failed.\n");
Willy Tarreau869c7592016-11-12 17:50:57 +0100878 dolog("ready_in\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100879 break;
880
881 case 'O':
882 if (sock < 0)
883 die(1, "Fatal: tcp_wait_out() on non-socket.\n");
884 if (tcp_wait_out(sock, argv[arg]) < 0)
885 die(1, "Fatal: tcp_wait_out() failed.\n");
Willy Tarreau869c7592016-11-12 17:50:57 +0100886 dolog("ready_out\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100887 break;
888
889 case 'K':
890 if (sock < 0 || close(sock) < 0)
891 die(1, "Fatal: close() on non-socket.\n");
Willy Tarreau869c7592016-11-12 17:50:57 +0100892 dolog("close\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100893 sock = -1;
894 break;
895
896 case 'F':
897 /* ignore errors on shutdown() as they are common */
898 if (sock >= 0)
899 shutdown(sock, SHUT_WR);
Willy Tarreau869c7592016-11-12 17:50:57 +0100900 dolog("shutdown\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100901 break;
902
Willy Tarreau95a6b782016-11-12 13:25:53 +0100903 case 'N':
904 ret = tcp_fork(sock, argv[arg]);
905 if (ret < 0)
906 die(1, "Fatal: fork() failed.\n");
907 if (ret > 0) {
908 /* loop back to first arg */
Willy Tarreau29cc11c2016-11-12 18:54:20 +0100909 arg = loop_arg - 1;
Willy Tarreau95a6b782016-11-12 13:25:53 +0100910 continue;
911 }
912 /* OK we're in the child, let's continue */
Willy Tarreau869c7592016-11-12 17:50:57 +0100913 pid = getpid();
Willy Tarreau29cc11c2016-11-12 18:54:20 +0100914 loop_arg = arg + 1;
Willy Tarreau95a6b782016-11-12 13:25:53 +0100915 break;
Willy Tarreau29cc11c2016-11-12 18:54:20 +0100916
917 case 'J': // jump back to oldest post-fork action
918 arg = loop_arg - 1;
919 continue;
920
Willy Tarreaub7a6d0d2017-05-02 22:14:59 +0200921 case 'X': // execute command. Optionally supports redirecting only i/o/e
922 if (arg + 1 >= argc)
923 die(1, "Fatal: missing argument after %s\n", argv[arg]);
924
925 errfd = dup(2);
926 fcntl(errfd, F_SETFD, fcntl(errfd, F_GETFD, FD_CLOEXEC) | FD_CLOEXEC);
927 fcntl(sock, F_SETFL, fcntl(sock, F_GETFL, O_NONBLOCK) & ~O_NONBLOCK);
928 if (!argv[arg][1] || strchr(argv[arg], 'i'))
929 dup2(sock, 0);
930 if (!argv[arg][1] || strchr(argv[arg], 'o'))
931 dup2(sock, 1);
932 if (!argv[arg][1] || strchr(argv[arg], 'e'))
933 dup2(sock, 2);
934 argv += arg + 1;
935 if (execvp(argv[0], argv) == -1) {
936 int e = errno;
937
938 dup2(errfd, 2); // restore original stderr
939 close(errfd);
940 die(1, "Fatal: execvp(%s) failed : %s\n", argv[0], strerror(e));
941 }
942 break;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100943 default:
944 usage(1, arg0);
945 }
946 }
947 return 0;
948}