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.
diff --git a/dev/tcploop/tcploop.c b/dev/tcploop/tcploop.c
index 1aebb88..8433872 100644
--- a/dev/tcploop/tcploop.c
+++ b/dev/tcploop/tcploop.c
@@ -99,6 +99,8 @@
"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 @@
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 @@
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 @@
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 @@
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");