[SCM] Socket Wrapper Repository - branch master updated
Stefan Metzmacher
metze at samba.org
Mon Jun 22 14:46:27 UTC 2020
The branch, master has been updated
via b94af54 socket_wrapper.c: let swrap_vioctl() handle SIOCOUTQ/TIOCOUTQ/FIONWRITE explicitly
via 64cee56 socket_wrapper.c: make FIONREAD handling more robust in swrap_vioctl()
via 309103f test_echo_tcp_socket_options.c: add tests for TCP_INFO
via c73d8a4 socket_wrapper.c: implement getsockopt(TCP_INFO) if the platform supports it
via 1c20b95 doc: Document SOCKET_WRAPPER_DIR_ALLOW_ORIG
via 19c3e87 swrap: Add SOCKET_WRAPPER_DIR_ALLOW_ORIG to allow fall back
via dd42895 swrap: Abort if socket wrapper directory is too long to be usable
via fc1e98f swrap: Add abstractions to construct Unix domain socket paths
via 80e0f42 swrap: Abort on failure to use SOCKET_WRAPPER_DIR
from 49aeafa Revert "socket_wrapper.c: implement getsockopt(TCP_INFO) if the platform supports it"
https://git.samba.org/?p=socket_wrapper.git;a=shortlog;h=master
- Log -----------------------------------------------------------------
commit b94af548f42e561207db7cacbe09c9e3286de2d3
Author: Stefan Metzmacher <metze at samba.org>
Date: Mon Jun 8 14:21:25 2020 +0200
socket_wrapper.c: let swrap_vioctl() handle SIOCOUTQ/TIOCOUTQ/FIONWRITE explicitly
They are used to ask for the number of unacked bytes in the send queue,
with AF_UNIX sockets get strange result, on linux 5.3 I get more bytes
reported than I sent into the socket. All bytes reach the destination
directly, so we can just always report 0 unacked bytes.
BUG: https://bugzilla.samba.org/show_bug.cgi?id=11897
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Andreas Schneider <asn at samba.org>
(cherry picked from commit f317ebcdcdd626ed9e06de2eb60031306994c803)
commit 64cee569a77e9d9d92e0dc0d2793536c9fb4a45e
Author: Stefan Metzmacher <metze at samba.org>
Date: Mon Jun 8 14:18:44 2020 +0200
socket_wrapper.c: make FIONREAD handling more robust in swrap_vioctl()
We should only dereference the va args when the kernel already checked
they are valid.
BUG: https://bugzilla.samba.org/show_bug.cgi?id=11897
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Andreas Schneider <asn at samba.org>
(cherry picked from commit c95b7cb1d7b9348472276edceff71889aa676d25)
commit 309103f464af19d6190f89de959c6dc41ba58c85
Author: Stefan Metzmacher <metze at samba.org>
Date: Fri Jun 19 20:52:23 2020 +0200
test_echo_tcp_socket_options.c: add tests for TCP_INFO
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Andreas Schneider <asn at samba.org>
(cherry picked from commit a37c0175492fb1b35257b785c71dea4e4f6d4750)
commit c73d8a43c07ffbd9f4a7010b99363ffa53b4723c
Author: Stefan Metzmacher <metze at samba.org>
Date: Mon Jun 8 10:32:28 2020 +0200
socket_wrapper.c: implement getsockopt(TCP_INFO) if the platform supports it
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 at samba.org>
Reviewed-by: Andreas Schneider <asn at samba.org>
(cherry picked from commit 300de6e099ea82ee5361918de8c3abb389e0782d)
commit 1c20b9596422c9cb92fc539493df45b03d91457b
Author: Martin Schwenke <martin at meltin.net>
Date: Thu May 14 09:57:24 2020 +1000
doc: Document SOCKET_WRAPPER_DIR_ALLOW_ORIG
Signed-off-by: Martin Schwenke <martin at meltin.net>
Reviewed-by: Andreas Schneider <asn at samba.org>
Reviewed-by: Stefan Metzmacher <metze at samba.org>
commit 19c3e87570954cb7fb4f6c105cbec9eabf4539b0
Author: Martin Schwenke <martin at meltin.net>
Date: Thu May 14 10:01:54 2020 +1000
swrap: Add SOCKET_WRAPPER_DIR_ALLOW_ORIG to allow fall back
Instead of failing when the path returned by realpath(3) is too long,
if SOCKET_WRAPPER_DIR_ALLOW_ORIG is set then fall back to the
original value. If this original path is too long or something else
fails then abort.
Signed-off-by: Martin Schwenke <martin at meltin.net>
Reviewed-by: Andreas Schneider <asn at samba.org>
Reviewed-by: Stefan Metzmacher <metze at samba.org>
commit dd428959713998d3f973bcf2762d489ef27d9f13
Author: Martin Schwenke <martin at meltin.net>
Date: Wed May 13 13:45:02 2020 +1000
swrap: Abort if socket wrapper directory is too long to be usable
If the socket wrapper directory path is too long to allow reliable
construction of the required Unix domain socket paths then
convert_in_un_alloc() can return ENFILE if paths are truncated in
unfortunate ways. This can be very hard to debug since, for example,
bind(2) should never return ENFILE.
Instead, abort if the path returned by realpath(3) is unusable.
The code structure is slightly weird but this accommodates an
additional change.
Signed-off-by: Martin Schwenke <martin at meltin.net>
Reviewed-by: Andreas Schneider <asn at samba.org>
Reviewed-by: Stefan Metzmacher <metze at samba.org>
commit fc1e98f8ca51ca4de7551e61b6b9c6c99d183b10
Author: Martin Schwenke <martin at meltin.net>
Date: Wed May 13 13:23:21 2020 +1000
swrap: Add abstractions to construct Unix domain socket paths
These include overflow checks but the results of the checks are not
yet used.
Signed-off-by: Martin Schwenke <martin at meltin.net>
Reviewed-by: Andreas Schneider <asn at samba.org>
Reviewed-by: Stefan Metzmacher <metze at samba.org>
commit 80e0f42b19d9d73a50c1cf7c5a19d1a2dac70d4e
Author: Martin Schwenke <martin at meltin.net>
Date: Sat Jun 13 20:50:42 2020 +1000
swrap: Abort on failure to use SOCKET_WRAPPER_DIR
If SOCKET_WRAPPER_DIR is set the intention is to use socket wrapper.
Returning NULL means socket wrapper is disabled. The only sure way to
avoid running without socket wrapper is to abort.
Signed-off-by: Martin Schwenke <martin at meltin.net>
Reviewed-by: Andreas Schneider <asn at samba.org>
Reviewed-by: Stefan Metzmacher <metze at samba.org>
-----------------------------------------------------------------------
Summary of changes:
ConfigureChecks.cmake | 1 +
config.h.cmake | 1 +
doc/socket_wrapper.1 | 7 +-
doc/socket_wrapper.1.txt | 10 ++
src/socket_wrapper.c | 209 +++++++++++++++++++++++++++++++----
tests/echo_srv.c | 32 ++++++
tests/test_echo_tcp_socket_options.c | 50 +++++++++
7 files changed, 289 insertions(+), 21 deletions(-)
Changeset truncated at 500 lines:
diff --git a/ConfigureChecks.cmake b/ConfigureChecks.cmake
index 4d5adc4..4a2f55e 100644
--- a/ConfigureChecks.cmake
+++ b/ConfigureChecks.cmake
@@ -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)
diff --git a/config.h.cmake b/config.h.cmake
index 36050b5..d3ceb23 100644
--- a/config.h.cmake
+++ b/config.h.cmake
@@ -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
diff --git a/doc/socket_wrapper.1 b/doc/socket_wrapper.1
index e244f10..ec7f4b8 100644
--- a/doc/socket_wrapper.1
+++ b/doc/socket_wrapper.1
@@ -1,7 +1,7 @@
'\" t
.\" Title: socket_wrapper
.\" Author: Samba Team
-.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
.\" Date: 2018-11-28
.\" Manual: \ \&
.\" Source: \ \&
@@ -157,6 +157,11 @@ If you need to see what is going on in socket_wrapper itself or try to find a bu
.RS 4
This allows you to disable deep binding in socket_wrapper\&. This is useful for running valgrind tools or sanitizers like (address, undefined, thread)\&.
.RE
+.PP
+\fBSOCKET_WRAPPER_DIR_ALLOW_ORIG\fR
+.RS 4
+SOCKET_WRAPPER_DIR is resolved by socket_wrapper using realpath(3)\&. Given that Unix sockets are constructed relative to this directory, the resulting path can sometimes be too long to allow valid socket paths to be constructed due to length restrictions\&. Setting this variable (to any value) allows socket_wrapper to fall back to the original value of SOCKET_WRAPPER_DIR if realpath(3) makes it too long to be usable\&.
+.RE
.SH "EXAMPLE"
.sp
.if n \{\
diff --git a/doc/socket_wrapper.1.txt b/doc/socket_wrapper.1.txt
index c00d582..d070fbf 100644
--- a/doc/socket_wrapper.1.txt
+++ b/doc/socket_wrapper.1.txt
@@ -95,6 +95,16 @@ debug symbols.
This allows you to disable deep binding in socket_wrapper. This is useful for
running valgrind tools or sanitizers like (address, undefined, thread).
+*SOCKET_WRAPPER_DIR_ALLOW_ORIG*::
+
+SOCKET_WRAPPER_DIR is resolved by socket_wrapper using realpath(3).
+Given that Unix sockets are constructed relative to this directory,
+the resulting path can sometimes be too long to allow valid socket
+paths to be constructed due to length restrictions. Setting this
+variable (to any value) allows socket_wrapper to fall back to the
+original value of SOCKET_WRAPPER_DIR if realpath(3) makes it too long
+to be usable.
+
EXAMPLE
-------
diff --git a/src/socket_wrapper.c b/src/socket_wrapper.c
index 5b7c9ea..ffdd31a 100644
--- a/src/socket_wrapper.c
+++ b/src/socket_wrapper.c
@@ -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;
@@ -1370,10 +1374,69 @@ static void swrap_set_next_free(struct socket_info *si, int next_free)
sic->meta.next_free = next_free;
}
+static int swrap_un_path(struct sockaddr_un *un,
+ const char *swrap_dir,
+ char type,
+ unsigned int iface,
+ unsigned int prt)
+{
+ int ret;
+
+ ret = snprintf(un->sun_path,
+ sizeof(un->sun_path),
+ "%s/"SOCKET_FORMAT,
+ swrap_dir,
+ type,
+ iface,
+ prt);
+ if ((size_t)ret >= sizeof(un->sun_path)) {
+ return ENAMETOOLONG;
+ }
+
+ return 0;
+}
+
+static int swrap_un_path_EINVAL(struct sockaddr_un *un,
+ const char *swrap_dir)
+{
+ int ret;
+
+ ret = snprintf(un->sun_path,
+ sizeof(un->sun_path),
+ "%s/EINVAL",
+ swrap_dir);
+
+ if ((size_t)ret >= sizeof(un->sun_path)) {
+ return ENAMETOOLONG;
+ }
+
+ return 0;
+}
+
+static bool swrap_dir_usable(const char *swrap_dir)
+{
+ struct sockaddr_un un;
+ int ret;
+
+ ret = swrap_un_path(&un, swrap_dir, SOCKET_TYPE_CHAR_TCP, 0, 0);
+ if (ret == 0) {
+ return true;
+ }
+
+ ret = swrap_un_path_EINVAL(&un, swrap_dir);
+ if (ret == 0) {
+ return true;
+ }
+
+ return false;
+}
+
static char *socket_wrapper_dir(void)
{
char *swrap_dir = NULL;
char *s = getenv("SOCKET_WRAPPER_DIR");
+ char *t;
+ bool ok;
if (s == NULL) {
SWRAP_LOG(SWRAP_LOG_WARN, "SOCKET_WRAPPER_DIR not set");
@@ -1385,9 +1448,43 @@ static char *socket_wrapper_dir(void)
SWRAP_LOG(SWRAP_LOG_ERROR,
"Unable to resolve socket_wrapper dir path: %s",
strerror(errno));
- return NULL;
+ abort();
+ }
+
+ ok = swrap_dir_usable(swrap_dir);
+ if (ok) {
+ goto done;
+ }
+
+ free(swrap_dir);
+
+ ok = swrap_dir_usable(s);
+ if (!ok) {
+ SWRAP_LOG(SWRAP_LOG_ERROR, "SOCKET_WRAPPER_DIR is too long");
+ abort();
+ }
+
+ t = getenv("SOCKET_WRAPPER_DIR_ALLOW_ORIG");
+ if (t == NULL) {
+ SWRAP_LOG(SWRAP_LOG_ERROR,
+ "realpath(SOCKET_WRAPPER_DIR) too long and "
+ "SOCKET_WRAPPER_DIR_ALLOW_ORIG not set");
+ abort();
+
}
+ swrap_dir = strdup(s);
+ if (swrap_dir == NULL) {
+ SWRAP_LOG(SWRAP_LOG_ERROR,
+ "Unable to duplicate socket_wrapper dir path");
+ abort();
+ }
+
+ SWRAP_LOG(SWRAP_LOG_WARN,
+ "realpath(SOCKET_WRAPPER_DIR) too long, "
+ "using original SOCKET_WRAPPER_DIR\n");
+
+done:
SWRAP_LOG(SWRAP_LOG_TRACE, "socket_wrapper_dir: %s", swrap_dir);
return swrap_dir;
}
@@ -1932,16 +2029,14 @@ static int convert_in_un_remote(struct socket_info *si, const struct sockaddr *i
}
if (is_bcast) {
- snprintf(un->sun_path, sizeof(un->sun_path),
- "%s/EINVAL", swrap_dir);
+ swrap_un_path_EINVAL(un, swrap_dir);
SWRAP_LOG(SWRAP_LOG_DEBUG, "un path [%s]", un->sun_path);
SAFE_FREE(swrap_dir);
/* the caller need to do more processing */
return 0;
}
- snprintf(un->sun_path, sizeof(un->sun_path), "%s/"SOCKET_FORMAT,
- swrap_dir, type, iface, prt);
+ swrap_un_path(un, swrap_dir, type, iface, prt);
SWRAP_LOG(SWRAP_LOG_DEBUG, "un path [%s]", un->sun_path);
SAFE_FREE(swrap_dir);
@@ -2109,8 +2204,7 @@ static int convert_in_un_alloc(struct socket_info *si, const struct sockaddr *in
if (prt == 0) {
/* handle auto-allocation of ephemeral ports */
for (prt = 5001; prt < 10000; prt++) {
- snprintf(un->sun_path, sizeof(un->sun_path), "%s/"SOCKET_FORMAT,
- swrap_dir, type, iface, prt);
+ swrap_un_path(un, swrap_dir, type, iface, prt);
if (stat(un->sun_path, &st) == 0) continue;
set_port(si->family, prt, &si->myname);
@@ -2126,8 +2220,7 @@ static int convert_in_un_alloc(struct socket_info *si, const struct sockaddr *in
}
}
- snprintf(un->sun_path, sizeof(un->sun_path), "%s/"SOCKET_FORMAT,
- swrap_dir, type, iface, prt);
+ swrap_un_path(un, swrap_dir, type, iface, prt);
SWRAP_LOG(SWRAP_LOG_DEBUG, "un path [%s]", un->sun_path);
SAFE_FREE(swrap_dir);
@@ -3719,9 +3812,11 @@ static int swrap_auto_bind(int fd, struct socket_info *si, int family)
for (i = 0; i < SOCKET_MAX_SOCKETS; i++) {
port = autobind_start + i;
- snprintf(un_addr.sa.un.sun_path, sizeof(un_addr.sa.un.sun_path),
- "%s/"SOCKET_FORMAT, swrap_dir, type,
- socket_wrapper_default_iface(), port);
+ swrap_un_path(&un_addr.sa.un,
+ swrap_dir,
+ type,
+ socket_wrapper_default_iface(),
+ port);
if (stat(un_addr.sa.un.sun_path, &st) == 0) continue;
ret = libc_bind(fd, &un_addr.sa.s, un_addr.sa_socklen);
@@ -4097,6 +4192,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 +4544,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;
}
@@ -4578,7 +4726,7 @@ static int swrap_vioctl(int s, unsigned long int r, va_list va)
{
struct socket_info *si = find_socket_info(s);
va_list ap;
- int value;
+ int *value_ptr = NULL;
int rc;
if (!si) {
@@ -4593,14 +4741,34 @@ static int swrap_vioctl(int s, unsigned long int r, va_list va)
switch (r) {
case FIONREAD:
- value = *((int *)va_arg(ap, int *));
+ if (rc == 0) {
+ value_ptr = ((int *)va_arg(ap, int *));
+ }
if (rc == -1 && errno != EAGAIN && errno != ENOBUFS) {
swrap_pcap_dump_packet(si, NULL, SWRAP_PENDING_RST, NULL, 0);
- } else if (value == 0) { /* END OF FILE */
+ } else if (value_ptr != NULL && *value_ptr == 0) { /* END OF FILE */
swrap_pcap_dump_packet(si, NULL, SWRAP_PENDING_RST, NULL, 0);
}
break;
+#ifdef FIONWRITE
+ case FIONWRITE:
+ /* this is FreeBSD */
+ FALL_THROUGH; /* to TIOCOUTQ */
+#endif /* FIONWRITE */
+ case TIOCOUTQ: /* same as SIOCOUTQ on Linux */
+ /*
+ * This may return more bytes then the application
+ * sent into the socket, for tcp it should
+ * return the number of unacked bytes.
+ *
+ * On AF_UNIX, all bytes are immediately acked!
+ */
+ if (rc == 0) {
+ value_ptr = ((int *)va_arg(ap, int *));
+ *value_ptr = 0;
+ }
+ break;
}
va_end(ap);
@@ -5529,9 +5697,11 @@ static ssize_t swrap_sendto(int s, const void *buf, size_t len, int flags,
}
for(iface=0; iface <= MAX_WRAPPED_INTERFACES; iface++) {
- snprintf(un_addr.sa.un.sun_path,
- sizeof(un_addr.sa.un.sun_path),
- "%s/"SOCKET_FORMAT, swrap_dir, type, iface, prt);
+ swrap_un_path(&un_addr.sa.un,
+ swrap_dir,
+ type,
+ iface,
+ prt);
if (stat(un_addr.sa.un.sun_path, &st) != 0) continue;
/* ignore the any errors in broadcast sends */
@@ -6038,8 +6208,7 @@ static ssize_t swrap_sendmsg(int s, const struct msghdr *omsg, int flags)
}
for(iface=0; iface <= MAX_WRAPPED_INTERFACES; iface++) {
- snprintf(un_addr.sun_path, sizeof(un_addr.sun_path), "%s/"SOCKET_FORMAT,
- swrap_dir, type, iface, prt);
+ swrap_un_path(&un_addr, swrap_dir, type, iface, prt);
if (stat(un_addr.sun_path, &st) != 0) continue;
msg.msg_name = &un_addr; /* optional address */
diff --git a/tests/echo_srv.c b/tests/echo_srv.c
index 93778f2..87c85f7 100644
--- a/tests/echo_srv.c
+++ b/tests/echo_srv.c
@@ -9,6 +9,10 @@
#include <arpa/inet.h>
#include <netinet/in.h>
+#include <netinet/tcp.h>
+#ifdef HAVE_NETINET_TCP_FSM_H
+#include <netinet/tcp_fsm.h>
+#endif
#include <netdb.h>
#include <resolv.h>
@@ -315,6 +319,34 @@ static int setup_srv(struct echo_srv_opts *opts, int *_sock)
perror("listen");
return ret;
}
+#ifdef TCP_INFO
+ {
+ struct tcp_info info;
+ socklen_t optlen = sizeof(info);
+
+ ZERO_STRUCT(info);
+ ret = getsockopt(sock, IPPROTO_TCP, TCP_INFO, &info, &optlen);
+ if (ret == -1) {
+ ret = errno;
+ perror("TCP_INFO failed");
+ close(sock);
+ return ret;
+ }
+#ifdef HAVE_NETINET_TCP_FSM_H
+/* This is FreeBSD */
+# define __TCP_LISTEN TCPS_LISTEN
+#else
+/* This is Linux */
+# define __TCP_LISTEN TCP_LISTEN
+#endif
+ if (info.tcpi_state != __TCP_LISTEN) {
+ errno = ret = ERANGE;
+ perror("not __TCP_LISTEN => ERANGE...");
+ close(sock);
+ return ret;
+ }
+ }
+#endif /* TCP_INFO */
}
*_sock = sock;
diff --git a/tests/test_echo_tcp_socket_options.c b/tests/test_echo_tcp_socket_options.c
index dfa46fe..5e5661d 100644
--- a/tests/test_echo_tcp_socket_options.c
+++ b/tests/test_echo_tcp_socket_options.c
@@ -11,12 +11,25 @@
#include <sys/socket.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 <netdb.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
+#ifdef HAVE_NETINET_TCP_FSM_H
+/* This is FreeBSD */
+# define __TCP_ESTABLISHED TCPS_ESTABLISHED
+# define __TCP_CLOSE TCPS_CLOSED
+#else
+/* This is Linux */
+# define __TCP_ESTABLISHED TCP_ESTABLISHED
+# define __TCP_CLOSE TCP_CLOSE
+#endif
+
#ifndef ZERO_STRUCT
#define ZERO_STRUCT(x) memset((char *)&(x), 0, sizeof(x))
#endif
@@ -300,6 +313,9 @@ static void test_sockopt_tcp(void **state)
.sa_socklen = sizeof(struct sockaddr_in),
};
int opt = -1;
+#ifdef TCP_INFO
+ struct tcp_info info;
+#endif
socklen_t optlen = sizeof(int);
int rc;
@@ -318,9 +334,27 @@ static void test_sockopt_tcp(void **state)
&addr.sa.in.sin_addr);
assert_int_equal(rc, 1);
+#ifdef TCP_INFO
+ ZERO_STRUCT(info);
+ optlen = sizeof(info);
+ rc = getsockopt(s, IPPROTO_TCP, TCP_INFO, &info, &optlen);
+ assert_return_code(rc, errno);
+ assert_int_equal(optlen, sizeof(info));
+ printf("info.tcpi_state=0x%x\n", info.tcpi_state);
--
Socket Wrapper Repository
More information about the samba-cvs
mailing list