From d493331d47dc2e81986ba44f154981224713a56c Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Tue, 7 Jun 2022 12:03:48 +0200 Subject: [PATCH] DEV: tcploop: add a new "bind" command to bind to ip/port. The Listen command automatically relies on it (without passing its argument), and both Listen and Connect now support working with the existing socket, so that it's possible to Bind an ip:port on an existing socket or to create a new one for the purpose of listening or connecting. It now becomes possible to do: tcploop 0 L1234 C8888 to connect from port 1234 to port 8888. --- dev/tcploop/tcploop.c | 72 +++++++++++++++++++++++++++++++------------ 1 file changed, 53 insertions(+), 19 deletions(-) diff --git a/dev/tcploop/tcploop.c b/dev/tcploop/tcploop.c index 1aebb881e..8433872f8 100644 --- a/dev/tcploop/tcploop.c +++ b/dev/tcploop/tcploop.c @@ -99,6 +99,8 @@ __attribute__((noreturn)) void usage(int code, const char *arg0) "actions :\n" " A[] : Accepts incoming sockets and closes count-1\n" " Note: fd=accept(fd)\n" + " B[[ip]:port] : Bind a new socket to ip:port or default one if unspecified.\n" + " Note: fd=socket,bind(fd)\n" " C[[ip]:port] : Connects to ip:port or default ones if unspecified.\n" " Note: fd=socket,connect(fd)\n" " D : Disconnect (connect to AF_UNSPEC)\n" @@ -345,10 +347,21 @@ int tcp_socket() return sock; } -/* Try to listen to address . Return the fd or -1 in case of error */ -int tcp_listen(int sock, const struct sockaddr_storage *sa, const char *arg) +/* Try to bind to local address . Return the fd or -1 in case of error. + * Supports being passed NULL for arg if none has to be passed. + */ +int tcp_bind(int sock, const struct sockaddr_storage *sa, const char *arg) { - int backlog; + struct sockaddr_storage conn_addr; + + if (arg && arg[1]) { + struct err_msg err; + + if (addr_to_ss(arg + 1, &conn_addr, &err) < 0) + die(1, "%s\n", err.msg); + sa = &conn_addr; + } + if (sock < 0) { sock = tcp_socket(); @@ -356,16 +369,6 @@ int tcp_listen(int sock, const struct sockaddr_storage *sa, const char *arg) return sock; } - if (arg[1]) - backlog = atoi(arg + 1); - else - backlog = 1000; - - if (backlog < 0 || backlog > 65535) { - fprintf(stderr, "backlog must be between 0 and 65535 inclusive (was %d)\n", backlog); - goto fail; - } - if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) == -1) { perror("setsockopt(SO_REUSEADDR)"); goto fail; @@ -383,6 +386,33 @@ int tcp_listen(int sock, const struct sockaddr_storage *sa, const char *arg) goto fail; } + return sock; + fail: + close(sock); + return -1; +} + +/* Try to listen to address . Return the fd or -1 in case of error */ +int tcp_listen(int sock, const struct sockaddr_storage *sa, const char *arg) +{ + int backlog; + + if (sock < 0) { + sock = tcp_bind(sock, sa, NULL); + if (sock < 0) + return sock; + } + + if (arg[1]) + backlog = atoi(arg + 1); + else + backlog = 1000; + + if (backlog < 0 || backlog > 65535) { + fprintf(stderr, "backlog must be between 0 and 65535 inclusive (was %d)\n", backlog); + goto fail; + } + if (listen(sock, backlog) == -1) { perror("listen"); goto fail; @@ -798,17 +828,21 @@ int main(int argc, char **argv) for (arg = loop_arg; arg < argc; arg++) { switch (argv[arg][0]) { case 'L': - /* silently ignore existing connections */ - if (sock == -1) - sock = tcp_listen(sock, &default_addr, argv[arg]); + sock = tcp_listen(sock, &default_addr, argv[arg]); if (sock < 0) die(1, "Fatal: tcp_listen() failed.\n"); break; - case 'C': + case 'B': /* silently ignore existing connections */ - if (sock == -1) - sock = tcp_connect(sock, &default_addr, argv[arg]); + sock = tcp_bind(sock, &default_addr, argv[arg]); + if (sock < 0) + die(1, "Fatal: tcp_connect() failed.\n"); + dolog("connect\n"); + break; + + case 'C': + sock = tcp_connect(sock, &default_addr, argv[arg]); if (sock < 0) die(1, "Fatal: tcp_connect() failed.\n"); dolog("connect\n");