blob: 9429aff0d5a8fe01bb74549279cbfcc1ba80848f [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>
42#include <netdb.h>
43#include <poll.h>
44#include <signal.h>
45#include <stdarg.h>
46#include <stdio.h>
47#include <stdlib.h>
48#include <string.h>
49#include <time.h>
50#include <unistd.h>
51
52
53struct err_msg {
54 int size;
55 int len;
56 char msg[0];
57};
58
59const int zero = 0;
60const int one = 1;
61const struct linger nolinger = { .l_onoff = 1, .l_linger = 0 };
62
63#define TRASH_SIZE 65536
64static char trash[TRASH_SIZE];
65
Willy Tarreau95a6b782016-11-12 13:25:53 +010066volatile int nbproc = 0;
Willy Tarreau869c7592016-11-12 17:50:57 +010067static struct timeval start_time;
68static int showtime;
69static int verbose;
70static int pid;
71
Willy Tarreau95a6b782016-11-12 13:25:53 +010072
Willy Tarreau84393aa2016-11-12 11:29:46 +010073/* display the message and exit with the code */
74__attribute__((noreturn)) void die(int code, const char *format, ...)
75{
76 va_list args;
77
Willy Tarreau1973e812016-11-12 18:45:42 +010078 if (format) {
79 va_start(args, format);
80 vfprintf(stderr, format, args);
81 va_end(args);
82 }
Willy Tarreau84393aa2016-11-12 11:29:46 +010083 exit(code);
84}
85
86/* display the usage message and exit with the code */
87__attribute__((noreturn)) void usage(int code, const char *arg0)
88{
Willy Tarreau9557bac2016-11-12 17:53:16 +010089 die(code,
90 "Usage : %s [options]* [<ip>:]port [<action>*]\n"
91 "\n"
92 "options :\n"
93 " -v : verbose\n"
94 " -t|-tt|-ttt : show time (msec / relative / absolute)\n"
95 "actions :\n"
96 " L[<backlog>] : Listens to ip:port and optionally sets backlog\n"
97 " Note: fd=socket,bind(fd),listen(fd)\n"
98 " C : Connects to ip:port\n"
99 " Note: fd=socket,connect(fd)\n"
100 " A[<count>] : Accepts <count> incoming sockets and closes count-1\n"
101 " Note: fd=accept(fd)\n"
102 " G : disable lingering\n"
103 " T : set TCP_NODELAY\n"
104 " Q : disable TCP Quick-ack\n"
105 " R[<size>] : Read this amount of bytes. 0=infinite. unset=any amount.\n"
106 " S[<size>] : Send this amount of bytes. 0=infinite. unset=any amount.\n"
Willy Tarreau59623e02016-11-12 18:25:45 +0100107 " S:<string> : Send this exact string. \\r, \\n, \\t, \\\\ supported.\n"
Willy Tarreau9557bac2016-11-12 17:53:16 +0100108 " E[<size>] : Echo this amount of bytes. 0=infinite. unset=any amount.\n"
109 " W[<time>] : Wait for any event on the socket, maximum <time> ms\n"
110 " P[<time>] : Pause for <time> ms (100 by default)\n"
111 " I : wait for Input data to be present (POLLIN)\n"
112 " O : wait for Output queue to be empty (POLLOUT + TIOCOUTQ)\n"
113 " F : FIN : shutdown(SHUT_WR)\n"
114 " N<max> : fork New process, limited to <max> concurrent (default 1)\n"
115 "\n"
116 "It's important to note that a single FD is used at once and that Accept\n"
117 "replaces the listening FD with the accepted one. Thus always do it after\n"
118 "a fork if other connections have to be accepted.\n"
119 "\n"
120 "After a fork, we loop back to the beginning and silently skip L/C if the\n"
121 "main socket already exists.\n"
122 "\n"
123 "Example dummy HTTP request drain server :\n"
124 " tcploop 8001 L W N20 A R S10 [ F K ]\n"
125 "\n"
126 "Example large bandwidth HTTP request drain server :\n"
127 " tcploop 8001 L W N20 A R S0 [ F K ]\n"
128 "\n"
129 "Example TCP client with pauses at each step :\n"
130 " tcploop 8001 C T W P100 S10 O P100 R S10 O R G K\n"
131 "", arg0);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100132}
133
Willy Tarreau869c7592016-11-12 17:50:57 +0100134void dolog(const char *format, ...)
135{
136 struct timeval date, tv;
137 int delay;
138 va_list args;
139
140 if (!verbose)
141 return;
142
143 if (showtime) {
144 gettimeofday(&date, NULL);
145 switch (showtime) {
146 case 1: // [msec] relative
147 delay = (date.tv_sec - start_time.tv_sec) * 1000000 + date.tv_usec - start_time.tv_usec;
148 fprintf(stderr, "[%d] ", delay / 1000);
149 break;
150 case 2: // [sec.usec] relative
151 tv.tv_usec = date.tv_usec - start_time.tv_usec;
152 tv.tv_sec = date.tv_sec - start_time.tv_sec;
153 if ((signed)tv.tv_sec > 0) {
154 if ((signed)tv.tv_usec < 0) {
155 tv.tv_usec += 1000000;
156 tv.tv_sec--;
157 }
158 } else if (tv.tv_sec == 0) {
159 if ((signed)tv.tv_usec < 0)
160 tv.tv_usec = 0;
161 } else {
162 tv.tv_sec = 0;
163 tv.tv_usec = 0;
164 }
165 fprintf(stderr, "[%d.%06d] ", tv.tv_sec, tv.tv_usec);
166 break;
167 default: // [sec.usec] absolute
168 fprintf(stderr, "[%d.%06d] ", date.tv_sec, date.tv_usec);
169 break;
170 }
171 }
172
173 fprintf(stderr, "%5d ", pid);
174
175 va_start(args, format);
176 vfprintf(stderr, format, args);
177 va_end(args);
178}
179
Willy Tarreau59623e02016-11-12 18:25:45 +0100180/* convert '\n', '\t', '\r', '\\' to their respective characters */
181int unescape(char *out, int size, const char *in)
182{
183 int len;
184
185 for (len = 0; len < size && *in; in++, out++, len++) {
186 if (*in == '\\') {
187 switch (in[1]) {
188 case 'n' : *out = '\n'; in++; continue;
189 case 't' : *out = '\t'; in++; continue;
190 case 'r' : *out = '\r'; in++; continue;
191 case '\\' : *out = '\\'; in++; continue;
192 default : break;
193 }
194 }
195 *out = *in;
196 }
197 return len;
198}
199
Willy Tarreau84393aa2016-11-12 11:29:46 +0100200struct err_msg *alloc_err_msg(int size)
201{
202 struct err_msg *err;
203
204 err = malloc(sizeof(*err) + size);
205 if (err) {
206 err->len = 0;
207 err->size = size;
208 }
209 return err;
210}
211
Willy Tarreau95a6b782016-11-12 13:25:53 +0100212void sig_handler(int sig)
213{
214 if (sig == SIGCHLD) {
215 while (waitpid(-1, NULL, WNOHANG) > 0)
216 __sync_sub_and_fetch(&nbproc, 1);
217 }
218}
Willy Tarreau84393aa2016-11-12 11:29:46 +0100219
220/* converts str in the form [[<ipv4>|<ipv6>|<hostname>]:]port to struct sockaddr_storage.
221 * Returns < 0 with err set in case of error.
222 */
223int addr_to_ss(char *str, struct sockaddr_storage *ss, struct err_msg *err)
224{
225 char *port_str;
226 int port;
227
228 memset(ss, 0, sizeof(*ss));
229
230 /* look for the addr/port delimiter, it's the last colon. If there's no
231 * colon, it's 0:<port>.
232 */
233 if ((port_str = strrchr(str, ':')) == NULL) {
234 port = atoi(str);
235 if (port <= 0 || port > 65535) {
236 err->len = snprintf(err->msg, err->size, "Missing/invalid port number: '%s'\n", str);
237 return -1;
238 }
239
240 ss->ss_family = AF_INET;
241 ((struct sockaddr_in *)ss)->sin_port = htons(port);
242 ((struct sockaddr_in *)ss)->sin_addr.s_addr = INADDR_ANY;
243 return 0;
244 }
245
246 *port_str++ = 0;
247
248 if (strrchr(str, ':') != NULL) {
249 /* IPv6 address contains ':' */
250 ss->ss_family = AF_INET6;
251 ((struct sockaddr_in6 *)ss)->sin6_port = htons(atoi(port_str));
252
253 if (!inet_pton(ss->ss_family, str, &((struct sockaddr_in6 *)ss)->sin6_addr)) {
254 err->len = snprintf(err->msg, err->size, "Invalid server address: '%s'\n", str);
255 return -1;
256 }
257 }
258 else {
259 ss->ss_family = AF_INET;
260 ((struct sockaddr_in *)ss)->sin_port = htons(atoi(port_str));
261
262 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
263 ((struct sockaddr_in *)ss)->sin_addr.s_addr = INADDR_ANY;
264 return 0;
265 }
266
267 if (!inet_pton(ss->ss_family, str, &((struct sockaddr_in *)ss)->sin_addr)) {
268 struct hostent *he = gethostbyname(str);
269
270 if (he == NULL) {
271 err->len = snprintf(err->msg, err->size, "Invalid server name: '%s'\n", str);
272 return -1;
273 }
274 ((struct sockaddr_in *)ss)->sin_addr = *(struct in_addr *) *(he->h_addr_list);
275 }
276 }
277
278 return 0;
279}
280
281/* waits up to one second on fd <fd> for events <events> (POLLIN|POLLOUT).
282 * returns poll's status.
283 */
284int wait_on_fd(int fd, int events)
285{
286 struct pollfd pollfd;
287 int ret;
288
289 do {
290 pollfd.fd = fd;
291 pollfd.events = events;
292 ret = poll(&pollfd, 1, 1000);
293 } while (ret == -1 && errno == EINTR);
294
295 return ret;
296}
297
298int tcp_set_nodelay(int sock, const char *arg)
299{
300 return setsockopt(sock, SOL_TCP, TCP_NODELAY, &one, sizeof(one));
301}
302
303int tcp_set_nolinger(int sock, const char *arg)
304{
305 return setsockopt(sock, SOL_SOCKET, SO_LINGER, (struct linger *) &nolinger, sizeof(struct linger));
306}
307
308int tcp_set_noquickack(int sock, const char *arg)
309{
310 /* warning: do not use during connect if nothing is to be sent! */
311 return setsockopt(sock, SOL_TCP, TCP_QUICKACK, &zero, sizeof(zero));
312}
313
314/* Try to listen to address <sa>. Return the fd or -1 in case of error */
315int tcp_listen(const struct sockaddr_storage *sa, const char *arg)
316{
317 int sock;
318 int backlog;
319
320 if (arg[1])
321 backlog = atoi(arg + 1);
322 else
323 backlog = 1000;
324
325 if (backlog < 0 || backlog > 65535) {
326 fprintf(stderr, "backlog must be between 0 and 65535 inclusive (was %d)\n", backlog);
327 return -1;
328 }
329
330 sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
331 if (sock < 0) {
332 perror("socket()");
333 return -1;
334 }
335
336 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) == -1) {
337 perror("setsockopt(SO_REUSEADDR)");
338 goto fail;
339 }
340
341#ifdef SO_REUSEPORT
342 if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (char *) &one, sizeof(one)) == -1) {
343 perror("setsockopt(SO_REUSEPORT)");
344 goto fail;
345 }
346#endif
347 if (bind(sock, (struct sockaddr *)sa, sa->ss_family == AF_INET6 ?
348 sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) == -1) {
349 perror("bind");
350 goto fail;
351 }
352
353 if (listen(sock, backlog) == -1) {
354 perror("listen");
355 goto fail;
356 }
357
358 return sock;
359 fail:
360 close(sock);
361 return -1;
362}
363
364/* accepts a socket from listening socket <sock>, and returns it (or -1 in case of error) */
365int tcp_accept(int sock, const char *arg)
366{
367 int count;
368 int newsock;
369
370 if (arg[1])
371 count = atoi(arg + 1);
372 else
373 count = 1;
374
375 if (count <= 0) {
376 fprintf(stderr, "accept count must be > 0 or unset (was %d)\n", count);
377 return -1;
378 }
379
380 do {
381 newsock = accept(sock, NULL, NULL);
382 if (newsock < 0) { // TODO: improve error handling
383 if (errno == EINTR || errno == EAGAIN || errno == ECONNABORTED)
384 continue;
385 perror("accept()");
386 break;
387 }
388
389 if (count > 1)
390 close(newsock);
391 count--;
392 } while (count > 0);
393
394 fcntl(newsock, F_SETFL, O_NONBLOCK);
395 return newsock;
396}
397
398/* Try to establish a new connection to <sa>. Return the fd or -1 in case of error */
399int tcp_connect(const struct sockaddr_storage *sa, const char *arg)
400{
401 int sock;
402
403 sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
404 if (sock < 0)
405 return -1;
406
407 if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1)
408 goto fail;
409
410 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) == -1)
411 goto fail;
412
413 if (connect(sock, (const struct sockaddr *)sa, sizeof(*sa)) < 0) {
414 if (errno != EINPROGRESS)
415 goto fail;
416 }
417
418 return sock;
419 fail:
420 close(sock);
421 return -1;
422}
423
Willy Tarreau1973e812016-11-12 18:45:42 +0100424/* receives N bytes from the socket and returns 0 (or -1 in case of a recv
425 * error, or -2 in case of an argument error). When no arg is passed, receives
426 * anything and stops. Otherwise reads the requested amount of data. 0 means
427 * read as much as possible.
Willy Tarreau84393aa2016-11-12 11:29:46 +0100428 */
429int tcp_recv(int sock, const char *arg)
430{
431 int count = -1; // stop at first read
432 int ret;
433
434 if (arg[1]) {
435 count = atoi(arg + 1);
436 if (count < 0) {
437 fprintf(stderr, "recv count must be >= 0 or unset (was %d)\n", count);
Willy Tarreau1973e812016-11-12 18:45:42 +0100438 return -2;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100439 }
440 }
441
442 while (1) {
443 ret = recv(sock, NULL, (count > 0) ? count : INT_MAX, MSG_NOSIGNAL | MSG_TRUNC);
444 if (ret < 0) {
445 if (errno == EINTR)
446 continue;
Willy Tarreau869c7592016-11-12 17:50:57 +0100447 if (errno != EAGAIN) {
448 dolog("recv %d\n", ret);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100449 return -1;
Willy Tarreau869c7592016-11-12 17:50:57 +0100450 }
Willy Tarreau84393aa2016-11-12 11:29:46 +0100451 while (!wait_on_fd(sock, POLLIN));
452 continue;
453 }
Willy Tarreau869c7592016-11-12 17:50:57 +0100454 dolog("recv %d\n", ret);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100455 if (!ret)
456 break;
457
458 if (!count)
459 continue;
460 else if (count > 0)
461 count -= ret;
462
463 if (count <= 0)
464 break;
465 }
466
467 return 0;
468}
469
Willy Tarreau1973e812016-11-12 18:45:42 +0100470/* Sends N bytes to the socket and returns 0 (or -1 in case of send error, -2
471 * in case of an argument error. If the byte count is not set, sends only one
472 * block. Sending zero means try to send forever. If the argument starts with
473 * ':' then whatever follows is interpreted as the payload to be sent as-is.
474 * Escaped characters '\r', '\n', '\t' and '\\' are detected and converted. In
Willy Tarreau59623e02016-11-12 18:25:45 +0100475 * this case, blocks must be small so that send() doesn't fragment them, as
476 * they will be put into the trash and expected to be sent at once.
Willy Tarreau84393aa2016-11-12 11:29:46 +0100477 */
478int tcp_send(int sock, const char *arg)
479{
480 int count = -1; // stop after first block
481 int ret;
482
Willy Tarreau59623e02016-11-12 18:25:45 +0100483 if (arg[1] == ':') {
484 count = unescape(trash, sizeof(trash), arg + 2);
485 } else if (arg[1]) {
Willy Tarreau84393aa2016-11-12 11:29:46 +0100486 count = atoi(arg + 1);
Willy Tarreau869c7592016-11-12 17:50:57 +0100487 if (count < 0) {
Willy Tarreau84393aa2016-11-12 11:29:46 +0100488 fprintf(stderr, "send count must be >= 0 or unset (was %d)\n", count);
Willy Tarreau1973e812016-11-12 18:45:42 +0100489 return -2;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100490 }
491 }
492
493 while (1) {
494 ret = send(sock, trash,
495 (count > 0) && (count < sizeof(trash)) ? count : sizeof(trash),
496 MSG_NOSIGNAL | ((count > sizeof(trash)) ? MSG_MORE : 0));
497 if (ret < 0) {
498 if (errno == EINTR)
499 continue;
Willy Tarreau869c7592016-11-12 17:50:57 +0100500 if (errno != EAGAIN) {
501 dolog("send %d\n", ret);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100502 return -1;
Willy Tarreau869c7592016-11-12 17:50:57 +0100503 }
Willy Tarreau84393aa2016-11-12 11:29:46 +0100504 while (!wait_on_fd(sock, POLLOUT));
505 continue;
506 }
Willy Tarreau869c7592016-11-12 17:50:57 +0100507 dolog("send %d\n", ret);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100508 if (!count)
509 continue;
510 else if (count > 0)
511 count -= ret;
512
513 if (count <= 0)
514 break;
515 }
516
517 return 0;
518}
519
520/* echoes N bytes to the socket and returns 0 (or -1 in case of error). If not
521 * set, echoes only the first block. Zero means forward forever.
522 */
523int tcp_echo(int sock, const char *arg)
524{
525 int count = -1; // echo forever
526 int ret;
527 int rcvd;
528
529 if (arg[1]) {
530 count = atoi(arg + 1);
531 if (count < 0) {
532 fprintf(stderr, "send count must be >= 0 or unset (was %d)\n", count);
533 return -1;
534 }
535 }
536
537 rcvd = 0;
538 while (1) {
539 if (rcvd <= 0) {
540 /* no data pending */
541 rcvd = recv(sock, trash, (count > 0) && (count < sizeof(trash)) ? count : sizeof(trash), MSG_NOSIGNAL);
542 if (rcvd < 0) {
543 if (errno == EINTR)
544 continue;
Willy Tarreau869c7592016-11-12 17:50:57 +0100545 if (errno != EAGAIN) {
546 dolog("recv %d\n", rcvd);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100547 return -1;
Willy Tarreau869c7592016-11-12 17:50:57 +0100548 }
Willy Tarreau84393aa2016-11-12 11:29:46 +0100549 while (!wait_on_fd(sock, POLLIN));
550 continue;
551 }
Willy Tarreau869c7592016-11-12 17:50:57 +0100552 dolog("recv %d\n", rcvd);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100553 if (!rcvd)
554 break;
555 }
556 else {
557 /* some data still pending */
558 ret = send(sock, trash, rcvd, MSG_NOSIGNAL | ((count > rcvd) ? MSG_MORE : 0));
559 if (ret < 0) {
560 if (errno == EINTR)
561 continue;
Willy Tarreau869c7592016-11-12 17:50:57 +0100562 if (errno != EAGAIN) {
563 dolog("send %d\n", ret);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100564 return -1;
Willy Tarreau869c7592016-11-12 17:50:57 +0100565 }
Willy Tarreau84393aa2016-11-12 11:29:46 +0100566 while (!wait_on_fd(sock, POLLOUT));
567 continue;
568 }
Willy Tarreau869c7592016-11-12 17:50:57 +0100569 dolog("send %d\n", ret);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100570 rcvd -= ret;
571 if (rcvd)
572 continue;
573
574 if (!count)
575 continue;
576 else if (count > 0)
577 count -= ret;
578
579 if (count <= 0)
580 break;
581 }
582 }
583 return 0;
584}
585
586/* waits for an event on the socket, usually indicates an accept for a
587 * listening socket and a connect for an outgoing socket.
588 */
589int tcp_wait(int sock, const char *arg)
590{
591 struct pollfd pollfd;
592 int delay = -1; // wait forever
593 int ret;
594
595 if (arg[1]) {
596 delay = atoi(arg + 1);
597 if (delay < 0) {
598 fprintf(stderr, "wait time must be >= 0 or unset (was %d)\n", delay);
599 return -1;
600 }
601 }
602
603 /* FIXME: this doesn't take into account delivered signals */
604 do {
605 pollfd.fd = sock;
606 pollfd.events = POLLIN | POLLOUT;
607 ret = poll(&pollfd, 1, delay);
608 } while (ret == -1 && errno == EINTR);
609
Willy Tarreau869c7592016-11-12 17:50:57 +0100610 if (ret > 0 && pollfd.revents & POLLERR)
611 return -1;
612
Willy Tarreau84393aa2016-11-12 11:29:46 +0100613 return 0;
614}
615
616/* waits for the input data to be present */
617int tcp_wait_in(int sock, const char *arg)
618{
619 struct pollfd pollfd;
620 int ret;
621
622 do {
623 pollfd.fd = sock;
624 pollfd.events = POLLIN;
625 ret = poll(&pollfd, 1, 1000);
626 } while (ret == -1 && errno == EINTR);
Willy Tarreau869c7592016-11-12 17:50:57 +0100627
628 if (ret > 0 && pollfd.revents & POLLERR)
629 return -1;
630
Willy Tarreau84393aa2016-11-12 11:29:46 +0100631 return 0;
632}
633
634/* waits for the output queue to be empty */
635int tcp_wait_out(int sock, const char *arg)
636{
637 struct pollfd pollfd;
638 int ret;
639
640 do {
641 pollfd.fd = sock;
642 pollfd.events = POLLOUT;
643 ret = poll(&pollfd, 1, 1000);
644 } while (ret == -1 && errno == EINTR);
645
Willy Tarreau869c7592016-11-12 17:50:57 +0100646 if (ret > 0 && pollfd.revents & POLLERR)
647 return -1;
648
Willy Tarreau84393aa2016-11-12 11:29:46 +0100649 /* Now wait for data to leave the socket */
650 do {
651 if (ioctl(sock, TIOCOUTQ, &ret) < 0)
652 return -1;
653 } while (ret > 0);
654 return 0;
655}
656
657/* delays processing for <time> milliseconds, 100 by default */
658int tcp_pause(int sock, const char *arg)
659{
660 struct pollfd pollfd;
661 int delay = 100;
662 int ret;
663
664 if (arg[1]) {
665 delay = atoi(arg + 1);
666 if (delay < 0) {
667 fprintf(stderr, "wait time must be >= 0 or unset (was %d)\n", delay);
668 return -1;
669 }
670 }
671
672 usleep(delay * 1000);
673 return 0;
674}
675
Willy Tarreau95a6b782016-11-12 13:25:53 +0100676/* forks another process while respecting the limit imposed in argument (1 by
677 * default). Will wait for another process to exit before creating a new one.
678 * Returns the value of the fork() syscall, ie 0 for the child, non-zero for
679 * the parent, -1 for an error.
680 */
681int tcp_fork(int sock, const char *arg)
682{
683 int max = 1;
684 int ret;
685
686 if (arg[1]) {
687 max = atoi(arg + 1);
688 if (max <= 0) {
689 fprintf(stderr, "max process must be > 0 or unset (was %d)\n", max);
690 return -1;
691 }
692 }
693
694 while (nbproc >= max)
695 poll(NULL, 0, 1000);
696
697 ret = fork();
698 if (ret > 0)
699 __sync_add_and_fetch(&nbproc, 1);
700 return ret;
701}
702
Willy Tarreau84393aa2016-11-12 11:29:46 +0100703int main(int argc, char **argv)
704{
705 struct sockaddr_storage ss;
706 struct err_msg err;
707 const char *arg0;
708 int arg;
Willy Tarreau95a6b782016-11-12 13:25:53 +0100709 int ret;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100710 int sock;
711
712 arg0 = argv[0];
Willy Tarreau869c7592016-11-12 17:50:57 +0100713
714 while (argc > 1 && argv[1][0] == '-') {
715 argc--; argv++;
716 if (strcmp(argv[0], "-t") == 0)
717 showtime++;
718 else if (strcmp(argv[0], "-tt") == 0)
719 showtime += 2;
720 else if (strcmp(argv[0], "-ttt") == 0)
721 showtime += 3;
722 else if (strcmp(argv[0], "-v") == 0)
723 verbose ++;
724 else if (strcmp(argv[0], "--") == 0)
725 break;
726 else
727 usage(1, arg0);
728 }
729
Willy Tarreau84393aa2016-11-12 11:29:46 +0100730 if (argc < 2)
731 usage(1, arg0);
732
Willy Tarreau869c7592016-11-12 17:50:57 +0100733 pid = getpid();
Willy Tarreau95a6b782016-11-12 13:25:53 +0100734 signal(SIGCHLD, sig_handler);
735
Willy Tarreau84393aa2016-11-12 11:29:46 +0100736 if (addr_to_ss(argv[1], &ss, &err) < 0)
737 die(1, "%s\n", err.msg);
738
Willy Tarreau869c7592016-11-12 17:50:57 +0100739 gettimeofday(&start_time, NULL);
740
Willy Tarreau84393aa2016-11-12 11:29:46 +0100741 sock = -1;
742 for (arg = 2; arg < argc; arg++) {
743 switch (argv[arg][0]) {
744 case 'L':
745 /* silently ignore existing connections */
746 if (sock == -1)
747 sock = tcp_listen(&ss, argv[arg]);
748 if (sock < 0)
749 die(1, "Fatal: tcp_listen() failed.\n");
750 break;
751
752 case 'C':
753 /* silently ignore existing connections */
754 if (sock == -1)
755 sock = tcp_connect(&ss, argv[arg]);
756 if (sock < 0)
757 die(1, "Fatal: tcp_connect() failed.\n");
Willy Tarreau869c7592016-11-12 17:50:57 +0100758 dolog("connect\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100759 break;
760
761 case 'A':
762 if (sock < 0)
763 die(1, "Fatal: tcp_accept() on non-socket.\n");
764 sock = tcp_accept(sock, argv[arg]);
765 if (sock < 0)
766 die(1, "Fatal: tcp_accept() failed.\n");
Willy Tarreau869c7592016-11-12 17:50:57 +0100767 dolog("accept\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100768 break;
769
770 case 'T':
771 if (sock < 0)
772 die(1, "Fatal: tcp_set_nodelay() on non-socket.\n");
773 if (tcp_set_nodelay(sock, argv[arg]) < 0)
774 die(1, "Fatal: tcp_set_nodelay() failed.\n");
775 break;
776
777 case 'G':
778 if (sock < 0)
779 die(1, "Fatal: tcp_set_nolinger() on non-socket.\n");
780 if (tcp_set_nolinger(sock, argv[arg]) < 0)
781 die(1, "Fatal: tcp_set_nolinger() failed.\n");
782 break;
783
784 case 'Q':
785 if (sock < 0)
786 die(1, "Fatal: tcp_set_noquickack() on non-socket.\n");
787 if (tcp_set_noquickack(sock, argv[arg]) < 0)
788 die(1, "Fatal: tcp_set_noquickack() failed.\n");
789 break;
790
791 case 'R':
792 if (sock < 0)
793 die(1, "Fatal: tcp_recv() on non-socket.\n");
Willy Tarreau1973e812016-11-12 18:45:42 +0100794 ret = tcp_recv(sock, argv[arg]);
795 if (ret < 0) {
796 if (ret == -1) // usually ECONNRESET, silently exit
797 die(0, NULL);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100798 die(1, "Fatal: tcp_recv() failed.\n");
Willy Tarreau1973e812016-11-12 18:45:42 +0100799 }
Willy Tarreau84393aa2016-11-12 11:29:46 +0100800 break;
801
802 case 'S':
803 if (sock < 0)
804 die(1, "Fatal: tcp_send() on non-socket.\n");
Willy Tarreau1973e812016-11-12 18:45:42 +0100805 ret = tcp_send(sock, argv[arg]);
806 if (ret < 0) {
807 if (ret == -1) // usually a broken pipe, silently exit
808 die(0, NULL);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100809 die(1, "Fatal: tcp_send() failed.\n");
Willy Tarreau1973e812016-11-12 18:45:42 +0100810 }
Willy Tarreau84393aa2016-11-12 11:29:46 +0100811 break;
812
813 case 'E':
814 if (sock < 0)
815 die(1, "Fatal: tcp_echo() on non-socket.\n");
816 if (tcp_echo(sock, argv[arg]) < 0)
817 die(1, "Fatal: tcp_echo() failed.\n");
818 break;
819
820 case 'P':
821 if (tcp_pause(sock, argv[arg]) < 0)
822 die(1, "Fatal: tcp_pause() failed.\n");
823 break;
824
825 case 'W':
826 if (sock < 0)
827 die(1, "Fatal: tcp_wait() on non-socket.\n");
828 if (tcp_wait(sock, argv[arg]) < 0)
829 die(1, "Fatal: tcp_wait() failed.\n");
Willy Tarreau869c7592016-11-12 17:50:57 +0100830 dolog("ready_any\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100831 break;
832
833 case 'I':
834 if (sock < 0)
835 die(1, "Fatal: tcp_wait_in() on non-socket.\n");
836 if (tcp_wait_in(sock, argv[arg]) < 0)
837 die(1, "Fatal: tcp_wait_in() failed.\n");
Willy Tarreau869c7592016-11-12 17:50:57 +0100838 dolog("ready_in\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100839 break;
840
841 case 'O':
842 if (sock < 0)
843 die(1, "Fatal: tcp_wait_out() on non-socket.\n");
844 if (tcp_wait_out(sock, argv[arg]) < 0)
845 die(1, "Fatal: tcp_wait_out() failed.\n");
Willy Tarreau869c7592016-11-12 17:50:57 +0100846 dolog("ready_out\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100847 break;
848
849 case 'K':
850 if (sock < 0 || close(sock) < 0)
851 die(1, "Fatal: close() on non-socket.\n");
Willy Tarreau869c7592016-11-12 17:50:57 +0100852 dolog("close\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100853 sock = -1;
854 break;
855
856 case 'F':
857 /* ignore errors on shutdown() as they are common */
858 if (sock >= 0)
859 shutdown(sock, SHUT_WR);
Willy Tarreau869c7592016-11-12 17:50:57 +0100860 dolog("shutdown\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100861 break;
862
Willy Tarreau95a6b782016-11-12 13:25:53 +0100863 case 'N':
864 ret = tcp_fork(sock, argv[arg]);
865 if (ret < 0)
866 die(1, "Fatal: fork() failed.\n");
867 if (ret > 0) {
868 /* loop back to first arg */
869 arg = 1;
870 continue;
871 }
872 /* OK we're in the child, let's continue */
Willy Tarreau869c7592016-11-12 17:50:57 +0100873 pid = getpid();
Willy Tarreau95a6b782016-11-12 13:25:53 +0100874 break;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100875 default:
876 usage(1, arg0);
877 }
878 }
879 return 0;
880}