summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorStefan Metzmacher <metze@samba.org>2020-06-19 21:07:09 +0000
committerStefan Metzmacher <metze@samba.org>2020-06-19 21:07:09 +0000
commitf4fc52be79edc74bd24b3ee968c5358af81b17bd (patch)
treeb9004de1af9a4e645da631f6ebf905967207d9c6 /src
parentbbc1d654cae9197fa3782e8ea8e1aaa9fdf0cfb0 (diff)
parentf317ebcdcdd626ed9e06de2eb60031306994c803 (diff)
downloadsocket_wrapper-f4fc52be79edc74bd24b3ee968c5358af81b17bd.tar.gz
socket_wrapper-f4fc52be79edc74bd24b3ee968c5358af81b17bd.tar.xz
socket_wrapper-f4fc52be79edc74bd24b3ee968c5358af81b17bd.zip
Merge branch 'tcp_info' into 'master'
Add support for TCP_INFO and SIOCOUTQ/TIOCOUTQ/FIONWRITE See merge request cwrap/socket_wrapper!11
Diffstat (limited to 'src')
-rw-r--r--src/socket_wrapper.c83
1 files changed, 80 insertions, 3 deletions
diff --git a/src/socket_wrapper.c b/src/socket_wrapper.c
index 5b7c9ea..333bdd4 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;
@@ -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;
}
@@ -4578,7 +4635,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 +4650,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);