public inbox for cygwin-cvs@sourceware.org
help / color / mirror / Atom feed
* [newlib-cygwin] Cygwin: tcp: Support TCP_KEEPIDLE, TCP_KEEPCNT, TCP_KEEPINTVL
@ 2020-07-01 18:32 Corinna Vinschen
0 siblings, 0 replies; only message in thread
From: Corinna Vinschen @ 2020-07-01 18:32 UTC (permalink / raw)
To: cygwin-cvs
https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=8ccffddc91942dcb4a6417c13b46c5ab5d81a5d9
commit 8ccffddc91942dcb4a6417c13b46c5ab5d81a5d9
Author: Corinna Vinschen <corinna@vinschen.de>
Date: Wed Jul 1 20:27:10 2020 +0200
Cygwin: tcp: Support TCP_KEEPIDLE, TCP_KEEPCNT, TCP_KEEPINTVL
Use WSAIoctl(SIO_KEEPALIVE_VALS) on older systems.
Make sure that keep-alive timeout is equivalent to
TCP_KEEPIDLE + TCP_KEEPCNT * TCP_KEEPINTVL on older systems,
even with TCP_KEEPCNT being a fixed value on those systems.
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
Diff:
---
winsup/cygwin/fhandler.h | 5 ++
winsup/cygwin/fhandler_socket_inet.cc | 163 ++++++++++++++++++++++++++++++++--
winsup/cygwin/include/netinet/tcp.h | 9 +-
winsup/cygwin/wincap.cc | 11 +++
winsup/cygwin/wincap.h | 2 +
5 files changed, 178 insertions(+), 12 deletions(-)
diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index 57f282105..24184dacc 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -720,6 +720,11 @@ class fhandler_socket_inet: public fhandler_socket_wsock
private:
bool oobinline; /* True if option SO_OOBINLINE is set */
bool tcp_fastopen; /* True if TCP_FASTOPEN is set on older systems */
+ int tcp_keepidle; /* TCP_KEEPIDLE value in secs on older systems */
+ int tcp_keepcnt; /* TCP_KEEPCNT value on older systems */
+ int tcp_keepintvl; /* TCP_KEEPINTVL value in secs on older systems */
+
+ int set_keepalive (int keepidle, int keepcnt, int keepintvl);
protected:
int af_local_connect () { return 0; }
diff --git a/winsup/cygwin/fhandler_socket_inet.cc b/winsup/cygwin/fhandler_socket_inet.cc
index 1e837d72c..9bdaece5a 100644
--- a/winsup/cygwin/fhandler_socket_inet.cc
+++ b/winsup/cygwin/fhandler_socket_inet.cc
@@ -23,6 +23,7 @@
#endif
#include <w32api/ws2tcpip.h>
#include <w32api/mswsock.h>
+#include <w32api/mstcpip.h>
#include <netinet/tcp.h>
#include <unistd.h>
#include <asm/byteorder.h>
@@ -692,7 +693,10 @@ fhandler_socket_wsock::set_socket_handle (SOCKET sock, int af, int type,
fhandler_socket_inet::fhandler_socket_inet () :
fhandler_socket_wsock (),
oobinline (false),
- tcp_fastopen (false)
+ tcp_fastopen (false),
+ tcp_keepidle (7200), /* WinSock default */
+ tcp_keepcnt (10), /* WinSock default */
+ tcp_keepintvl (1) /* WinSock default */
{
}
@@ -1572,6 +1576,63 @@ fhandler_socket_wsock::writev (const struct iovec *const iov, const int iovcnt,
return send_internal (&wsamsg, 0);
}
+#define MAX_TCP_KEEPIDLE 32767
+#define MAX_TCP_KEEPCNT 255
+#define MAX_TCP_KEEPINTVL 32767
+
+#define FIXED_WSOCK_TCP_KEEPCNT 10
+
+int
+fhandler_socket_inet::set_keepalive (int keepidle, int keepcnt, int keepintvl)
+{
+ struct tcp_keepalive tka;
+ int so_keepalive = 0;
+ int len = sizeof so_keepalive;
+ int ret;
+ DWORD dummy;
+
+ /* Per MSDN,
+ https://docs.microsoft.com/en-us/windows/win32/winsock/sio-keepalive-vals
+ the subsequent keep-alive settings in struct tcp_keepalive are only used
+ if the onoff member is != 0. Request the current state of SO_KEEPALIVE,
+ then set the keep-alive options with onoff set to 1. On success, if
+ SO_KEEPALIVE was 0, restore to the original SO_KEEPALIVE setting. Per
+ the above MSDN doc, the SIO_KEEPALIVE_VALS settings are persistent
+ across switching SO_KEEPALIVE. */
+ ret = ::getsockopt (get_socket (), SOL_SOCKET, SO_KEEPALIVE,
+ (char *) &so_keepalive, &len);
+ if (ret == SOCKET_ERROR)
+ debug_printf ("getsockopt (SO_KEEPALIVE) failed, %u\n", WSAGetLastError ());
+ tka.onoff = 1;
+ tka.keepalivetime = keepidle * MSPERSEC;
+ /* WinSock TCP_KEEPCNT is fixed. But we still want that the keep-alive
+ times out after TCP_KEEPIDLE + TCP_KEEPCNT * TCP_KEEPINTVL secs.
+ To that end, we set keepaliveinterval so that
+
+ keepaliveinterval * FIXED_WSOCK_TCP_KEEPCNT == TCP_KEEPINTVL * TCP_KEEPCNT
+
+ FIXME? Does that make sense?
+
+ Sidenote: Given the max values, the entire operation fits into an int. */
+ tka.keepaliveinterval = MSPERSEC / FIXED_WSOCK_TCP_KEEPCNT * keepcnt
+ * keepintvl;
+ if (WSAIoctl (get_socket (), SIO_KEEPALIVE_VALS, (LPVOID) &tka, sizeof tka,
+ NULL, 0, &dummy, NULL, NULL) == SOCKET_ERROR)
+ {
+ set_winsock_errno ();
+ return -1;
+ }
+ if (!so_keepalive)
+ {
+ ret = ::setsockopt (get_socket (), SOL_SOCKET, SO_KEEPALIVE,
+ (const char *) &so_keepalive, sizeof so_keepalive);
+ if (ret == SOCKET_ERROR)
+ debug_printf ("setsockopt (SO_KEEPALIVE) failed, %u\n",
+ WSAGetLastError ());
+ }
+ return 0;
+}
+
int
fhandler_socket_inet::setsockopt (int level, int optname, const void *optval,
socklen_t optlen)
@@ -1686,6 +1747,14 @@ fhandler_socket_inet::setsockopt (int level, int optname, const void *optval,
break;
case IPPROTO_TCP:
+ /* Check for stream socket early on, so we don't have to do this for
+ every option. Also, WinSock returns EINVAL. */
+ if (type != SOCK_STREAM)
+ {
+ set_errno (EOPNOTSUPP);
+ return -1;
+ }
+
switch (optname)
{
case TCP_MAXSEG:
@@ -1698,13 +1767,56 @@ fhandler_socket_inet::setsockopt (int level, int optname, const void *optval,
/* Fake FastOpen on older systems. */
if (!wincap.has_tcp_fastopen ())
{
- if (type != SOCK_STREAM)
+ ignore = true;
+ tcp_fastopen = *(int *) optval ? true : false;
+ }
+ break;
+
+ case TCP_KEEPIDLE:
+ /* Handle TCP_KEEPIDLE on older systems. */
+ if (!wincap.has_linux_tcp_keepalive_sockopts ())
+ {
+ if (*(int *) optval < 1 || *(int *) optval > MAX_TCP_KEEPIDLE)
{
- set_errno (EOPNOTSUPP);
+ set_errno (EINVAL);
return -1;
}
+ if (set_keepalive (*(int *) optval, tcp_keepcnt, tcp_keepintvl))
+ return -1;
ignore = true;
- tcp_fastopen = *(int *) optval ? true : false;
+ tcp_keepidle = *(int *) optval;
+ }
+ break;
+
+ case TCP_KEEPCNT:
+ /* Fake TCP_KEEPCNT on older systems. */
+ if (!wincap.has_linux_tcp_keepalive_sockopts ())
+ {
+ if (*(int *) optval < 1 || *(int *) optval > MAX_TCP_KEEPCNT)
+ {
+ set_errno (EINVAL);
+ return -1;
+ }
+ if (set_keepalive (tcp_keepidle, *(int *) optval, tcp_keepintvl))
+ return -1;
+ ignore = true;
+ tcp_keepcnt = *(int *) optval;
+ }
+ break;
+
+ case TCP_KEEPINTVL:
+ /* Handle TCP_KEEPINTVL on older systems. */
+ if (!wincap.has_linux_tcp_keepalive_sockopts ())
+ {
+ if (*(int *) optval < 1 || *(int *) optval > MAX_TCP_KEEPINTVL)
+ {
+ set_errno (EINVAL);
+ return -1;
+ }
+ if (set_keepalive (tcp_keepidle, tcp_keepcnt, *(int *) optval))
+ return -1;
+ ignore = true;
+ tcp_keepintvl = *(int *) optval;
}
break;
@@ -1841,23 +1953,56 @@ fhandler_socket_inet::getsockopt (int level, int optname, const void *optval,
break;
case IPPROTO_TCP:
+ /* Check for stream socket early on, so we don't have to do this for
+ every option. Also, WinSock returns EINVAL. */
+ if (type != SOCK_STREAM)
+ {
+ set_errno (EOPNOTSUPP);
+ return -1;
+ }
+
switch (optname)
{
case TCP_FASTOPEN:
/* Fake FastOpen on older systems */
if (!wincap.has_tcp_fastopen ())
{
- if (type != SOCK_STREAM)
- {
- set_errno (EOPNOTSUPP);
- return -1;
- }
*(int *) optval = tcp_fastopen ? 1 : 0;
*optlen = sizeof (int);
return 0;
}
break;
+ case TCP_KEEPIDLE:
+ /* Use stored value on older systems */
+ if (!wincap.has_linux_tcp_keepalive_sockopts ())
+ {
+ *(int *) optval = tcp_keepidle;
+ *optlen = sizeof (int);
+ return 0;
+ }
+ break;
+
+ case TCP_KEEPCNT:
+ /* Use stored value on older systems */
+ if (!wincap.has_linux_tcp_keepalive_sockopts ())
+ {
+ *(int *) optval = tcp_keepcnt;
+ *optlen = sizeof (int);
+ return 0;
+ }
+ break;
+
+ case TCP_KEEPINTVL:
+ /* Use stored value on older systems */
+ if (!wincap.has_linux_tcp_keepalive_sockopts ())
+ {
+ *(int *) optval = tcp_keepintvl;
+ *optlen = sizeof (int);
+ return 0;
+ }
+ break;
+
default:
break;
}
diff --git a/winsup/cygwin/include/netinet/tcp.h b/winsup/cygwin/include/netinet/tcp.h
index ab1cd12bf..9c2e90eaa 100644
--- a/winsup/cygwin/include/netinet/tcp.h
+++ b/winsup/cygwin/include/netinet/tcp.h
@@ -123,8 +123,11 @@ struct tcphdr {
/*
* User-settable options (used with setsockopt).
*/
-#define TCP_NODELAY 0x01 /* don't delay send to coalesce packets */
-#define TCP_MAXSEG 0x04 /* get maximum segment size (r/o on windows) */
-#define TCP_FASTOPEN 0x0f /* enable FastOpen on listeners */
+#define TCP_NODELAY 0x01 /* don't delay send to coalesce packets */
+#define TCP_KEEPIDLE 0x03 /* start keepalives after this period */
+#define TCP_MAXSEG 0x04 /* get maximum segment size (r/o on windows) */
+#define TCP_FASTOPEN 0x0f /* enable FastOpen on listeners */
+#define TCP_KEEPCNT 0x10 /* number of keepalives before death */
+#define TCP_KEEPINTVL 0x11 /* interval between keepalives */
#endif
diff --git a/winsup/cygwin/wincap.cc b/winsup/cygwin/wincap.cc
index be6d71d12..323c5a368 100644
--- a/winsup/cygwin/wincap.cc
+++ b/winsup/cygwin/wincap.cc
@@ -47,6 +47,7 @@ wincaps wincap_vista __attribute__((section (".cygwin_dll_common"), shared)) = {
has_con_esc_rep:false,
has_extended_mem_api:false,
has_tcp_fastopen:false,
+ has_linux_tcp_keepalive_sockopts:false,
},
};
@@ -79,6 +80,7 @@ wincaps wincap_7 __attribute__((section (".cygwin_dll_common"), shared)) = {
has_con_esc_rep:false,
has_extended_mem_api:false,
has_tcp_fastopen:false,
+ has_linux_tcp_keepalive_sockopts:false,
},
};
@@ -111,6 +113,7 @@ wincaps wincap_8 __attribute__((section (".cygwin_dll_common"), shared)) = {
has_con_esc_rep:false,
has_extended_mem_api:false,
has_tcp_fastopen:false,
+ has_linux_tcp_keepalive_sockopts:false,
},
};
@@ -143,6 +146,7 @@ wincaps wincap_8_1 __attribute__((section (".cygwin_dll_common"), shared)) = {
has_con_esc_rep:false,
has_extended_mem_api:false,
has_tcp_fastopen:false,
+ has_linux_tcp_keepalive_sockopts:false,
},
};
@@ -175,6 +179,7 @@ wincaps wincap_10_1507 __attribute__((section (".cygwin_dll_common"), shared))
has_con_esc_rep:false,
has_extended_mem_api:false,
has_tcp_fastopen:false,
+ has_linux_tcp_keepalive_sockopts:false,
},
};
@@ -207,6 +212,7 @@ wincaps wincap_10_1607 __attribute__((section (".cygwin_dll_common"), shared))
has_con_esc_rep:false,
has_extended_mem_api:false,
has_tcp_fastopen:true,
+ has_linux_tcp_keepalive_sockopts:false,
},
};
@@ -239,6 +245,7 @@ wincaps wincap_10_1703 __attribute__((section (".cygwin_dll_common"), shared)) =
has_con_esc_rep:false,
has_extended_mem_api:false,
has_tcp_fastopen:true,
+ has_linux_tcp_keepalive_sockopts:false,
},
};
@@ -271,6 +278,7 @@ wincaps wincap_10_1709 __attribute__((section (".cygwin_dll_common"), shared)) =
has_con_esc_rep:false,
has_extended_mem_api:false,
has_tcp_fastopen:true,
+ has_linux_tcp_keepalive_sockopts:true,
},
};
@@ -303,6 +311,7 @@ wincaps wincap_10_1803 __attribute__((section (".cygwin_dll_common"), shared)) =
has_con_esc_rep:false,
has_extended_mem_api:true,
has_tcp_fastopen:true,
+ has_linux_tcp_keepalive_sockopts:true,
},
};
@@ -335,6 +344,7 @@ wincaps wincap_10_1809 __attribute__((section (".cygwin_dll_common"), shared)) =
has_con_esc_rep:false,
has_extended_mem_api:true,
has_tcp_fastopen:true,
+ has_linux_tcp_keepalive_sockopts:true,
},
};
@@ -367,6 +377,7 @@ wincaps wincap_10_1903 __attribute__((section (".cygwin_dll_common"), shared)) =
has_con_esc_rep:true,
has_extended_mem_api:true,
has_tcp_fastopen:true,
+ has_linux_tcp_keepalive_sockopts:true,
},
};
diff --git a/winsup/cygwin/wincap.h b/winsup/cygwin/wincap.h
index 54a880af7..26c4c01ef 100644
--- a/winsup/cygwin/wincap.h
+++ b/winsup/cygwin/wincap.h
@@ -41,6 +41,7 @@ struct wincaps
unsigned has_con_esc_rep : 1;
unsigned has_extended_mem_api : 1;
unsigned has_tcp_fastopen : 1;
+ unsigned has_linux_tcp_keepalive_sockopts : 1;
};
};
@@ -105,6 +106,7 @@ public:
bool IMPLEMENT (has_con_esc_rep)
bool IMPLEMENT (has_extended_mem_api)
bool IMPLEMENT (has_tcp_fastopen)
+ bool IMPLEMENT (has_linux_tcp_keepalive_sockopts)
void disable_case_sensitive_dirs ()
{
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2020-07-01 18:32 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-07-01 18:32 [newlib-cygwin] Cygwin: tcp: Support TCP_KEEPIDLE, TCP_KEEPCNT, TCP_KEEPINTVL Corinna Vinschen
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).