socket_wrapper.c: implement getsockopt(TCP_INFO) if the platform supports it
authorStefan Metzmacher <metze@samba.org>
Mon, 8 Jun 2020 08:32:28 +0000 (10:32 +0200)
committerStefan Metzmacher <metze@samba.org>
Fri, 19 Jun 2020 19:16:34 +0000 (21:16 +0200)
This just implements a few basics, which are required by Samba.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=11897

Signed-off-by: Stefan Metzmacher <metze@samba.org>
ConfigureChecks.cmake
config.h.cmake
src/socket_wrapper.c

index 4d5adc4219fb5155027737206e45dec59c341813..4a2f55e95258f67ad310f0c9671a28ce0333fa61 100644 (file)
@@ -43,6 +43,7 @@ int main(void){ return 0; }
 endif(CMAKE_COMPILER_IS_GNUCC AND NOT MINGW AND NOT OS2)
 
 # HEADERS
+check_include_file(netinet/tcp_fsm.h HAVE_NETINET_TCP_FSM_H)
 check_include_file(sys/filio.h HAVE_SYS_FILIO_H)
 check_include_file(sys/signalfd.h HAVE_SYS_SIGNALFD_H)
 check_include_file(sys/eventfd.h HAVE_SYS_EVENTFD_H)
index 36050b560b0b7149276733f0208fb113946e44b2..d3ceb238f0274e8905d1e2535f6dea30dbd52b13 100644 (file)
@@ -9,6 +9,7 @@
 
 /************************** HEADER FILES *************************/
 
+#cmakedefine HAVE_NETINET_TCP_FSM_H 1
 #cmakedefine HAVE_SYS_FILIO_H 1
 #cmakedefine HAVE_SYS_SIGNALFD_H 1
 #cmakedefine HAVE_SYS_EVENTFD_H 1
index 5b7c9eaddc526625bdaf034baf5cf6beafe56eb9..4fb7b23c8eed358a6af1b3cb8400dd3b46e30f5f 100644 (file)
@@ -66,6 +66,9 @@
 #include <sys/un.h>
 #include <netinet/in.h>
 #include <netinet/tcp.h>
+#ifdef HAVE_NETINET_TCP_FSM_H
+#include <netinet/tcp_fsm.h>
+#endif
 #include <arpa/inet.h>
 #include <fcntl.h>
 #include <stdlib.h>
@@ -264,6 +267,7 @@ struct socket_info
        int defer_connect;
        int pktinfo;
        int tcp_nodelay;
+       int listening;
 
        /* The unix path so we can unlink it on close() */
        struct sockaddr_un un_addr;
@@ -4097,6 +4101,9 @@ static int swrap_listen(int s, int backlog)
        }
 
        ret = libc_listen(s, backlog);
+       if (ret == 0) {
+               si->listening = 1;
+       }
 
 out:
        SWRAP_UNLOCK_SI(si);
@@ -4446,6 +4453,56 @@ static int swrap_getsockopt(int s, int level, int optname,
                        ret = 0;
                        goto done;
 #endif /* TCP_NODELAY */
+#ifdef TCP_INFO
+               case TCP_INFO: {
+                       struct tcp_info info;
+                       socklen_t ilen = sizeof(info);
+
+#ifdef HAVE_NETINET_TCP_FSM_H
+/* This is FreeBSD */
+# define __TCP_LISTEN TCPS_LISTEN
+# define __TCP_ESTABLISHED TCPS_ESTABLISHED
+# define __TCP_CLOSE TCPS_CLOSED
+#else
+/* This is Linux */
+# define __TCP_LISTEN TCP_LISTEN
+# define __TCP_ESTABLISHED TCP_ESTABLISHED
+# define __TCP_CLOSE TCP_CLOSE
+#endif
+
+                       ZERO_STRUCT(info);
+                       if (si->listening) {
+                               info.tcpi_state = __TCP_LISTEN;
+                       } else if (si->connected) {
+                               /*
+                                * For now we just fake a few values
+                                * supported both by FreeBSD and Linux
+                                */
+                               info.tcpi_state = __TCP_ESTABLISHED;
+                               info.tcpi_rto = 200000;  /* 200 msec */
+                               info.tcpi_rtt = 5000;    /* 5 msec */
+                               info.tcpi_rttvar = 5000; /* 5 msec */
+                       } else {
+                               info.tcpi_state = __TCP_CLOSE;
+                               info.tcpi_rto = 1000000;  /* 1 sec */
+                               info.tcpi_rtt = 0;
+                               info.tcpi_rttvar = 250000; /* 250 msec */
+                       }
+
+                       if (optval == NULL || optlen == NULL ||
+                           *optlen < (socklen_t)ilen) {
+                               errno = EINVAL;
+                               ret = -1;
+                               goto done;
+                       }
+
+                       *optlen = ilen;
+                       memcpy(optval, &info, ilen);
+
+                       ret = 0;
+                       goto done;
+               }
+#endif /* TCP_INFO */
                default:
                        break;
                }