blob: ceb6f5ccd3d9c668366f90ff3dfff19d18dd86d5 [file] [log] [blame]
Willy Tarreau84393aa2016-11-12 11:29:46 +01001#include <sys/resource.h>
2#include <sys/select.h>
3#include <sys/types.h>
4#include <sys/socket.h>
5#include <sys/stat.h>
6#include <sys/time.h>
7#include <sys/ioctl.h>
Willy Tarreau95a6b782016-11-12 13:25:53 +01008#include <sys/wait.h>
Willy Tarreau84393aa2016-11-12 11:29:46 +01009#include <arpa/inet.h>
10#include <netinet/in.h>
11#include <netinet/tcp.h>
12
13#include <ctype.h>
14#include <errno.h>
15#include <fcntl.h>
16#include <netdb.h>
17#include <poll.h>
18#include <signal.h>
19#include <stdarg.h>
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23#include <time.h>
24#include <unistd.h>
25
26
27struct err_msg {
28 int size;
29 int len;
30 char msg[0];
31};
32
33const int zero = 0;
34const int one = 1;
35const struct linger nolinger = { .l_onoff = 1, .l_linger = 0 };
36
37#define TRASH_SIZE 65536
38static char trash[TRASH_SIZE];
39
Willy Tarreau95a6b782016-11-12 13:25:53 +010040volatile int nbproc = 0;
Willy Tarreau869c7592016-11-12 17:50:57 +010041static struct timeval start_time;
42static int showtime;
43static int verbose;
44static int pid;
45
Willy Tarreau95a6b782016-11-12 13:25:53 +010046
Willy Tarreau84393aa2016-11-12 11:29:46 +010047/* display the message and exit with the code */
48__attribute__((noreturn)) void die(int code, const char *format, ...)
49{
50 va_list args;
51
52 va_start(args, format);
53 vfprintf(stderr, format, args);
54 va_end(args);
55 exit(code);
56}
57
58/* display the usage message and exit with the code */
59__attribute__((noreturn)) void usage(int code, const char *arg0)
60{
61 die(code, "Usage: %s [<ip>:]port [action*]\n", arg0);
62}
63
Willy Tarreau869c7592016-11-12 17:50:57 +010064void dolog(const char *format, ...)
65{
66 struct timeval date, tv;
67 int delay;
68 va_list args;
69
70 if (!verbose)
71 return;
72
73 if (showtime) {
74 gettimeofday(&date, NULL);
75 switch (showtime) {
76 case 1: // [msec] relative
77 delay = (date.tv_sec - start_time.tv_sec) * 1000000 + date.tv_usec - start_time.tv_usec;
78 fprintf(stderr, "[%d] ", delay / 1000);
79 break;
80 case 2: // [sec.usec] relative
81 tv.tv_usec = date.tv_usec - start_time.tv_usec;
82 tv.tv_sec = date.tv_sec - start_time.tv_sec;
83 if ((signed)tv.tv_sec > 0) {
84 if ((signed)tv.tv_usec < 0) {
85 tv.tv_usec += 1000000;
86 tv.tv_sec--;
87 }
88 } else if (tv.tv_sec == 0) {
89 if ((signed)tv.tv_usec < 0)
90 tv.tv_usec = 0;
91 } else {
92 tv.tv_sec = 0;
93 tv.tv_usec = 0;
94 }
95 fprintf(stderr, "[%d.%06d] ", tv.tv_sec, tv.tv_usec);
96 break;
97 default: // [sec.usec] absolute
98 fprintf(stderr, "[%d.%06d] ", date.tv_sec, date.tv_usec);
99 break;
100 }
101 }
102
103 fprintf(stderr, "%5d ", pid);
104
105 va_start(args, format);
106 vfprintf(stderr, format, args);
107 va_end(args);
108}
109
Willy Tarreau84393aa2016-11-12 11:29:46 +0100110struct err_msg *alloc_err_msg(int size)
111{
112 struct err_msg *err;
113
114 err = malloc(sizeof(*err) + size);
115 if (err) {
116 err->len = 0;
117 err->size = size;
118 }
119 return err;
120}
121
Willy Tarreau95a6b782016-11-12 13:25:53 +0100122void sig_handler(int sig)
123{
124 if (sig == SIGCHLD) {
125 while (waitpid(-1, NULL, WNOHANG) > 0)
126 __sync_sub_and_fetch(&nbproc, 1);
127 }
128}
Willy Tarreau84393aa2016-11-12 11:29:46 +0100129
130/* converts str in the form [[<ipv4>|<ipv6>|<hostname>]:]port to struct sockaddr_storage.
131 * Returns < 0 with err set in case of error.
132 */
133int addr_to_ss(char *str, struct sockaddr_storage *ss, struct err_msg *err)
134{
135 char *port_str;
136 int port;
137
138 memset(ss, 0, sizeof(*ss));
139
140 /* look for the addr/port delimiter, it's the last colon. If there's no
141 * colon, it's 0:<port>.
142 */
143 if ((port_str = strrchr(str, ':')) == NULL) {
144 port = atoi(str);
145 if (port <= 0 || port > 65535) {
146 err->len = snprintf(err->msg, err->size, "Missing/invalid port number: '%s'\n", str);
147 return -1;
148 }
149
150 ss->ss_family = AF_INET;
151 ((struct sockaddr_in *)ss)->sin_port = htons(port);
152 ((struct sockaddr_in *)ss)->sin_addr.s_addr = INADDR_ANY;
153 return 0;
154 }
155
156 *port_str++ = 0;
157
158 if (strrchr(str, ':') != NULL) {
159 /* IPv6 address contains ':' */
160 ss->ss_family = AF_INET6;
161 ((struct sockaddr_in6 *)ss)->sin6_port = htons(atoi(port_str));
162
163 if (!inet_pton(ss->ss_family, str, &((struct sockaddr_in6 *)ss)->sin6_addr)) {
164 err->len = snprintf(err->msg, err->size, "Invalid server address: '%s'\n", str);
165 return -1;
166 }
167 }
168 else {
169 ss->ss_family = AF_INET;
170 ((struct sockaddr_in *)ss)->sin_port = htons(atoi(port_str));
171
172 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
173 ((struct sockaddr_in *)ss)->sin_addr.s_addr = INADDR_ANY;
174 return 0;
175 }
176
177 if (!inet_pton(ss->ss_family, str, &((struct sockaddr_in *)ss)->sin_addr)) {
178 struct hostent *he = gethostbyname(str);
179
180 if (he == NULL) {
181 err->len = snprintf(err->msg, err->size, "Invalid server name: '%s'\n", str);
182 return -1;
183 }
184 ((struct sockaddr_in *)ss)->sin_addr = *(struct in_addr *) *(he->h_addr_list);
185 }
186 }
187
188 return 0;
189}
190
191/* waits up to one second on fd <fd> for events <events> (POLLIN|POLLOUT).
192 * returns poll's status.
193 */
194int wait_on_fd(int fd, int events)
195{
196 struct pollfd pollfd;
197 int ret;
198
199 do {
200 pollfd.fd = fd;
201 pollfd.events = events;
202 ret = poll(&pollfd, 1, 1000);
203 } while (ret == -1 && errno == EINTR);
204
205 return ret;
206}
207
208int tcp_set_nodelay(int sock, const char *arg)
209{
210 return setsockopt(sock, SOL_TCP, TCP_NODELAY, &one, sizeof(one));
211}
212
213int tcp_set_nolinger(int sock, const char *arg)
214{
215 return setsockopt(sock, SOL_SOCKET, SO_LINGER, (struct linger *) &nolinger, sizeof(struct linger));
216}
217
218int tcp_set_noquickack(int sock, const char *arg)
219{
220 /* warning: do not use during connect if nothing is to be sent! */
221 return setsockopt(sock, SOL_TCP, TCP_QUICKACK, &zero, sizeof(zero));
222}
223
224/* Try to listen to address <sa>. Return the fd or -1 in case of error */
225int tcp_listen(const struct sockaddr_storage *sa, const char *arg)
226{
227 int sock;
228 int backlog;
229
230 if (arg[1])
231 backlog = atoi(arg + 1);
232 else
233 backlog = 1000;
234
235 if (backlog < 0 || backlog > 65535) {
236 fprintf(stderr, "backlog must be between 0 and 65535 inclusive (was %d)\n", backlog);
237 return -1;
238 }
239
240 sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
241 if (sock < 0) {
242 perror("socket()");
243 return -1;
244 }
245
246 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) == -1) {
247 perror("setsockopt(SO_REUSEADDR)");
248 goto fail;
249 }
250
251#ifdef SO_REUSEPORT
252 if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (char *) &one, sizeof(one)) == -1) {
253 perror("setsockopt(SO_REUSEPORT)");
254 goto fail;
255 }
256#endif
257 if (bind(sock, (struct sockaddr *)sa, sa->ss_family == AF_INET6 ?
258 sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) == -1) {
259 perror("bind");
260 goto fail;
261 }
262
263 if (listen(sock, backlog) == -1) {
264 perror("listen");
265 goto fail;
266 }
267
268 return sock;
269 fail:
270 close(sock);
271 return -1;
272}
273
274/* accepts a socket from listening socket <sock>, and returns it (or -1 in case of error) */
275int tcp_accept(int sock, const char *arg)
276{
277 int count;
278 int newsock;
279
280 if (arg[1])
281 count = atoi(arg + 1);
282 else
283 count = 1;
284
285 if (count <= 0) {
286 fprintf(stderr, "accept count must be > 0 or unset (was %d)\n", count);
287 return -1;
288 }
289
290 do {
291 newsock = accept(sock, NULL, NULL);
292 if (newsock < 0) { // TODO: improve error handling
293 if (errno == EINTR || errno == EAGAIN || errno == ECONNABORTED)
294 continue;
295 perror("accept()");
296 break;
297 }
298
299 if (count > 1)
300 close(newsock);
301 count--;
302 } while (count > 0);
303
304 fcntl(newsock, F_SETFL, O_NONBLOCK);
305 return newsock;
306}
307
308/* Try to establish a new connection to <sa>. Return the fd or -1 in case of error */
309int tcp_connect(const struct sockaddr_storage *sa, const char *arg)
310{
311 int sock;
312
313 sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
314 if (sock < 0)
315 return -1;
316
317 if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1)
318 goto fail;
319
320 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) == -1)
321 goto fail;
322
323 if (connect(sock, (const struct sockaddr *)sa, sizeof(*sa)) < 0) {
324 if (errno != EINPROGRESS)
325 goto fail;
326 }
327
328 return sock;
329 fail:
330 close(sock);
331 return -1;
332}
333
334/* receives N bytes from the socket and returns 0 (or -1 in case of error).
335 * When no arg is passed, receives anything and stops. Otherwise reads the
336 * requested amount of data. 0 means read as much as possible.
337 */
338int tcp_recv(int sock, const char *arg)
339{
340 int count = -1; // stop at first read
341 int ret;
342
343 if (arg[1]) {
344 count = atoi(arg + 1);
345 if (count < 0) {
346 fprintf(stderr, "recv count must be >= 0 or unset (was %d)\n", count);
347 return -1;
348 }
349 }
350
351 while (1) {
352 ret = recv(sock, NULL, (count > 0) ? count : INT_MAX, MSG_NOSIGNAL | MSG_TRUNC);
353 if (ret < 0) {
354 if (errno == EINTR)
355 continue;
Willy Tarreau869c7592016-11-12 17:50:57 +0100356 if (errno != EAGAIN) {
357 dolog("recv %d\n", ret);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100358 return -1;
Willy Tarreau869c7592016-11-12 17:50:57 +0100359 }
Willy Tarreau84393aa2016-11-12 11:29:46 +0100360 while (!wait_on_fd(sock, POLLIN));
361 continue;
362 }
Willy Tarreau869c7592016-11-12 17:50:57 +0100363 dolog("recv %d\n", ret);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100364 if (!ret)
365 break;
366
367 if (!count)
368 continue;
369 else if (count > 0)
370 count -= ret;
371
372 if (count <= 0)
373 break;
374 }
375
376 return 0;
377}
378
379/* sends N bytes to the socket and returns 0 (or -1 in case of error). If not
380 * set, sends only one block. Sending zero means try to send forever.
381 */
382int tcp_send(int sock, const char *arg)
383{
384 int count = -1; // stop after first block
385 int ret;
386
387 if (arg[1]) {
388 count = atoi(arg + 1);
Willy Tarreau869c7592016-11-12 17:50:57 +0100389 if (count < 0) {
Willy Tarreau84393aa2016-11-12 11:29:46 +0100390 fprintf(stderr, "send count must be >= 0 or unset (was %d)\n", count);
391 return -1;
392 }
393 }
394
395 while (1) {
396 ret = send(sock, trash,
397 (count > 0) && (count < sizeof(trash)) ? count : sizeof(trash),
398 MSG_NOSIGNAL | ((count > sizeof(trash)) ? MSG_MORE : 0));
399 if (ret < 0) {
400 if (errno == EINTR)
401 continue;
Willy Tarreau869c7592016-11-12 17:50:57 +0100402 if (errno != EAGAIN) {
403 dolog("send %d\n", ret);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100404 return -1;
Willy Tarreau869c7592016-11-12 17:50:57 +0100405 }
Willy Tarreau84393aa2016-11-12 11:29:46 +0100406 while (!wait_on_fd(sock, POLLOUT));
407 continue;
408 }
Willy Tarreau869c7592016-11-12 17:50:57 +0100409 dolog("send %d\n", ret);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100410 if (!count)
411 continue;
412 else if (count > 0)
413 count -= ret;
414
415 if (count <= 0)
416 break;
417 }
418
419 return 0;
420}
421
422/* echoes N bytes to the socket and returns 0 (or -1 in case of error). If not
423 * set, echoes only the first block. Zero means forward forever.
424 */
425int tcp_echo(int sock, const char *arg)
426{
427 int count = -1; // echo forever
428 int ret;
429 int rcvd;
430
431 if (arg[1]) {
432 count = atoi(arg + 1);
433 if (count < 0) {
434 fprintf(stderr, "send count must be >= 0 or unset (was %d)\n", count);
435 return -1;
436 }
437 }
438
439 rcvd = 0;
440 while (1) {
441 if (rcvd <= 0) {
442 /* no data pending */
443 rcvd = recv(sock, trash, (count > 0) && (count < sizeof(trash)) ? count : sizeof(trash), MSG_NOSIGNAL);
444 if (rcvd < 0) {
445 if (errno == EINTR)
446 continue;
Willy Tarreau869c7592016-11-12 17:50:57 +0100447 if (errno != EAGAIN) {
448 dolog("recv %d\n", rcvd);
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", rcvd);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100455 if (!rcvd)
456 break;
457 }
458 else {
459 /* some data still pending */
460 ret = send(sock, trash, rcvd, MSG_NOSIGNAL | ((count > rcvd) ? MSG_MORE : 0));
461 if (ret < 0) {
462 if (errno == EINTR)
463 continue;
Willy Tarreau869c7592016-11-12 17:50:57 +0100464 if (errno != EAGAIN) {
465 dolog("send %d\n", ret);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100466 return -1;
Willy Tarreau869c7592016-11-12 17:50:57 +0100467 }
Willy Tarreau84393aa2016-11-12 11:29:46 +0100468 while (!wait_on_fd(sock, POLLOUT));
469 continue;
470 }
Willy Tarreau869c7592016-11-12 17:50:57 +0100471 dolog("send %d\n", ret);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100472 rcvd -= ret;
473 if (rcvd)
474 continue;
475
476 if (!count)
477 continue;
478 else if (count > 0)
479 count -= ret;
480
481 if (count <= 0)
482 break;
483 }
484 }
485 return 0;
486}
487
488/* waits for an event on the socket, usually indicates an accept for a
489 * listening socket and a connect for an outgoing socket.
490 */
491int tcp_wait(int sock, const char *arg)
492{
493 struct pollfd pollfd;
494 int delay = -1; // wait forever
495 int ret;
496
497 if (arg[1]) {
498 delay = atoi(arg + 1);
499 if (delay < 0) {
500 fprintf(stderr, "wait time must be >= 0 or unset (was %d)\n", delay);
501 return -1;
502 }
503 }
504
505 /* FIXME: this doesn't take into account delivered signals */
506 do {
507 pollfd.fd = sock;
508 pollfd.events = POLLIN | POLLOUT;
509 ret = poll(&pollfd, 1, delay);
510 } while (ret == -1 && errno == EINTR);
511
Willy Tarreau869c7592016-11-12 17:50:57 +0100512 if (ret > 0 && pollfd.revents & POLLERR)
513 return -1;
514
Willy Tarreau84393aa2016-11-12 11:29:46 +0100515 return 0;
516}
517
518/* waits for the input data to be present */
519int tcp_wait_in(int sock, const char *arg)
520{
521 struct pollfd pollfd;
522 int ret;
523
524 do {
525 pollfd.fd = sock;
526 pollfd.events = POLLIN;
527 ret = poll(&pollfd, 1, 1000);
528 } while (ret == -1 && errno == EINTR);
Willy Tarreau869c7592016-11-12 17:50:57 +0100529
530 if (ret > 0 && pollfd.revents & POLLERR)
531 return -1;
532
Willy Tarreau84393aa2016-11-12 11:29:46 +0100533 return 0;
534}
535
536/* waits for the output queue to be empty */
537int tcp_wait_out(int sock, const char *arg)
538{
539 struct pollfd pollfd;
540 int ret;
541
542 do {
543 pollfd.fd = sock;
544 pollfd.events = POLLOUT;
545 ret = poll(&pollfd, 1, 1000);
546 } while (ret == -1 && errno == EINTR);
547
Willy Tarreau869c7592016-11-12 17:50:57 +0100548 if (ret > 0 && pollfd.revents & POLLERR)
549 return -1;
550
Willy Tarreau84393aa2016-11-12 11:29:46 +0100551 /* Now wait for data to leave the socket */
552 do {
553 if (ioctl(sock, TIOCOUTQ, &ret) < 0)
554 return -1;
555 } while (ret > 0);
556 return 0;
557}
558
559/* delays processing for <time> milliseconds, 100 by default */
560int tcp_pause(int sock, const char *arg)
561{
562 struct pollfd pollfd;
563 int delay = 100;
564 int ret;
565
566 if (arg[1]) {
567 delay = atoi(arg + 1);
568 if (delay < 0) {
569 fprintf(stderr, "wait time must be >= 0 or unset (was %d)\n", delay);
570 return -1;
571 }
572 }
573
574 usleep(delay * 1000);
575 return 0;
576}
577
Willy Tarreau95a6b782016-11-12 13:25:53 +0100578/* forks another process while respecting the limit imposed in argument (1 by
579 * default). Will wait for another process to exit before creating a new one.
580 * Returns the value of the fork() syscall, ie 0 for the child, non-zero for
581 * the parent, -1 for an error.
582 */
583int tcp_fork(int sock, const char *arg)
584{
585 int max = 1;
586 int ret;
587
588 if (arg[1]) {
589 max = atoi(arg + 1);
590 if (max <= 0) {
591 fprintf(stderr, "max process must be > 0 or unset (was %d)\n", max);
592 return -1;
593 }
594 }
595
596 while (nbproc >= max)
597 poll(NULL, 0, 1000);
598
599 ret = fork();
600 if (ret > 0)
601 __sync_add_and_fetch(&nbproc, 1);
602 return ret;
603}
604
Willy Tarreau84393aa2016-11-12 11:29:46 +0100605int main(int argc, char **argv)
606{
607 struct sockaddr_storage ss;
608 struct err_msg err;
609 const char *arg0;
610 int arg;
Willy Tarreau95a6b782016-11-12 13:25:53 +0100611 int ret;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100612 int sock;
613
614 arg0 = argv[0];
Willy Tarreau869c7592016-11-12 17:50:57 +0100615
616 while (argc > 1 && argv[1][0] == '-') {
617 argc--; argv++;
618 if (strcmp(argv[0], "-t") == 0)
619 showtime++;
620 else if (strcmp(argv[0], "-tt") == 0)
621 showtime += 2;
622 else if (strcmp(argv[0], "-ttt") == 0)
623 showtime += 3;
624 else if (strcmp(argv[0], "-v") == 0)
625 verbose ++;
626 else if (strcmp(argv[0], "--") == 0)
627 break;
628 else
629 usage(1, arg0);
630 }
631
Willy Tarreau84393aa2016-11-12 11:29:46 +0100632 if (argc < 2)
633 usage(1, arg0);
634
Willy Tarreau869c7592016-11-12 17:50:57 +0100635 pid = getpid();
Willy Tarreau95a6b782016-11-12 13:25:53 +0100636 signal(SIGCHLD, sig_handler);
637
Willy Tarreau84393aa2016-11-12 11:29:46 +0100638 if (addr_to_ss(argv[1], &ss, &err) < 0)
639 die(1, "%s\n", err.msg);
640
Willy Tarreau869c7592016-11-12 17:50:57 +0100641 gettimeofday(&start_time, NULL);
642
Willy Tarreau84393aa2016-11-12 11:29:46 +0100643 sock = -1;
644 for (arg = 2; arg < argc; arg++) {
645 switch (argv[arg][0]) {
646 case 'L':
647 /* silently ignore existing connections */
648 if (sock == -1)
649 sock = tcp_listen(&ss, argv[arg]);
650 if (sock < 0)
651 die(1, "Fatal: tcp_listen() failed.\n");
652 break;
653
654 case 'C':
655 /* silently ignore existing connections */
656 if (sock == -1)
657 sock = tcp_connect(&ss, argv[arg]);
658 if (sock < 0)
659 die(1, "Fatal: tcp_connect() failed.\n");
Willy Tarreau869c7592016-11-12 17:50:57 +0100660 dolog("connect\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100661 break;
662
663 case 'A':
664 if (sock < 0)
665 die(1, "Fatal: tcp_accept() on non-socket.\n");
666 sock = tcp_accept(sock, argv[arg]);
667 if (sock < 0)
668 die(1, "Fatal: tcp_accept() failed.\n");
Willy Tarreau869c7592016-11-12 17:50:57 +0100669 dolog("accept\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100670 break;
671
672 case 'T':
673 if (sock < 0)
674 die(1, "Fatal: tcp_set_nodelay() on non-socket.\n");
675 if (tcp_set_nodelay(sock, argv[arg]) < 0)
676 die(1, "Fatal: tcp_set_nodelay() failed.\n");
677 break;
678
679 case 'G':
680 if (sock < 0)
681 die(1, "Fatal: tcp_set_nolinger() on non-socket.\n");
682 if (tcp_set_nolinger(sock, argv[arg]) < 0)
683 die(1, "Fatal: tcp_set_nolinger() failed.\n");
684 break;
685
686 case 'Q':
687 if (sock < 0)
688 die(1, "Fatal: tcp_set_noquickack() on non-socket.\n");
689 if (tcp_set_noquickack(sock, argv[arg]) < 0)
690 die(1, "Fatal: tcp_set_noquickack() failed.\n");
691 break;
692
693 case 'R':
694 if (sock < 0)
695 die(1, "Fatal: tcp_recv() on non-socket.\n");
696 if (tcp_recv(sock, argv[arg]) < 0)
697 die(1, "Fatal: tcp_recv() failed.\n");
698 break;
699
700 case 'S':
701 if (sock < 0)
702 die(1, "Fatal: tcp_send() on non-socket.\n");
703 if (tcp_send(sock, argv[arg]) < 0)
704 die(1, "Fatal: tcp_send() failed.\n");
705 break;
706
707 case 'E':
708 if (sock < 0)
709 die(1, "Fatal: tcp_echo() on non-socket.\n");
710 if (tcp_echo(sock, argv[arg]) < 0)
711 die(1, "Fatal: tcp_echo() failed.\n");
712 break;
713
714 case 'P':
715 if (tcp_pause(sock, argv[arg]) < 0)
716 die(1, "Fatal: tcp_pause() failed.\n");
717 break;
718
719 case 'W':
720 if (sock < 0)
721 die(1, "Fatal: tcp_wait() on non-socket.\n");
722 if (tcp_wait(sock, argv[arg]) < 0)
723 die(1, "Fatal: tcp_wait() failed.\n");
Willy Tarreau869c7592016-11-12 17:50:57 +0100724 dolog("ready_any\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100725 break;
726
727 case 'I':
728 if (sock < 0)
729 die(1, "Fatal: tcp_wait_in() on non-socket.\n");
730 if (tcp_wait_in(sock, argv[arg]) < 0)
731 die(1, "Fatal: tcp_wait_in() failed.\n");
Willy Tarreau869c7592016-11-12 17:50:57 +0100732 dolog("ready_in\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100733 break;
734
735 case 'O':
736 if (sock < 0)
737 die(1, "Fatal: tcp_wait_out() on non-socket.\n");
738 if (tcp_wait_out(sock, argv[arg]) < 0)
739 die(1, "Fatal: tcp_wait_out() failed.\n");
Willy Tarreau869c7592016-11-12 17:50:57 +0100740 dolog("ready_out\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100741 break;
742
743 case 'K':
744 if (sock < 0 || close(sock) < 0)
745 die(1, "Fatal: close() on non-socket.\n");
Willy Tarreau869c7592016-11-12 17:50:57 +0100746 dolog("close\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100747 sock = -1;
748 break;
749
750 case 'F':
751 /* ignore errors on shutdown() as they are common */
752 if (sock >= 0)
753 shutdown(sock, SHUT_WR);
Willy Tarreau869c7592016-11-12 17:50:57 +0100754 dolog("shutdown\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100755 break;
756
Willy Tarreau95a6b782016-11-12 13:25:53 +0100757 case 'N':
758 ret = tcp_fork(sock, argv[arg]);
759 if (ret < 0)
760 die(1, "Fatal: fork() failed.\n");
761 if (ret > 0) {
762 /* loop back to first arg */
763 arg = 1;
764 continue;
765 }
766 /* OK we're in the child, let's continue */
Willy Tarreau869c7592016-11-12 17:50:57 +0100767 pid = getpid();
Willy Tarreau95a6b782016-11-12 13:25:53 +0100768 break;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100769 default:
770 usage(1, arg0);
771 }
772 }
773 return 0;
774}