// 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 })