blob: ff21fc59e5bf53320c5eefc392d9548f87a2d9b1 [file] [log] [blame]
// Copyright 2024 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package windows
import (
"errors"
"sync"
"syscall"
"unsafe"
)
// https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_osversioninfow
type _OSVERSIONINFOW struct {
osVersionInfoSize uint32
majorVersion uint32
minorVersion uint32
buildNumber uint32
platformId uint32
csdVersion [128]uint16
}
// According to documentation, RtlGetVersion function always succeeds.
//sys rtlGetVersion(info *_OSVERSIONINFOW) = ntdll.RtlGetVersion
// version retrieves the major, minor, and build version numbers
// of the current Windows OS from the RtlGetVersion API.
func version() (major, minor, build uint32) {
info := _OSVERSIONINFOW{}
info.osVersionInfoSize = uint32(unsafe.Sizeof(info))
rtlGetVersion(&info)
return info.majorVersion, info.minorVersion, info.buildNumber
}
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.
var SupportTCPInitialRTONoSYNRetransmissions = sync.OnceValue(func() bool {
major, _, build := version()
return major >= 10 && build >= 16299
})
// SupportUnixSocket indicates whether the current Windows version supports
// Unix Domain Sockets.
// The minimal requirement is Windows 10.0.17063.
var SupportUnixSocket = sync.OnceValue(func() bool {
var size uint32
// First call to get the required buffer size in bytes.
// Ignore the error, it will always fail.
_, _ = syscall.WSAEnumProtocols(nil, nil, &size)
n := int32(size) / int32(unsafe.Sizeof(syscall.WSAProtocolInfo{}))
// Second call to get the actual protocols.
buf := make([]syscall.WSAProtocolInfo, n)
n, err := syscall.WSAEnumProtocols(nil, &buf[0], &size)
if err != nil {
return false
}
for i := int32(0); i < n; i++ {
if buf[i].AddressFamily == syscall.AF_UNIX {
return true
}
}
return false
})