blob: f9f5f6307d2b3033e9ab72976a792b4064918aa3 [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"
108 " A[<count>] : Accepts <count> incoming sockets and closes count-1\n"
109 " Note: fd=accept(fd)\n"
Willy Tarreau29cc11c2016-11-12 18:54:20 +0100110 " J : Jump back to oldest post-fork/post-accept action\n"
Willy Tarreaubcd817e2017-03-14 14:44:06 +0100111 " K : kill the connection and go on with next operation\n"
Willy Tarreau9557bac2016-11-12 17:53:16 +0100112 " G : disable lingering\n"
113 " T : set TCP_NODELAY\n"
114 " Q : disable TCP Quick-ack\n"
115 " R[<size>] : Read this amount of bytes. 0=infinite. unset=any amount.\n"
116 " S[<size>] : Send this amount of bytes. 0=infinite. unset=any amount.\n"
Willy Tarreau59623e02016-11-12 18:25:45 +0100117 " S:<string> : Send this exact string. \\r, \\n, \\t, \\\\ supported.\n"
Willy Tarreau9557bac2016-11-12 17:53:16 +0100118 " E[<size>] : Echo this amount of bytes. 0=infinite. unset=any amount.\n"
119 " W[<time>] : Wait for any event on the socket, maximum <time> ms\n"
120 " P[<time>] : Pause for <time> ms (100 by default)\n"
121 " I : wait for Input data to be present (POLLIN)\n"
122 " O : wait for Output queue to be empty (POLLOUT + TIOCOUTQ)\n"
123 " F : FIN : shutdown(SHUT_WR)\n"
124 " N<max> : fork New process, limited to <max> concurrent (default 1)\n"
Willy Tarreaub7a6d0d2017-05-02 22:14:59 +0200125 " X[i|o|e]* ** : execvp() next args passing socket as stdin/stdout/stderr.\n"
126 " If i/o/e present, only stdin/out/err are mapped to socket.\n"
Willy Tarreau9557bac2016-11-12 17:53:16 +0100127 "\n"
128 "It's important to note that a single FD is used at once and that Accept\n"
129 "replaces the listening FD with the accepted one. Thus always do it after\n"
130 "a fork if other connections have to be accepted.\n"
131 "\n"
132 "After a fork, we loop back to the beginning and silently skip L/C if the\n"
133 "main socket already exists.\n"
134 "\n"
135 "Example dummy HTTP request drain server :\n"
136 " tcploop 8001 L W N20 A R S10 [ F K ]\n"
137 "\n"
138 "Example large bandwidth HTTP request drain server :\n"
139 " tcploop 8001 L W N20 A R S0 [ F K ]\n"
140 "\n"
141 "Example TCP client with pauses at each step :\n"
142 " tcploop 8001 C T W P100 S10 O P100 R S10 O R G K\n"
Willy Tarreaub7a6d0d2017-05-02 22:14:59 +0200143 "\n"
144 "Simple chargen server :\n"
145 " tcploop 8001 L A Xo cat /dev/zero\n"
146 "\n"
147 "Simple telnet server :\n"
148 " tcploop 8001 L W N A X /usr/sbin/in.telnetd\n"
Willy Tarreau9557bac2016-11-12 17:53:16 +0100149 "", arg0);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100150}
151
Willy Tarreau869c7592016-11-12 17:50:57 +0100152void dolog(const char *format, ...)
153{
154 struct timeval date, tv;
155 int delay;
156 va_list args;
157
158 if (!verbose)
159 return;
160
161 if (showtime) {
162 gettimeofday(&date, NULL);
163 switch (showtime) {
164 case 1: // [msec] relative
165 delay = (date.tv_sec - start_time.tv_sec) * 1000000 + date.tv_usec - start_time.tv_usec;
166 fprintf(stderr, "[%d] ", delay / 1000);
167 break;
168 case 2: // [sec.usec] relative
169 tv.tv_usec = date.tv_usec - start_time.tv_usec;
170 tv.tv_sec = date.tv_sec - start_time.tv_sec;
171 if ((signed)tv.tv_sec > 0) {
172 if ((signed)tv.tv_usec < 0) {
173 tv.tv_usec += 1000000;
174 tv.tv_sec--;
175 }
176 } else if (tv.tv_sec == 0) {
177 if ((signed)tv.tv_usec < 0)
178 tv.tv_usec = 0;
179 } else {
180 tv.tv_sec = 0;
181 tv.tv_usec = 0;
182 }
Willy Tarreau752cc492017-03-14 14:37:13 +0100183 fprintf(stderr, "[%d.%06d] ", (int)tv.tv_sec, (int)tv.tv_usec);
Willy Tarreau869c7592016-11-12 17:50:57 +0100184 break;
185 default: // [sec.usec] absolute
Willy Tarreau752cc492017-03-14 14:37:13 +0100186 fprintf(stderr, "[%d.%06d] ", (int)date.tv_sec, (int)date.tv_usec);
Willy Tarreau869c7592016-11-12 17:50:57 +0100187 break;
188 }
189 }
190
191 fprintf(stderr, "%5d ", pid);
192
193 va_start(args, format);
194 vfprintf(stderr, format, args);
195 va_end(args);
196}
197
Willy Tarreau59623e02016-11-12 18:25:45 +0100198/* convert '\n', '\t', '\r', '\\' to their respective characters */
199int unescape(char *out, int size, const char *in)
200{
201 int len;
202
203 for (len = 0; len < size && *in; in++, out++, len++) {
204 if (*in == '\\') {
205 switch (in[1]) {
206 case 'n' : *out = '\n'; in++; continue;
207 case 't' : *out = '\t'; in++; continue;
208 case 'r' : *out = '\r'; in++; continue;
209 case '\\' : *out = '\\'; in++; continue;
210 default : break;
211 }
212 }
213 *out = *in;
214 }
215 return len;
216}
217
Willy Tarreau84393aa2016-11-12 11:29:46 +0100218struct err_msg *alloc_err_msg(int size)
219{
220 struct err_msg *err;
221
222 err = malloc(sizeof(*err) + size);
223 if (err) {
224 err->len = 0;
225 err->size = size;
226 }
227 return err;
228}
229
Willy Tarreau95a6b782016-11-12 13:25:53 +0100230void sig_handler(int sig)
231{
232 if (sig == SIGCHLD) {
233 while (waitpid(-1, NULL, WNOHANG) > 0)
234 __sync_sub_and_fetch(&nbproc, 1);
235 }
236}
Willy Tarreau84393aa2016-11-12 11:29:46 +0100237
238/* converts str in the form [[<ipv4>|<ipv6>|<hostname>]:]port to struct sockaddr_storage.
239 * Returns < 0 with err set in case of error.
240 */
241int addr_to_ss(char *str, struct sockaddr_storage *ss, struct err_msg *err)
242{
243 char *port_str;
244 int port;
245
246 memset(ss, 0, sizeof(*ss));
247
248 /* look for the addr/port delimiter, it's the last colon. If there's no
249 * colon, it's 0:<port>.
250 */
251 if ((port_str = strrchr(str, ':')) == NULL) {
252 port = atoi(str);
253 if (port <= 0 || port > 65535) {
254 err->len = snprintf(err->msg, err->size, "Missing/invalid port number: '%s'\n", str);
255 return -1;
256 }
257
258 ss->ss_family = AF_INET;
259 ((struct sockaddr_in *)ss)->sin_port = htons(port);
260 ((struct sockaddr_in *)ss)->sin_addr.s_addr = INADDR_ANY;
261 return 0;
262 }
263
264 *port_str++ = 0;
265
266 if (strrchr(str, ':') != NULL) {
267 /* IPv6 address contains ':' */
268 ss->ss_family = AF_INET6;
269 ((struct sockaddr_in6 *)ss)->sin6_port = htons(atoi(port_str));
270
271 if (!inet_pton(ss->ss_family, str, &((struct sockaddr_in6 *)ss)->sin6_addr)) {
272 err->len = snprintf(err->msg, err->size, "Invalid server address: '%s'\n", str);
273 return -1;
274 }
275 }
276 else {
277 ss->ss_family = AF_INET;
278 ((struct sockaddr_in *)ss)->sin_port = htons(atoi(port_str));
279
280 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
281 ((struct sockaddr_in *)ss)->sin_addr.s_addr = INADDR_ANY;
282 return 0;
283 }
284
285 if (!inet_pton(ss->ss_family, str, &((struct sockaddr_in *)ss)->sin_addr)) {
286 struct hostent *he = gethostbyname(str);
287
288 if (he == NULL) {
289 err->len = snprintf(err->msg, err->size, "Invalid server name: '%s'\n", str);
290 return -1;
291 }
292 ((struct sockaddr_in *)ss)->sin_addr = *(struct in_addr *) *(he->h_addr_list);
293 }
294 }
295
296 return 0;
297}
298
299/* waits up to one second on fd <fd> for events <events> (POLLIN|POLLOUT).
300 * returns poll's status.
301 */
302int wait_on_fd(int fd, int events)
303{
304 struct pollfd pollfd;
305 int ret;
306
307 do {
308 pollfd.fd = fd;
309 pollfd.events = events;
310 ret = poll(&pollfd, 1, 1000);
311 } while (ret == -1 && errno == EINTR);
312
313 return ret;
314}
315
316int tcp_set_nodelay(int sock, const char *arg)
317{
318 return setsockopt(sock, SOL_TCP, TCP_NODELAY, &one, sizeof(one));
319}
320
321int tcp_set_nolinger(int sock, const char *arg)
322{
323 return setsockopt(sock, SOL_SOCKET, SO_LINGER, (struct linger *) &nolinger, sizeof(struct linger));
324}
325
326int tcp_set_noquickack(int sock, const char *arg)
327{
Willy Tarreau0c0c0a62017-03-14 14:36:26 +0100328#ifdef TCP_QUICKACK
Willy Tarreau84393aa2016-11-12 11:29:46 +0100329 /* warning: do not use during connect if nothing is to be sent! */
330 return setsockopt(sock, SOL_TCP, TCP_QUICKACK, &zero, sizeof(zero));
Willy Tarreau0c0c0a62017-03-14 14:36:26 +0100331#else
332 return 0;
333#endif
Willy Tarreau84393aa2016-11-12 11:29:46 +0100334}
335
336/* Try to listen to address <sa>. Return the fd or -1 in case of error */
337int tcp_listen(const struct sockaddr_storage *sa, const char *arg)
338{
339 int sock;
340 int backlog;
341
342 if (arg[1])
343 backlog = atoi(arg + 1);
344 else
345 backlog = 1000;
346
347 if (backlog < 0 || backlog > 65535) {
348 fprintf(stderr, "backlog must be between 0 and 65535 inclusive (was %d)\n", backlog);
349 return -1;
350 }
351
352 sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
353 if (sock < 0) {
354 perror("socket()");
355 return -1;
356 }
357
358 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) == -1) {
359 perror("setsockopt(SO_REUSEADDR)");
360 goto fail;
361 }
362
363#ifdef SO_REUSEPORT
364 if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (char *) &one, sizeof(one)) == -1) {
365 perror("setsockopt(SO_REUSEPORT)");
366 goto fail;
367 }
368#endif
369 if (bind(sock, (struct sockaddr *)sa, sa->ss_family == AF_INET6 ?
370 sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) == -1) {
371 perror("bind");
372 goto fail;
373 }
374
375 if (listen(sock, backlog) == -1) {
376 perror("listen");
377 goto fail;
378 }
379
380 return sock;
381 fail:
382 close(sock);
383 return -1;
384}
385
386/* accepts a socket from listening socket <sock>, and returns it (or -1 in case of error) */
387int tcp_accept(int sock, const char *arg)
388{
389 int count;
390 int newsock;
391
392 if (arg[1])
393 count = atoi(arg + 1);
394 else
395 count = 1;
396
397 if (count <= 0) {
398 fprintf(stderr, "accept count must be > 0 or unset (was %d)\n", count);
399 return -1;
400 }
401
402 do {
403 newsock = accept(sock, NULL, NULL);
404 if (newsock < 0) { // TODO: improve error handling
405 if (errno == EINTR || errno == EAGAIN || errno == ECONNABORTED)
406 continue;
407 perror("accept()");
408 break;
409 }
410
411 if (count > 1)
412 close(newsock);
413 count--;
414 } while (count > 0);
415
416 fcntl(newsock, F_SETFL, O_NONBLOCK);
417 return newsock;
418}
419
420/* Try to establish a new connection to <sa>. Return the fd or -1 in case of error */
421int tcp_connect(const struct sockaddr_storage *sa, const char *arg)
422{
423 int sock;
424
425 sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
426 if (sock < 0)
427 return -1;
428
429 if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1)
430 goto fail;
431
432 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) == -1)
433 goto fail;
434
Willy Tarreau24d41b92017-03-14 14:50:05 +0100435 if (connect(sock, (const struct sockaddr *)sa, sizeof(struct sockaddr_in)) < 0) {
Willy Tarreau84393aa2016-11-12 11:29:46 +0100436 if (errno != EINPROGRESS)
437 goto fail;
438 }
439
440 return sock;
441 fail:
442 close(sock);
443 return -1;
444}
445
Willy Tarreau1973e812016-11-12 18:45:42 +0100446/* receives N bytes from the socket and returns 0 (or -1 in case of a recv
447 * error, or -2 in case of an argument error). When no arg is passed, receives
448 * anything and stops. Otherwise reads the requested amount of data. 0 means
449 * read as much as possible.
Willy Tarreau84393aa2016-11-12 11:29:46 +0100450 */
451int tcp_recv(int sock, const char *arg)
452{
453 int count = -1; // stop at first read
454 int ret;
Willy Tarreaua84a2db2017-03-14 14:50:52 +0100455 int max;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100456
457 if (arg[1]) {
458 count = atoi(arg + 1);
459 if (count < 0) {
460 fprintf(stderr, "recv count must be >= 0 or unset (was %d)\n", count);
Willy Tarreau1973e812016-11-12 18:45:42 +0100461 return -2;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100462 }
463 }
464
465 while (1) {
Willy Tarreaua84a2db2017-03-14 14:50:52 +0100466 max = (count > 0) ? count : INT_MAX;
467 if (max > sizeof(trash))
468 max = sizeof(trash);
469 ret = recv(sock, trash, max, MSG_NOSIGNAL | MSG_TRUNC);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100470 if (ret < 0) {
471 if (errno == EINTR)
472 continue;
Willy Tarreau869c7592016-11-12 17:50:57 +0100473 if (errno != EAGAIN) {
474 dolog("recv %d\n", ret);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100475 return -1;
Willy Tarreau869c7592016-11-12 17:50:57 +0100476 }
Willy Tarreau84393aa2016-11-12 11:29:46 +0100477 while (!wait_on_fd(sock, POLLIN));
478 continue;
479 }
Willy Tarreau869c7592016-11-12 17:50:57 +0100480 dolog("recv %d\n", ret);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100481 if (!ret)
482 break;
483
484 if (!count)
485 continue;
486 else if (count > 0)
487 count -= ret;
488
489 if (count <= 0)
490 break;
491 }
492
493 return 0;
494}
495
Willy Tarreau1973e812016-11-12 18:45:42 +0100496/* Sends N bytes to the socket and returns 0 (or -1 in case of send error, -2
497 * in case of an argument error. If the byte count is not set, sends only one
498 * block. Sending zero means try to send forever. If the argument starts with
499 * ':' then whatever follows is interpreted as the payload to be sent as-is.
500 * Escaped characters '\r', '\n', '\t' and '\\' are detected and converted. In
Willy Tarreau59623e02016-11-12 18:25:45 +0100501 * this case, blocks must be small so that send() doesn't fragment them, as
502 * they will be put into the trash and expected to be sent at once.
Willy Tarreau84393aa2016-11-12 11:29:46 +0100503 */
504int tcp_send(int sock, const char *arg)
505{
506 int count = -1; // stop after first block
507 int ret;
508
Willy Tarreau59623e02016-11-12 18:25:45 +0100509 if (arg[1] == ':') {
510 count = unescape(trash, sizeof(trash), arg + 2);
511 } else if (arg[1]) {
Willy Tarreau84393aa2016-11-12 11:29:46 +0100512 count = atoi(arg + 1);
Willy Tarreau869c7592016-11-12 17:50:57 +0100513 if (count < 0) {
Willy Tarreau84393aa2016-11-12 11:29:46 +0100514 fprintf(stderr, "send count must be >= 0 or unset (was %d)\n", count);
Willy Tarreau1973e812016-11-12 18:45:42 +0100515 return -2;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100516 }
517 }
518
519 while (1) {
520 ret = send(sock, trash,
521 (count > 0) && (count < sizeof(trash)) ? count : sizeof(trash),
522 MSG_NOSIGNAL | ((count > sizeof(trash)) ? MSG_MORE : 0));
523 if (ret < 0) {
524 if (errno == EINTR)
525 continue;
Willy Tarreau869c7592016-11-12 17:50:57 +0100526 if (errno != EAGAIN) {
527 dolog("send %d\n", ret);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100528 return -1;
Willy Tarreau869c7592016-11-12 17:50:57 +0100529 }
Willy Tarreau84393aa2016-11-12 11:29:46 +0100530 while (!wait_on_fd(sock, POLLOUT));
531 continue;
532 }
Willy Tarreau869c7592016-11-12 17:50:57 +0100533 dolog("send %d\n", ret);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100534 if (!count)
535 continue;
536 else if (count > 0)
537 count -= ret;
538
539 if (count <= 0)
540 break;
541 }
542
543 return 0;
544}
545
546/* echoes N bytes to the socket and returns 0 (or -1 in case of error). If not
547 * set, echoes only the first block. Zero means forward forever.
548 */
549int tcp_echo(int sock, const char *arg)
550{
551 int count = -1; // echo forever
552 int ret;
553 int rcvd;
554
555 if (arg[1]) {
556 count = atoi(arg + 1);
557 if (count < 0) {
558 fprintf(stderr, "send count must be >= 0 or unset (was %d)\n", count);
559 return -1;
560 }
561 }
562
563 rcvd = 0;
564 while (1) {
565 if (rcvd <= 0) {
566 /* no data pending */
567 rcvd = recv(sock, trash, (count > 0) && (count < sizeof(trash)) ? count : sizeof(trash), MSG_NOSIGNAL);
568 if (rcvd < 0) {
569 if (errno == EINTR)
570 continue;
Willy Tarreau869c7592016-11-12 17:50:57 +0100571 if (errno != EAGAIN) {
572 dolog("recv %d\n", rcvd);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100573 return -1;
Willy Tarreau869c7592016-11-12 17:50:57 +0100574 }
Willy Tarreau84393aa2016-11-12 11:29:46 +0100575 while (!wait_on_fd(sock, POLLIN));
576 continue;
577 }
Willy Tarreau869c7592016-11-12 17:50:57 +0100578 dolog("recv %d\n", rcvd);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100579 if (!rcvd)
580 break;
581 }
582 else {
583 /* some data still pending */
584 ret = send(sock, trash, rcvd, MSG_NOSIGNAL | ((count > rcvd) ? MSG_MORE : 0));
585 if (ret < 0) {
586 if (errno == EINTR)
587 continue;
Willy Tarreau869c7592016-11-12 17:50:57 +0100588 if (errno != EAGAIN) {
589 dolog("send %d\n", ret);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100590 return -1;
Willy Tarreau869c7592016-11-12 17:50:57 +0100591 }
Willy Tarreau84393aa2016-11-12 11:29:46 +0100592 while (!wait_on_fd(sock, POLLOUT));
593 continue;
594 }
Willy Tarreau869c7592016-11-12 17:50:57 +0100595 dolog("send %d\n", ret);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100596 rcvd -= ret;
597 if (rcvd)
598 continue;
599
600 if (!count)
601 continue;
602 else if (count > 0)
603 count -= ret;
604
605 if (count <= 0)
606 break;
607 }
608 }
609 return 0;
610}
611
612/* waits for an event on the socket, usually indicates an accept for a
613 * listening socket and a connect for an outgoing socket.
614 */
615int tcp_wait(int sock, const char *arg)
616{
617 struct pollfd pollfd;
618 int delay = -1; // wait forever
619 int ret;
620
621 if (arg[1]) {
622 delay = atoi(arg + 1);
623 if (delay < 0) {
624 fprintf(stderr, "wait time must be >= 0 or unset (was %d)\n", delay);
625 return -1;
626 }
627 }
628
629 /* FIXME: this doesn't take into account delivered signals */
630 do {
631 pollfd.fd = sock;
632 pollfd.events = POLLIN | POLLOUT;
633 ret = poll(&pollfd, 1, delay);
634 } while (ret == -1 && errno == EINTR);
635
Willy Tarreau869c7592016-11-12 17:50:57 +0100636 if (ret > 0 && pollfd.revents & POLLERR)
637 return -1;
638
Willy Tarreau84393aa2016-11-12 11:29:46 +0100639 return 0;
640}
641
642/* waits for the input data to be present */
643int tcp_wait_in(int sock, const char *arg)
644{
645 struct pollfd pollfd;
646 int ret;
647
648 do {
649 pollfd.fd = sock;
650 pollfd.events = POLLIN;
651 ret = poll(&pollfd, 1, 1000);
652 } while (ret == -1 && errno == EINTR);
Willy Tarreau869c7592016-11-12 17:50:57 +0100653
654 if (ret > 0 && pollfd.revents & POLLERR)
655 return -1;
656
Willy Tarreau84393aa2016-11-12 11:29:46 +0100657 return 0;
658}
659
660/* waits for the output queue to be empty */
661int tcp_wait_out(int sock, const char *arg)
662{
663 struct pollfd pollfd;
664 int ret;
665
666 do {
667 pollfd.fd = sock;
668 pollfd.events = POLLOUT;
669 ret = poll(&pollfd, 1, 1000);
670 } while (ret == -1 && errno == EINTR);
671
Willy Tarreau869c7592016-11-12 17:50:57 +0100672 if (ret > 0 && pollfd.revents & POLLERR)
673 return -1;
674
Willy Tarreau84393aa2016-11-12 11:29:46 +0100675 /* Now wait for data to leave the socket */
676 do {
677 if (ioctl(sock, TIOCOUTQ, &ret) < 0)
678 return -1;
679 } while (ret > 0);
680 return 0;
681}
682
683/* delays processing for <time> milliseconds, 100 by default */
684int tcp_pause(int sock, const char *arg)
685{
686 struct pollfd pollfd;
687 int delay = 100;
688 int ret;
689
690 if (arg[1]) {
691 delay = atoi(arg + 1);
692 if (delay < 0) {
693 fprintf(stderr, "wait time must be >= 0 or unset (was %d)\n", delay);
694 return -1;
695 }
696 }
697
698 usleep(delay * 1000);
699 return 0;
700}
701
Willy Tarreau95a6b782016-11-12 13:25:53 +0100702/* forks another process while respecting the limit imposed in argument (1 by
703 * default). Will wait for another process to exit before creating a new one.
704 * Returns the value of the fork() syscall, ie 0 for the child, non-zero for
705 * the parent, -1 for an error.
706 */
707int tcp_fork(int sock, const char *arg)
708{
709 int max = 1;
710 int ret;
711
712 if (arg[1]) {
713 max = atoi(arg + 1);
714 if (max <= 0) {
715 fprintf(stderr, "max process must be > 0 or unset (was %d)\n", max);
716 return -1;
717 }
718 }
719
720 while (nbproc >= max)
721 poll(NULL, 0, 1000);
722
723 ret = fork();
724 if (ret > 0)
725 __sync_add_and_fetch(&nbproc, 1);
726 return ret;
727}
728
Willy Tarreau84393aa2016-11-12 11:29:46 +0100729int main(int argc, char **argv)
730{
731 struct sockaddr_storage ss;
732 struct err_msg err;
733 const char *arg0;
Willy Tarreau29cc11c2016-11-12 18:54:20 +0100734 int loop_arg;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100735 int arg;
Willy Tarreau95a6b782016-11-12 13:25:53 +0100736 int ret;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100737 int sock;
Willy Tarreaub7a6d0d2017-05-02 22:14:59 +0200738 int errfd;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100739
740 arg0 = argv[0];
Willy Tarreau869c7592016-11-12 17:50:57 +0100741
742 while (argc > 1 && argv[1][0] == '-') {
743 argc--; argv++;
744 if (strcmp(argv[0], "-t") == 0)
745 showtime++;
746 else if (strcmp(argv[0], "-tt") == 0)
747 showtime += 2;
748 else if (strcmp(argv[0], "-ttt") == 0)
749 showtime += 3;
750 else if (strcmp(argv[0], "-v") == 0)
751 verbose ++;
752 else if (strcmp(argv[0], "--") == 0)
753 break;
754 else
755 usage(1, arg0);
756 }
757
Willy Tarreau84393aa2016-11-12 11:29:46 +0100758 if (argc < 2)
759 usage(1, arg0);
760
Willy Tarreau869c7592016-11-12 17:50:57 +0100761 pid = getpid();
Willy Tarreau95a6b782016-11-12 13:25:53 +0100762 signal(SIGCHLD, sig_handler);
763
Willy Tarreau84393aa2016-11-12 11:29:46 +0100764 if (addr_to_ss(argv[1], &ss, &err) < 0)
765 die(1, "%s\n", err.msg);
766
Willy Tarreau869c7592016-11-12 17:50:57 +0100767 gettimeofday(&start_time, NULL);
768
Willy Tarreau84393aa2016-11-12 11:29:46 +0100769 sock = -1;
Willy Tarreau29cc11c2016-11-12 18:54:20 +0100770 loop_arg = 2;
771 for (arg = loop_arg; arg < argc; arg++) {
Willy Tarreau84393aa2016-11-12 11:29:46 +0100772 switch (argv[arg][0]) {
773 case 'L':
774 /* silently ignore existing connections */
775 if (sock == -1)
776 sock = tcp_listen(&ss, argv[arg]);
777 if (sock < 0)
778 die(1, "Fatal: tcp_listen() failed.\n");
779 break;
780
781 case 'C':
782 /* silently ignore existing connections */
783 if (sock == -1)
784 sock = tcp_connect(&ss, argv[arg]);
785 if (sock < 0)
786 die(1, "Fatal: tcp_connect() failed.\n");
Willy Tarreau869c7592016-11-12 17:50:57 +0100787 dolog("connect\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100788 break;
789
790 case 'A':
791 if (sock < 0)
792 die(1, "Fatal: tcp_accept() on non-socket.\n");
793 sock = tcp_accept(sock, argv[arg]);
794 if (sock < 0)
795 die(1, "Fatal: tcp_accept() failed.\n");
Willy Tarreau869c7592016-11-12 17:50:57 +0100796 dolog("accept\n");
Willy Tarreau29cc11c2016-11-12 18:54:20 +0100797 loop_arg = arg + 1; // cannot loop before accept()
Willy Tarreau84393aa2016-11-12 11:29:46 +0100798 break;
799
800 case 'T':
801 if (sock < 0)
802 die(1, "Fatal: tcp_set_nodelay() on non-socket.\n");
803 if (tcp_set_nodelay(sock, argv[arg]) < 0)
804 die(1, "Fatal: tcp_set_nodelay() failed.\n");
805 break;
806
807 case 'G':
808 if (sock < 0)
809 die(1, "Fatal: tcp_set_nolinger() on non-socket.\n");
810 if (tcp_set_nolinger(sock, argv[arg]) < 0)
811 die(1, "Fatal: tcp_set_nolinger() failed.\n");
812 break;
813
814 case 'Q':
815 if (sock < 0)
816 die(1, "Fatal: tcp_set_noquickack() on non-socket.\n");
817 if (tcp_set_noquickack(sock, argv[arg]) < 0)
818 die(1, "Fatal: tcp_set_noquickack() failed.\n");
819 break;
820
821 case 'R':
822 if (sock < 0)
823 die(1, "Fatal: tcp_recv() on non-socket.\n");
Willy Tarreau1973e812016-11-12 18:45:42 +0100824 ret = tcp_recv(sock, argv[arg]);
825 if (ret < 0) {
826 if (ret == -1) // usually ECONNRESET, silently exit
827 die(0, NULL);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100828 die(1, "Fatal: tcp_recv() failed.\n");
Willy Tarreau1973e812016-11-12 18:45:42 +0100829 }
Willy Tarreau84393aa2016-11-12 11:29:46 +0100830 break;
831
832 case 'S':
833 if (sock < 0)
834 die(1, "Fatal: tcp_send() on non-socket.\n");
Willy Tarreau1973e812016-11-12 18:45:42 +0100835 ret = tcp_send(sock, argv[arg]);
836 if (ret < 0) {
837 if (ret == -1) // usually a broken pipe, silently exit
838 die(0, NULL);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100839 die(1, "Fatal: tcp_send() failed.\n");
Willy Tarreau1973e812016-11-12 18:45:42 +0100840 }
Willy Tarreau84393aa2016-11-12 11:29:46 +0100841 break;
842
843 case 'E':
844 if (sock < 0)
845 die(1, "Fatal: tcp_echo() on non-socket.\n");
846 if (tcp_echo(sock, argv[arg]) < 0)
847 die(1, "Fatal: tcp_echo() failed.\n");
848 break;
849
850 case 'P':
851 if (tcp_pause(sock, argv[arg]) < 0)
852 die(1, "Fatal: tcp_pause() failed.\n");
853 break;
854
855 case 'W':
856 if (sock < 0)
857 die(1, "Fatal: tcp_wait() on non-socket.\n");
858 if (tcp_wait(sock, argv[arg]) < 0)
859 die(1, "Fatal: tcp_wait() failed.\n");
Willy Tarreau869c7592016-11-12 17:50:57 +0100860 dolog("ready_any\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100861 break;
862
863 case 'I':
864 if (sock < 0)
865 die(1, "Fatal: tcp_wait_in() on non-socket.\n");
866 if (tcp_wait_in(sock, argv[arg]) < 0)
867 die(1, "Fatal: tcp_wait_in() failed.\n");
Willy Tarreau869c7592016-11-12 17:50:57 +0100868 dolog("ready_in\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100869 break;
870
871 case 'O':
872 if (sock < 0)
873 die(1, "Fatal: tcp_wait_out() on non-socket.\n");
874 if (tcp_wait_out(sock, argv[arg]) < 0)
875 die(1, "Fatal: tcp_wait_out() failed.\n");
Willy Tarreau869c7592016-11-12 17:50:57 +0100876 dolog("ready_out\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100877 break;
878
879 case 'K':
880 if (sock < 0 || close(sock) < 0)
881 die(1, "Fatal: close() on non-socket.\n");
Willy Tarreau869c7592016-11-12 17:50:57 +0100882 dolog("close\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100883 sock = -1;
884 break;
885
886 case 'F':
887 /* ignore errors on shutdown() as they are common */
888 if (sock >= 0)
889 shutdown(sock, SHUT_WR);
Willy Tarreau869c7592016-11-12 17:50:57 +0100890 dolog("shutdown\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100891 break;
892
Willy Tarreau95a6b782016-11-12 13:25:53 +0100893 case 'N':
894 ret = tcp_fork(sock, argv[arg]);
895 if (ret < 0)
896 die(1, "Fatal: fork() failed.\n");
897 if (ret > 0) {
898 /* loop back to first arg */
Willy Tarreau29cc11c2016-11-12 18:54:20 +0100899 arg = loop_arg - 1;
Willy Tarreau95a6b782016-11-12 13:25:53 +0100900 continue;
901 }
902 /* OK we're in the child, let's continue */
Willy Tarreau869c7592016-11-12 17:50:57 +0100903 pid = getpid();
Willy Tarreau29cc11c2016-11-12 18:54:20 +0100904 loop_arg = arg + 1;
Willy Tarreau95a6b782016-11-12 13:25:53 +0100905 break;
Willy Tarreau29cc11c2016-11-12 18:54:20 +0100906
907 case 'J': // jump back to oldest post-fork action
908 arg = loop_arg - 1;
909 continue;
910
Willy Tarreaub7a6d0d2017-05-02 22:14:59 +0200911 case 'X': // execute command. Optionally supports redirecting only i/o/e
912 if (arg + 1 >= argc)
913 die(1, "Fatal: missing argument after %s\n", argv[arg]);
914
915 errfd = dup(2);
916 fcntl(errfd, F_SETFD, fcntl(errfd, F_GETFD, FD_CLOEXEC) | FD_CLOEXEC);
917 fcntl(sock, F_SETFL, fcntl(sock, F_GETFL, O_NONBLOCK) & ~O_NONBLOCK);
918 if (!argv[arg][1] || strchr(argv[arg], 'i'))
919 dup2(sock, 0);
920 if (!argv[arg][1] || strchr(argv[arg], 'o'))
921 dup2(sock, 1);
922 if (!argv[arg][1] || strchr(argv[arg], 'e'))
923 dup2(sock, 2);
924 argv += arg + 1;
925 if (execvp(argv[0], argv) == -1) {
926 int e = errno;
927
928 dup2(errfd, 2); // restore original stderr
929 close(errfd);
930 die(1, "Fatal: execvp(%s) failed : %s\n", argv[0], strerror(e));
931 }
932 break;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100933 default:
934 usage(1, arg0);
935 }
936 }
937 return 0;
938}