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.
This commit is contained in:
Willy Tarreau 2022-06-07 12:03:48 +02:00
parent cb284c7a62
commit d493331d47

View File

@ -99,6 +99,8 @@ __attribute__((noreturn)) void usage(int code, const char *arg0)
"actions :\n"
" A[<count>] : Accepts <count> 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 <sa>. 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 <sa>. 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 <sa>. 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");