blob: d1995f46e4641a0fd8e268bb562ecfe92e5dfcdf [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"
125 "\n"
126 "It's important to note that a single FD is used at once and that Accept\n"
127 "replaces the listening FD with the accepted one. Thus always do it after\n"
128 "a fork if other connections have to be accepted.\n"
129 "\n"
130 "After a fork, we loop back to the beginning and silently skip L/C if the\n"
131 "main socket already exists.\n"
132 "\n"
133 "Example dummy HTTP request drain server :\n"
134 " tcploop 8001 L W N20 A R S10 [ F K ]\n"
135 "\n"
136 "Example large bandwidth HTTP request drain server :\n"
137 " tcploop 8001 L W N20 A R S0 [ F K ]\n"
138 "\n"
139 "Example TCP client with pauses at each step :\n"
140 " tcploop 8001 C T W P100 S10 O P100 R S10 O R G K\n"
141 "", arg0);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100142}
143
Willy Tarreau869c7592016-11-12 17:50:57 +0100144void dolog(const char *format, ...)
145{
146 struct timeval date, tv;
147 int delay;
148 va_list args;
149
150 if (!verbose)
151 return;
152
153 if (showtime) {
154 gettimeofday(&date, NULL);
155 switch (showtime) {
156 case 1: // [msec] relative
157 delay = (date.tv_sec - start_time.tv_sec) * 1000000 + date.tv_usec - start_time.tv_usec;
158 fprintf(stderr, "[%d] ", delay / 1000);
159 break;
160 case 2: // [sec.usec] relative
161 tv.tv_usec = date.tv_usec - start_time.tv_usec;
162 tv.tv_sec = date.tv_sec - start_time.tv_sec;
163 if ((signed)tv.tv_sec > 0) {
164 if ((signed)tv.tv_usec < 0) {
165 tv.tv_usec += 1000000;
166 tv.tv_sec--;
167 }
168 } else if (tv.tv_sec == 0) {
169 if ((signed)tv.tv_usec < 0)
170 tv.tv_usec = 0;
171 } else {
172 tv.tv_sec = 0;
173 tv.tv_usec = 0;
174 }
Willy Tarreau752cc492017-03-14 14:37:13 +0100175 fprintf(stderr, "[%d.%06d] ", (int)tv.tv_sec, (int)tv.tv_usec);
Willy Tarreau869c7592016-11-12 17:50:57 +0100176 break;
177 default: // [sec.usec] absolute
Willy Tarreau752cc492017-03-14 14:37:13 +0100178 fprintf(stderr, "[%d.%06d] ", (int)date.tv_sec, (int)date.tv_usec);
Willy Tarreau869c7592016-11-12 17:50:57 +0100179 break;
180 }
181 }
182
183 fprintf(stderr, "%5d ", pid);
184
185 va_start(args, format);
186 vfprintf(stderr, format, args);
187 va_end(args);
188}
189
Willy Tarreau59623e02016-11-12 18:25:45 +0100190/* convert '\n', '\t', '\r', '\\' to their respective characters */
191int unescape(char *out, int size, const char *in)
192{
193 int len;
194
195 for (len = 0; len < size && *in; in++, out++, len++) {
196 if (*in == '\\') {
197 switch (in[1]) {
198 case 'n' : *out = '\n'; in++; continue;
199 case 't' : *out = '\t'; in++; continue;
200 case 'r' : *out = '\r'; in++; continue;
201 case '\\' : *out = '\\'; in++; continue;
202 default : break;
203 }
204 }
205 *out = *in;
206 }
207 return len;
208}
209
Willy Tarreau84393aa2016-11-12 11:29:46 +0100210struct err_msg *alloc_err_msg(int size)
211{
212 struct err_msg *err;
213
214 err = malloc(sizeof(*err) + size);
215 if (err) {
216 err->len = 0;
217 err->size = size;
218 }
219 return err;
220}
221
Willy Tarreau95a6b782016-11-12 13:25:53 +0100222void sig_handler(int sig)
223{
224 if (sig == SIGCHLD) {
225 while (waitpid(-1, NULL, WNOHANG) > 0)
226 __sync_sub_and_fetch(&nbproc, 1);
227 }
228}
Willy Tarreau84393aa2016-11-12 11:29:46 +0100229
230/* converts str in the form [[<ipv4>|<ipv6>|<hostname>]:]port to struct sockaddr_storage.
231 * Returns < 0 with err set in case of error.
232 */
233int addr_to_ss(char *str, struct sockaddr_storage *ss, struct err_msg *err)
234{
235 char *port_str;
236 int port;
237
238 memset(ss, 0, sizeof(*ss));
239
240 /* look for the addr/port delimiter, it's the last colon. If there's no
241 * colon, it's 0:<port>.
242 */
243 if ((port_str = strrchr(str, ':')) == NULL) {
244 port = atoi(str);
245 if (port <= 0 || port > 65535) {
246 err->len = snprintf(err->msg, err->size, "Missing/invalid port number: '%s'\n", str);
247 return -1;
248 }
249
250 ss->ss_family = AF_INET;
251 ((struct sockaddr_in *)ss)->sin_port = htons(port);
252 ((struct sockaddr_in *)ss)->sin_addr.s_addr = INADDR_ANY;
253 return 0;
254 }
255
256 *port_str++ = 0;
257
258 if (strrchr(str, ':') != NULL) {
259 /* IPv6 address contains ':' */
260 ss->ss_family = AF_INET6;
261 ((struct sockaddr_in6 *)ss)->sin6_port = htons(atoi(port_str));
262
263 if (!inet_pton(ss->ss_family, str, &((struct sockaddr_in6 *)ss)->sin6_addr)) {
264 err->len = snprintf(err->msg, err->size, "Invalid server address: '%s'\n", str);
265 return -1;
266 }
267 }
268 else {
269 ss->ss_family = AF_INET;
270 ((struct sockaddr_in *)ss)->sin_port = htons(atoi(port_str));
271
272 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
273 ((struct sockaddr_in *)ss)->sin_addr.s_addr = INADDR_ANY;
274 return 0;
275 }
276
277 if (!inet_pton(ss->ss_family, str, &((struct sockaddr_in *)ss)->sin_addr)) {
278 struct hostent *he = gethostbyname(str);
279
280 if (he == NULL) {
281 err->len = snprintf(err->msg, err->size, "Invalid server name: '%s'\n", str);
282 return -1;
283 }
284 ((struct sockaddr_in *)ss)->sin_addr = *(struct in_addr *) *(he->h_addr_list);
285 }
286 }
287
288 return 0;
289}
290
291/* waits up to one second on fd <fd> for events <events> (POLLIN|POLLOUT).
292 * returns poll's status.
293 */
294int wait_on_fd(int fd, int events)
295{
296 struct pollfd pollfd;
297 int ret;
298
299 do {
300 pollfd.fd = fd;
301 pollfd.events = events;
302 ret = poll(&pollfd, 1, 1000);
303 } while (ret == -1 && errno == EINTR);
304
305 return ret;
306}
307
308int tcp_set_nodelay(int sock, const char *arg)
309{
310 return setsockopt(sock, SOL_TCP, TCP_NODELAY, &one, sizeof(one));
311}
312
313int tcp_set_nolinger(int sock, const char *arg)
314{
315 return setsockopt(sock, SOL_SOCKET, SO_LINGER, (struct linger *) &nolinger, sizeof(struct linger));
316}
317
318int tcp_set_noquickack(int sock, const char *arg)
319{
Willy Tarreau0c0c0a62017-03-14 14:36:26 +0100320#ifdef TCP_QUICKACK
Willy Tarreau84393aa2016-11-12 11:29:46 +0100321 /* warning: do not use during connect if nothing is to be sent! */
322 return setsockopt(sock, SOL_TCP, TCP_QUICKACK, &zero, sizeof(zero));
Willy Tarreau0c0c0a62017-03-14 14:36:26 +0100323#else
324 return 0;
325#endif
Willy Tarreau84393aa2016-11-12 11:29:46 +0100326}
327
328/* Try to listen to address <sa>. Return the fd or -1 in case of error */
329int tcp_listen(const struct sockaddr_storage *sa, const char *arg)
330{
331 int sock;
332 int backlog;
333
334 if (arg[1])
335 backlog = atoi(arg + 1);
336 else
337 backlog = 1000;
338
339 if (backlog < 0 || backlog > 65535) {
340 fprintf(stderr, "backlog must be between 0 and 65535 inclusive (was %d)\n", backlog);
341 return -1;
342 }
343
344 sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
345 if (sock < 0) {
346 perror("socket()");
347 return -1;
348 }
349
350 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) == -1) {
351 perror("setsockopt(SO_REUSEADDR)");
352 goto fail;
353 }
354
355#ifdef SO_REUSEPORT
356 if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (char *) &one, sizeof(one)) == -1) {
357 perror("setsockopt(SO_REUSEPORT)");
358 goto fail;
359 }
360#endif
361 if (bind(sock, (struct sockaddr *)sa, sa->ss_family == AF_INET6 ?
362 sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) == -1) {
363 perror("bind");
364 goto fail;
365 }
366
367 if (listen(sock, backlog) == -1) {
368 perror("listen");
369 goto fail;
370 }
371
372 return sock;
373 fail:
374 close(sock);
375 return -1;
376}
377
378/* accepts a socket from listening socket <sock>, and returns it (or -1 in case of error) */
379int tcp_accept(int sock, const char *arg)
380{
381 int count;
382 int newsock;
383
384 if (arg[1])
385 count = atoi(arg + 1);
386 else
387 count = 1;
388
389 if (count <= 0) {
390 fprintf(stderr, "accept count must be > 0 or unset (was %d)\n", count);
391 return -1;
392 }
393
394 do {
395 newsock = accept(sock, NULL, NULL);
396 if (newsock < 0) { // TODO: improve error handling
397 if (errno == EINTR || errno == EAGAIN || errno == ECONNABORTED)
398 continue;
399 perror("accept()");
400 break;
401 }
402
403 if (count > 1)
404 close(newsock);
405 count--;
406 } while (count > 0);
407
408 fcntl(newsock, F_SETFL, O_NONBLOCK);
409 return newsock;
410}
411
412/* Try to establish a new connection to <sa>. Return the fd or -1 in case of error */
413int tcp_connect(const struct sockaddr_storage *sa, const char *arg)
414{
415 int sock;
416
417 sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
418 if (sock < 0)
419 return -1;
420
421 if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1)
422 goto fail;
423
424 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) == -1)
425 goto fail;
426
Willy Tarreau24d41b92017-03-14 14:50:05 +0100427 if (connect(sock, (const struct sockaddr *)sa, sizeof(struct sockaddr_in)) < 0) {
Willy Tarreau84393aa2016-11-12 11:29:46 +0100428 if (errno != EINPROGRESS)
429 goto fail;
430 }
431
432 return sock;
433 fail:
434 close(sock);
435 return -1;
436}
437
Willy Tarreau1973e812016-11-12 18:45:42 +0100438/* receives N bytes from the socket and returns 0 (or -1 in case of a recv
439 * error, or -2 in case of an argument error). When no arg is passed, receives
440 * anything and stops. Otherwise reads the requested amount of data. 0 means
441 * read as much as possible.
Willy Tarreau84393aa2016-11-12 11:29:46 +0100442 */
443int tcp_recv(int sock, const char *arg)
444{
445 int count = -1; // stop at first read
446 int ret;
447
448 if (arg[1]) {
449 count = atoi(arg + 1);
450 if (count < 0) {
451 fprintf(stderr, "recv count must be >= 0 or unset (was %d)\n", count);
Willy Tarreau1973e812016-11-12 18:45:42 +0100452 return -2;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100453 }
454 }
455
456 while (1) {
457 ret = recv(sock, NULL, (count > 0) ? count : INT_MAX, MSG_NOSIGNAL | MSG_TRUNC);
458 if (ret < 0) {
459 if (errno == EINTR)
460 continue;
Willy Tarreau869c7592016-11-12 17:50:57 +0100461 if (errno != EAGAIN) {
462 dolog("recv %d\n", ret);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100463 return -1;
Willy Tarreau869c7592016-11-12 17:50:57 +0100464 }
Willy Tarreau84393aa2016-11-12 11:29:46 +0100465 while (!wait_on_fd(sock, POLLIN));
466 continue;
467 }
Willy Tarreau869c7592016-11-12 17:50:57 +0100468 dolog("recv %d\n", ret);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100469 if (!ret)
470 break;
471
472 if (!count)
473 continue;
474 else if (count > 0)
475 count -= ret;
476
477 if (count <= 0)
478 break;
479 }
480
481 return 0;
482}
483
Willy Tarreau1973e812016-11-12 18:45:42 +0100484/* Sends N bytes to the socket and returns 0 (or -1 in case of send error, -2
485 * in case of an argument error. If the byte count is not set, sends only one
486 * block. Sending zero means try to send forever. If the argument starts with
487 * ':' then whatever follows is interpreted as the payload to be sent as-is.
488 * Escaped characters '\r', '\n', '\t' and '\\' are detected and converted. In
Willy Tarreau59623e02016-11-12 18:25:45 +0100489 * this case, blocks must be small so that send() doesn't fragment them, as
490 * they will be put into the trash and expected to be sent at once.
Willy Tarreau84393aa2016-11-12 11:29:46 +0100491 */
492int tcp_send(int sock, const char *arg)
493{
494 int count = -1; // stop after first block
495 int ret;
496
Willy Tarreau59623e02016-11-12 18:25:45 +0100497 if (arg[1] == ':') {
498 count = unescape(trash, sizeof(trash), arg + 2);
499 } else if (arg[1]) {
Willy Tarreau84393aa2016-11-12 11:29:46 +0100500 count = atoi(arg + 1);
Willy Tarreau869c7592016-11-12 17:50:57 +0100501 if (count < 0) {
Willy Tarreau84393aa2016-11-12 11:29:46 +0100502 fprintf(stderr, "send count must be >= 0 or unset (was %d)\n", count);
Willy Tarreau1973e812016-11-12 18:45:42 +0100503 return -2;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100504 }
505 }
506
507 while (1) {
508 ret = send(sock, trash,
509 (count > 0) && (count < sizeof(trash)) ? count : sizeof(trash),
510 MSG_NOSIGNAL | ((count > sizeof(trash)) ? MSG_MORE : 0));
511 if (ret < 0) {
512 if (errno == EINTR)
513 continue;
Willy Tarreau869c7592016-11-12 17:50:57 +0100514 if (errno != EAGAIN) {
515 dolog("send %d\n", ret);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100516 return -1;
Willy Tarreau869c7592016-11-12 17:50:57 +0100517 }
Willy Tarreau84393aa2016-11-12 11:29:46 +0100518 while (!wait_on_fd(sock, POLLOUT));
519 continue;
520 }
Willy Tarreau869c7592016-11-12 17:50:57 +0100521 dolog("send %d\n", ret);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100522 if (!count)
523 continue;
524 else if (count > 0)
525 count -= ret;
526
527 if (count <= 0)
528 break;
529 }
530
531 return 0;
532}
533
534/* echoes N bytes to the socket and returns 0 (or -1 in case of error). If not
535 * set, echoes only the first block. Zero means forward forever.
536 */
537int tcp_echo(int sock, const char *arg)
538{
539 int count = -1; // echo forever
540 int ret;
541 int rcvd;
542
543 if (arg[1]) {
544 count = atoi(arg + 1);
545 if (count < 0) {
546 fprintf(stderr, "send count must be >= 0 or unset (was %d)\n", count);
547 return -1;
548 }
549 }
550
551 rcvd = 0;
552 while (1) {
553 if (rcvd <= 0) {
554 /* no data pending */
555 rcvd = recv(sock, trash, (count > 0) && (count < sizeof(trash)) ? count : sizeof(trash), MSG_NOSIGNAL);
556 if (rcvd < 0) {
557 if (errno == EINTR)
558 continue;
Willy Tarreau869c7592016-11-12 17:50:57 +0100559 if (errno != EAGAIN) {
560 dolog("recv %d\n", rcvd);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100561 return -1;
Willy Tarreau869c7592016-11-12 17:50:57 +0100562 }
Willy Tarreau84393aa2016-11-12 11:29:46 +0100563 while (!wait_on_fd(sock, POLLIN));
564 continue;
565 }
Willy Tarreau869c7592016-11-12 17:50:57 +0100566 dolog("recv %d\n", rcvd);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100567 if (!rcvd)
568 break;
569 }
570 else {
571 /* some data still pending */
572 ret = send(sock, trash, rcvd, MSG_NOSIGNAL | ((count > rcvd) ? MSG_MORE : 0));
573 if (ret < 0) {
574 if (errno == EINTR)
575 continue;
Willy Tarreau869c7592016-11-12 17:50:57 +0100576 if (errno != EAGAIN) {
577 dolog("send %d\n", ret);
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, POLLOUT));
581 continue;
582 }
Willy Tarreau869c7592016-11-12 17:50:57 +0100583 dolog("send %d\n", ret);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100584 rcvd -= ret;
585 if (rcvd)
586 continue;
587
588 if (!count)
589 continue;
590 else if (count > 0)
591 count -= ret;
592
593 if (count <= 0)
594 break;
595 }
596 }
597 return 0;
598}
599
600/* waits for an event on the socket, usually indicates an accept for a
601 * listening socket and a connect for an outgoing socket.
602 */
603int tcp_wait(int sock, const char *arg)
604{
605 struct pollfd pollfd;
606 int delay = -1; // wait forever
607 int ret;
608
609 if (arg[1]) {
610 delay = atoi(arg + 1);
611 if (delay < 0) {
612 fprintf(stderr, "wait time must be >= 0 or unset (was %d)\n", delay);
613 return -1;
614 }
615 }
616
617 /* FIXME: this doesn't take into account delivered signals */
618 do {
619 pollfd.fd = sock;
620 pollfd.events = POLLIN | POLLOUT;
621 ret = poll(&pollfd, 1, delay);
622 } while (ret == -1 && errno == EINTR);
623
Willy Tarreau869c7592016-11-12 17:50:57 +0100624 if (ret > 0 && pollfd.revents & POLLERR)
625 return -1;
626
Willy Tarreau84393aa2016-11-12 11:29:46 +0100627 return 0;
628}
629
630/* waits for the input data to be present */
631int tcp_wait_in(int sock, const char *arg)
632{
633 struct pollfd pollfd;
634 int ret;
635
636 do {
637 pollfd.fd = sock;
638 pollfd.events = POLLIN;
639 ret = poll(&pollfd, 1, 1000);
640 } while (ret == -1 && errno == EINTR);
Willy Tarreau869c7592016-11-12 17:50:57 +0100641
642 if (ret > 0 && pollfd.revents & POLLERR)
643 return -1;
644
Willy Tarreau84393aa2016-11-12 11:29:46 +0100645 return 0;
646}
647
648/* waits for the output queue to be empty */
649int tcp_wait_out(int sock, const char *arg)
650{
651 struct pollfd pollfd;
652 int ret;
653
654 do {
655 pollfd.fd = sock;
656 pollfd.events = POLLOUT;
657 ret = poll(&pollfd, 1, 1000);
658 } while (ret == -1 && errno == EINTR);
659
Willy Tarreau869c7592016-11-12 17:50:57 +0100660 if (ret > 0 && pollfd.revents & POLLERR)
661 return -1;
662
Willy Tarreau84393aa2016-11-12 11:29:46 +0100663 /* Now wait for data to leave the socket */
664 do {
665 if (ioctl(sock, TIOCOUTQ, &ret) < 0)
666 return -1;
667 } while (ret > 0);
668 return 0;
669}
670
671/* delays processing for <time> milliseconds, 100 by default */
672int tcp_pause(int sock, const char *arg)
673{
674 struct pollfd pollfd;
675 int delay = 100;
676 int ret;
677
678 if (arg[1]) {
679 delay = atoi(arg + 1);
680 if (delay < 0) {
681 fprintf(stderr, "wait time must be >= 0 or unset (was %d)\n", delay);
682 return -1;
683 }
684 }
685
686 usleep(delay * 1000);
687 return 0;
688}
689
Willy Tarreau95a6b782016-11-12 13:25:53 +0100690/* forks another process while respecting the limit imposed in argument (1 by
691 * default). Will wait for another process to exit before creating a new one.
692 * Returns the value of the fork() syscall, ie 0 for the child, non-zero for
693 * the parent, -1 for an error.
694 */
695int tcp_fork(int sock, const char *arg)
696{
697 int max = 1;
698 int ret;
699
700 if (arg[1]) {
701 max = atoi(arg + 1);
702 if (max <= 0) {
703 fprintf(stderr, "max process must be > 0 or unset (was %d)\n", max);
704 return -1;
705 }
706 }
707
708 while (nbproc >= max)
709 poll(NULL, 0, 1000);
710
711 ret = fork();
712 if (ret > 0)
713 __sync_add_and_fetch(&nbproc, 1);
714 return ret;
715}
716
Willy Tarreau84393aa2016-11-12 11:29:46 +0100717int main(int argc, char **argv)
718{
719 struct sockaddr_storage ss;
720 struct err_msg err;
721 const char *arg0;
Willy Tarreau29cc11c2016-11-12 18:54:20 +0100722 int loop_arg;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100723 int arg;
Willy Tarreau95a6b782016-11-12 13:25:53 +0100724 int ret;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100725 int sock;
726
727 arg0 = argv[0];
Willy Tarreau869c7592016-11-12 17:50:57 +0100728
729 while (argc > 1 && argv[1][0] == '-') {
730 argc--; argv++;
731 if (strcmp(argv[0], "-t") == 0)
732 showtime++;
733 else if (strcmp(argv[0], "-tt") == 0)
734 showtime += 2;
735 else if (strcmp(argv[0], "-ttt") == 0)
736 showtime += 3;
737 else if (strcmp(argv[0], "-v") == 0)
738 verbose ++;
739 else if (strcmp(argv[0], "--") == 0)
740 break;
741 else
742 usage(1, arg0);
743 }
744
Willy Tarreau84393aa2016-11-12 11:29:46 +0100745 if (argc < 2)
746 usage(1, arg0);
747
Willy Tarreau869c7592016-11-12 17:50:57 +0100748 pid = getpid();
Willy Tarreau95a6b782016-11-12 13:25:53 +0100749 signal(SIGCHLD, sig_handler);
750
Willy Tarreau84393aa2016-11-12 11:29:46 +0100751 if (addr_to_ss(argv[1], &ss, &err) < 0)
752 die(1, "%s\n", err.msg);
753
Willy Tarreau869c7592016-11-12 17:50:57 +0100754 gettimeofday(&start_time, NULL);
755
Willy Tarreau84393aa2016-11-12 11:29:46 +0100756 sock = -1;
Willy Tarreau29cc11c2016-11-12 18:54:20 +0100757 loop_arg = 2;
758 for (arg = loop_arg; arg < argc; arg++) {
Willy Tarreau84393aa2016-11-12 11:29:46 +0100759 switch (argv[arg][0]) {
760 case 'L':
761 /* silently ignore existing connections */
762 if (sock == -1)
763 sock = tcp_listen(&ss, argv[arg]);
764 if (sock < 0)
765 die(1, "Fatal: tcp_listen() failed.\n");
766 break;
767
768 case 'C':
769 /* silently ignore existing connections */
770 if (sock == -1)
771 sock = tcp_connect(&ss, argv[arg]);
772 if (sock < 0)
773 die(1, "Fatal: tcp_connect() failed.\n");
Willy Tarreau869c7592016-11-12 17:50:57 +0100774 dolog("connect\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100775 break;
776
777 case 'A':
778 if (sock < 0)
779 die(1, "Fatal: tcp_accept() on non-socket.\n");
780 sock = tcp_accept(sock, argv[arg]);
781 if (sock < 0)
782 die(1, "Fatal: tcp_accept() failed.\n");
Willy Tarreau869c7592016-11-12 17:50:57 +0100783 dolog("accept\n");
Willy Tarreau29cc11c2016-11-12 18:54:20 +0100784 loop_arg = arg + 1; // cannot loop before accept()
Willy Tarreau84393aa2016-11-12 11:29:46 +0100785 break;
786
787 case 'T':
788 if (sock < 0)
789 die(1, "Fatal: tcp_set_nodelay() on non-socket.\n");
790 if (tcp_set_nodelay(sock, argv[arg]) < 0)
791 die(1, "Fatal: tcp_set_nodelay() failed.\n");
792 break;
793
794 case 'G':
795 if (sock < 0)
796 die(1, "Fatal: tcp_set_nolinger() on non-socket.\n");
797 if (tcp_set_nolinger(sock, argv[arg]) < 0)
798 die(1, "Fatal: tcp_set_nolinger() failed.\n");
799 break;
800
801 case 'Q':
802 if (sock < 0)
803 die(1, "Fatal: tcp_set_noquickack() on non-socket.\n");
804 if (tcp_set_noquickack(sock, argv[arg]) < 0)
805 die(1, "Fatal: tcp_set_noquickack() failed.\n");
806 break;
807
808 case 'R':
809 if (sock < 0)
810 die(1, "Fatal: tcp_recv() on non-socket.\n");
Willy Tarreau1973e812016-11-12 18:45:42 +0100811 ret = tcp_recv(sock, argv[arg]);
812 if (ret < 0) {
813 if (ret == -1) // usually ECONNRESET, silently exit
814 die(0, NULL);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100815 die(1, "Fatal: tcp_recv() failed.\n");
Willy Tarreau1973e812016-11-12 18:45:42 +0100816 }
Willy Tarreau84393aa2016-11-12 11:29:46 +0100817 break;
818
819 case 'S':
820 if (sock < 0)
821 die(1, "Fatal: tcp_send() on non-socket.\n");
Willy Tarreau1973e812016-11-12 18:45:42 +0100822 ret = tcp_send(sock, argv[arg]);
823 if (ret < 0) {
824 if (ret == -1) // usually a broken pipe, silently exit
825 die(0, NULL);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100826 die(1, "Fatal: tcp_send() failed.\n");
Willy Tarreau1973e812016-11-12 18:45:42 +0100827 }
Willy Tarreau84393aa2016-11-12 11:29:46 +0100828 break;
829
830 case 'E':
831 if (sock < 0)
832 die(1, "Fatal: tcp_echo() on non-socket.\n");
833 if (tcp_echo(sock, argv[arg]) < 0)
834 die(1, "Fatal: tcp_echo() failed.\n");
835 break;
836
837 case 'P':
838 if (tcp_pause(sock, argv[arg]) < 0)
839 die(1, "Fatal: tcp_pause() failed.\n");
840 break;
841
842 case 'W':
843 if (sock < 0)
844 die(1, "Fatal: tcp_wait() on non-socket.\n");
845 if (tcp_wait(sock, argv[arg]) < 0)
846 die(1, "Fatal: tcp_wait() failed.\n");
Willy Tarreau869c7592016-11-12 17:50:57 +0100847 dolog("ready_any\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100848 break;
849
850 case 'I':
851 if (sock < 0)
852 die(1, "Fatal: tcp_wait_in() on non-socket.\n");
853 if (tcp_wait_in(sock, argv[arg]) < 0)
854 die(1, "Fatal: tcp_wait_in() failed.\n");
Willy Tarreau869c7592016-11-12 17:50:57 +0100855 dolog("ready_in\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100856 break;
857
858 case 'O':
859 if (sock < 0)
860 die(1, "Fatal: tcp_wait_out() on non-socket.\n");
861 if (tcp_wait_out(sock, argv[arg]) < 0)
862 die(1, "Fatal: tcp_wait_out() failed.\n");
Willy Tarreau869c7592016-11-12 17:50:57 +0100863 dolog("ready_out\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100864 break;
865
866 case 'K':
867 if (sock < 0 || close(sock) < 0)
868 die(1, "Fatal: close() on non-socket.\n");
Willy Tarreau869c7592016-11-12 17:50:57 +0100869 dolog("close\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100870 sock = -1;
871 break;
872
873 case 'F':
874 /* ignore errors on shutdown() as they are common */
875 if (sock >= 0)
876 shutdown(sock, SHUT_WR);
Willy Tarreau869c7592016-11-12 17:50:57 +0100877 dolog("shutdown\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100878 break;
879
Willy Tarreau95a6b782016-11-12 13:25:53 +0100880 case 'N':
881 ret = tcp_fork(sock, argv[arg]);
882 if (ret < 0)
883 die(1, "Fatal: fork() failed.\n");
884 if (ret > 0) {
885 /* loop back to first arg */
Willy Tarreau29cc11c2016-11-12 18:54:20 +0100886 arg = loop_arg - 1;
Willy Tarreau95a6b782016-11-12 13:25:53 +0100887 continue;
888 }
889 /* OK we're in the child, let's continue */
Willy Tarreau869c7592016-11-12 17:50:57 +0100890 pid = getpid();
Willy Tarreau29cc11c2016-11-12 18:54:20 +0100891 loop_arg = arg + 1;
Willy Tarreau95a6b782016-11-12 13:25:53 +0100892 break;
Willy Tarreau29cc11c2016-11-12 18:54:20 +0100893
894 case 'J': // jump back to oldest post-fork action
895 arg = loop_arg - 1;
896 continue;
897
Willy Tarreau84393aa2016-11-12 11:29:46 +0100898 default:
899 usage(1, arg0);
900 }
901 }
902 return 0;
903}