github.com/ice-blockchain/go/src@v0.0.0-20240403114104-1564d284e521/internal/syscall/windows/version_windows.go (about) 1 // Copyright 2024 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package windows 6 7 import ( 8 "errors" 9 "sync" 10 "syscall" 11 "unsafe" 12 ) 13 14 // https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_osversioninfow 15 type _OSVERSIONINFOW struct { 16 osVersionInfoSize uint32 17 majorVersion uint32 18 minorVersion uint32 19 buildNumber uint32 20 platformId uint32 21 csdVersion [128]uint16 22 } 23 24 // According to documentation, RtlGetVersion function always succeeds. 25 //sys rtlGetVersion(info *_OSVERSIONINFOW) = ntdll.RtlGetVersion 26 27 // version retrieves the major, minor, and build version numbers 28 // of the current Windows OS from the RtlGetVersion API. 29 func version() (major, minor, build uint32) { 30 info := _OSVERSIONINFOW{} 31 info.osVersionInfoSize = uint32(unsafe.Sizeof(info)) 32 rtlGetVersion(&info) 33 return info.majorVersion, info.minorVersion, info.buildNumber 34 } 35 36 var ( 37 supportTCPKeepAliveIdle bool 38 supportTCPKeepAliveInterval bool 39 supportTCPKeepAliveCount bool 40 ) 41 42 var initTCPKeepAlive = sync.OnceFunc(func() { 43 s, err := WSASocket(syscall.AF_INET, syscall.SOCK_STREAM, syscall.IPPROTO_TCP, nil, 0, WSA_FLAG_NO_HANDLE_INHERIT) 44 if err != nil { 45 // Fallback to checking the Windows version. 46 major, _, build := version() 47 supportTCPKeepAliveIdle = major >= 10 && build >= 16299 48 supportTCPKeepAliveInterval = major >= 10 && build >= 16299 49 supportTCPKeepAliveCount = major >= 10 && build >= 15063 50 return 51 } 52 defer syscall.Closesocket(s) 53 var optSupported = func(opt int) bool { 54 err := syscall.SetsockoptInt(s, syscall.IPPROTO_TCP, opt, 1) 55 return !errors.Is(err, syscall.WSAENOPROTOOPT) 56 } 57 supportTCPKeepAliveIdle = optSupported(TCP_KEEPIDLE) 58 supportTCPKeepAliveInterval = optSupported(TCP_KEEPINTVL) 59 supportTCPKeepAliveCount = optSupported(TCP_KEEPCNT) 60 }) 61 62 // SupportTCPKeepAliveInterval indicates whether TCP_KEEPIDLE is supported. 63 // The minimal requirement is Windows 10.0.16299. 64 func SupportTCPKeepAliveIdle() bool { 65 initTCPKeepAlive() 66 return supportTCPKeepAliveIdle 67 } 68 69 // SupportTCPKeepAliveInterval indicates whether TCP_KEEPINTVL is supported. 70 // The minimal requirement is Windows 10.0.16299. 71 func SupportTCPKeepAliveInterval() bool { 72 initTCPKeepAlive() 73 return supportTCPKeepAliveInterval 74 } 75 76 // SupportTCPKeepAliveCount indicates whether TCP_KEEPCNT is supported. 77 // supports TCP_KEEPCNT. 78 // The minimal requirement is Windows 10.0.15063. 79 func SupportTCPKeepAliveCount() bool { 80 initTCPKeepAlive() 81 return supportTCPKeepAliveCount 82 } 83 84 // SupportTCPInitialRTONoSYNRetransmissions indicates whether the current 85 // Windows version supports the TCP_INITIAL_RTO_NO_SYN_RETRANSMISSIONS. 86 // The minimal requirement is Windows 10.0.16299. 87 var SupportTCPInitialRTONoSYNRetransmissions = sync.OnceValue(func() bool { 88 major, _, build := version() 89 return major >= 10 && build >= 16299 90 }) 91 92 // SupportUnixSocket indicates whether the current Windows version supports 93 // Unix Domain Sockets. 94 // The minimal requirement is Windows 10.0.17063. 95 var SupportUnixSocket = sync.OnceValue(func() bool { 96 var size uint32 97 // First call to get the required buffer size in bytes. 98 // Ignore the error, it will always fail. 99 _, _ = syscall.WSAEnumProtocols(nil, nil, &size) 100 n := int32(size) / int32(unsafe.Sizeof(syscall.WSAProtocolInfo{})) 101 // Second call to get the actual protocols. 102 buf := make([]syscall.WSAProtocolInfo, n) 103 n, err := syscall.WSAEnumProtocols(nil, &buf[0], &size) 104 if err != nil { 105 return false 106 } 107 for i := int32(0); i < n; i++ { 108 if buf[i].AddressFamily == syscall.AF_UNIX { 109 return true 110 } 111 } 112 return false 113 })