1
0
mirror of https://github.com/golang/go synced 2024-09-28 17:24:28 -06:00

net,internal/syscall/windows: prove that keep alive options exists

The net package currently uses windows.SupportFullTCPKeepAlive to
know if TCP_KEEPIDLE, TCP_KEEPINTVL, and TCP_KEEPCNT are available.
This function is a wrapper over the undocumented RtlGetNtVersionNumbers
API, which tests if the Windows version is at least 10.0.16299. This
approach artificially limits the use of TCP_KEEPCNT, which is
available since Windows 10.0.15063. It also uses an undocumented API,
which is not something we want to rely on.

This CL removes windows.SupportFullTCPKeepAlive in favor of dedicated
proves for each option which are not based on the Windows version.

While here, remove some assertions in setKeepAliveCount. It is better
to let the system decide if the value is valid or not.

Updates #65817.

Cq-Include-Trybots: luci.golang.try:gotip-windows-arm64
Change-Id: I0fe70d46c8675eab06c0e4628cf68571b6e50b80
Reviewed-on: https://go-review.googlesource.com/c/go/+/570077
Reviewed-by: Than McIntosh <thanm@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Alex Brainman <alex.brainman@gmail.com>
This commit is contained in:
qmuntal 2024-03-08 15:40:34 +01:00 committed by Quim Muntal
parent f268539544
commit 68a508cdaf
4 changed files with 51 additions and 19 deletions

View File

@ -5,6 +5,7 @@
package windows
import (
"errors"
"sync"
"syscall"
"unsafe"
@ -23,14 +24,54 @@ func version() (major, minor, build uint32) {
//go:noescape
func rtlGetNtVersionNumbers(majorVersion *uint32, minorVersion *uint32, buildNumber *uint32)
// SupportFullTCPKeepAlive indicates whether the current Windows version
// supports the full TCP keep-alive configurations.
// The minimal requirement is Windows 10.0.16299.
var SupportFullTCPKeepAlive = sync.OnceValue(func() bool {
major, _, build := version()
return major >= 10 && build >= 16299
var (
supportTCPKeepAliveIdle bool
supportTCPKeepAliveInterval bool
supportTCPKeepAliveCount bool
)
var initTCPKeepAlive = sync.OnceFunc(func() {
s, err := WSASocket(syscall.AF_INET, syscall.SOCK_STREAM, syscall.IPPROTO_TCP, nil, 0, WSA_FLAG_NO_HANDLE_INHERIT)
if err != nil {
// Fallback to checking the Windows version.
major, _, build := version()
supportTCPKeepAliveIdle = major >= 10 && build >= 16299
supportTCPKeepAliveInterval = major >= 10 && build >= 16299
supportTCPKeepAliveCount = major >= 10 && build >= 15063
return
}
defer syscall.Closesocket(s)
var optSupported = func(opt int) bool {
err := syscall.SetsockoptInt(s, syscall.IPPROTO_TCP, opt, 1)
return !errors.Is(err, syscall.WSAENOPROTOOPT)
}
supportTCPKeepAliveIdle = optSupported(TCP_KEEPIDLE)
supportTCPKeepAliveInterval = optSupported(TCP_KEEPINTVL)
supportTCPKeepAliveCount = optSupported(TCP_KEEPCNT)
})
// SupportTCPKeepAliveInterval indicates whether TCP_KEEPIDLE is supported.
// The minimal requirement is Windows 10.0.16299.
func SupportTCPKeepAliveIdle() bool {
initTCPKeepAlive()
return supportTCPKeepAliveIdle
}
// SupportTCPKeepAliveInterval indicates whether TCP_KEEPINTVL is supported.
// The minimal requirement is Windows 10.0.16299.
func SupportTCPKeepAliveInterval() bool {
initTCPKeepAlive()
return supportTCPKeepAliveInterval
}
// SupportTCPKeepAliveCount indicates whether TCP_KEEPCNT is supported.
// supports TCP_KEEPCNT.
// The minimal requirement is Windows 10.0.15063.
func SupportTCPKeepAliveCount() bool {
initTCPKeepAlive()
return supportTCPKeepAliveCount
}
// SupportTCPInitialRTONoSYNRetransmissions indicates whether the current
// Windows version supports the TCP_INITIAL_RTO_NO_SYN_RETRANSMISSIONS.
// The minimal requirement is Windows 10.0.16299.

View File

@ -25,7 +25,7 @@ func maybeSkipKeepAliveTest(t *testing.T) {
// doesn't provide any ways to retrieve the current TCP keep-alive settings, therefore
// we're not able to run the test suite similar to Unix-like OS's on Windows.
// Try to find another proper approach to test the keep-alive settings on old Windows.
if !windows.SupportFullTCPKeepAlive() {
if !windows.SupportTCPKeepAliveIdle() || !windows.SupportTCPKeepAliveInterval() || !windows.SupportTCPKeepAliveCount() {
t.Skip("skipping on windows")
}
}

View File

@ -18,7 +18,7 @@ func (c *TCPConn) SetKeepAliveConfig(config KeepAliveConfig) error {
if err := setKeepAlive(c.fd, config.Enable); err != nil {
return &OpError{Op: "set", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
}
if windows.SupportFullTCPKeepAlive() {
if windows.SupportTCPKeepAliveIdle() && windows.SupportTCPKeepAliveInterval() {
if err := setKeepAliveIdle(c.fd, config.Idle); err != nil {
return &OpError{Op: "set", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
}

View File

@ -21,7 +21,7 @@ const (
)
func setKeepAliveIdle(fd *netFD, d time.Duration) error {
if !windows.SupportFullTCPKeepAlive() {
if !windows.SupportTCPKeepAliveIdle() {
return setKeepAliveIdleAndInterval(fd, d, -1)
}
@ -38,7 +38,7 @@ func setKeepAliveIdle(fd *netFD, d time.Duration) error {
}
func setKeepAliveInterval(fd *netFD, d time.Duration) error {
if !windows.SupportFullTCPKeepAlive() {
if !windows.SupportTCPKeepAliveInterval() {
return setKeepAliveIdleAndInterval(fd, -1, d)
}
@ -61,15 +61,6 @@ func setKeepAliveCount(fd *netFD, n int) error {
return nil
}
// This value is not capable to be changed on old versions of Windows.
if !windows.SupportFullTCPKeepAlive() {
return syscall.WSAENOPROTOOPT
}
// It is illegal to set TCP_KEEPCNT to a value greater than 255.
if n > 255 {
return syscall.EINVAL
}
err := fd.pfd.SetsockoptInt(syscall.IPPROTO_TCP, windows.TCP_KEEPCNT, n)
runtime.KeepAlive(fd)
return os.NewSyscallError("setsockopt", err)