CONTRIB: tcploop: implement a disconnect operation 'D'
This performs a connect(AF_UNSPEC) over an existing connection. This is
mainly for compatibility testing. At this step it only seems to work on
linux for TCP sockets (both listening and established), while SO_LINGER
successfully resets established connections on freebsd and aix.
diff --git a/contrib/tcploop/tcploop.c b/contrib/tcploop/tcploop.c
index f9f5f63..55b7936 100644
--- a/contrib/tcploop/tcploop.c
+++ b/contrib/tcploop/tcploop.c
@@ -105,6 +105,7 @@
" Note: fd=socket,bind(fd),listen(fd)\n"
" C : Connects to ip:port\n"
" Note: fd=socket,connect(fd)\n"
+ " D : Disconnect (connect to AF_UNSPEC)\n"
" A[<count>] : Accepts <count> incoming sockets and closes count-1\n"
" Note: fd=accept(fd)\n"
" J : Jump back to oldest post-fork/post-accept action\n"
@@ -443,6 +444,14 @@
return -1;
}
+/* Try to disconnect by connecting to AF_UNSPEC. Return >=0 on success, -1 in case of error */
+int tcp_disconnect(int sock)
+{
+ const struct sockaddr sa = { .sa_family = AF_UNSPEC };
+
+ return connect(sock, &sa, sizeof(sa));
+}
+
/* receives N bytes from the socket and returns 0 (or -1 in case of a recv
* error, or -2 in case of an argument error). When no arg is passed, receives
* anything and stops. Otherwise reads the requested amount of data. 0 means
@@ -787,6 +796,13 @@
dolog("connect\n");
break;
+ case 'D':
+ /* silently ignore non-existing connections */
+ if (sock >= 0 && tcp_disconnect(sock) < 0)
+ die(1, "Fatal: tcp_connect() failed.\n");
+ dolog("disconnect\n");
+ break;
+
case 'A':
if (sock < 0)
die(1, "Fatal: tcp_accept() on non-socket.\n");