version_windows.mx raw
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-_osversioninfoexw
15 type _OSVERSIONINFOEXW struct {
16 osVersionInfoSize uint32
17 majorVersion uint32
18 minorVersion uint32
19 buildNumber uint32
20 platformId uint32
21 csdVersion [128]uint16
22 servicePackMajor uint16
23 servicePackMinor uint16
24 suiteMask uint16
25 productType byte
26 reserved byte
27 }
28
29 // According to documentation, RtlGetVersion function always succeeds.
30 //sys rtlGetVersion(info *_OSVERSIONINFOEXW) = ntdll.RtlGetVersion
31
32 // Retrieves version information of the current Windows OS
33 // from the RtlGetVersion API.
34 func getVersionInfo() *_OSVERSIONINFOEXW {
35 info := _OSVERSIONINFOEXW{}
36 info.osVersionInfoSize = uint32(unsafe.Sizeof(info))
37 rtlGetVersion(&info)
38 return &info
39 }
40
41 // Version retrieves the major, minor, and build version numbers
42 // of the current Windows OS from the RtlGetVersion API.
43 func Version() (major, minor, build uint32) {
44 info := getVersionInfo()
45 return info.majorVersion, info.minorVersion, info.buildNumber
46 }
47
48 // SupportUnlimitedTransmitFile indicates whether the current
49 // Windows version's TransmitFile function imposes any
50 // concurrent operation limits.
51 // Workstation and client versions of Windows limit the number
52 // of concurrent TransmitFile operations allowed on the system
53 // to a maximum of two. Please see:
54 // https://learn.microsoft.com/en-us/windows/win32/api/mswsock/nf-mswsock-transmitfile
55 // https://golang.org/issue/73746
56 var SupportUnlimitedTransmitFile = sync.OnceValue(func() bool {
57 info := getVersionInfo()
58 return info.productType != VER_NT_WORKSTATION
59 })
60
61 var (
62 supportTCPKeepAliveIdle bool
63 supportTCPKeepAliveInterval bool
64 supportTCPKeepAliveCount bool
65 )
66
67 var initTCPKeepAlive = sync.OnceFunc(func() {
68 s, err := WSASocket(syscall.AF_INET, syscall.SOCK_STREAM, syscall.IPPROTO_TCP, nil, 0, WSA_FLAG_NO_HANDLE_INHERIT)
69 if err != nil {
70 // Fallback to checking the Windows version.
71 major, _, build := Version()
72 supportTCPKeepAliveIdle = major >= 10 && build >= 16299
73 supportTCPKeepAliveInterval = major >= 10 && build >= 16299
74 supportTCPKeepAliveCount = major >= 10 && build >= 15063
75 return
76 }
77 defer syscall.Closesocket(s)
78 var optSupported = func(opt int) bool {
79 err := syscall.SetsockoptInt(s, syscall.IPPROTO_TCP, opt, 1)
80 return !errors.Is(err, syscall.WSAENOPROTOOPT)
81 }
82 supportTCPKeepAliveIdle = optSupported(TCP_KEEPIDLE)
83 supportTCPKeepAliveInterval = optSupported(TCP_KEEPINTVL)
84 supportTCPKeepAliveCount = optSupported(TCP_KEEPCNT)
85 })
86
87 // SupportTCPKeepAliveIdle indicates whether TCP_KEEPIDLE is supported.
88 // The minimal requirement is Windows 10.0.16299.
89 func SupportTCPKeepAliveIdle() bool {
90 initTCPKeepAlive()
91 return supportTCPKeepAliveIdle
92 }
93
94 // SupportTCPKeepAliveInterval indicates whether TCP_KEEPINTVL is supported.
95 // The minimal requirement is Windows 10.0.16299.
96 func SupportTCPKeepAliveInterval() bool {
97 initTCPKeepAlive()
98 return supportTCPKeepAliveInterval
99 }
100
101 // SupportTCPKeepAliveCount indicates whether TCP_KEEPCNT is supported.
102 // supports TCP_KEEPCNT.
103 // The minimal requirement is Windows 10.0.15063.
104 func SupportTCPKeepAliveCount() bool {
105 initTCPKeepAlive()
106 return supportTCPKeepAliveCount
107 }
108
109 // SupportTCPInitialRTONoSYNRetransmissions indicates whether the current
110 // Windows version supports the TCP_INITIAL_RTO_NO_SYN_RETRANSMISSIONS.
111 // The minimal requirement is Windows 10.0.16299.
112 var SupportTCPInitialRTONoSYNRetransmissions = sync.OnceValue(func() bool {
113 major, _, build := Version()
114 return major >= 10 && build >= 16299
115 })
116
117 // SupportUnixSocket indicates whether the current Windows version supports
118 // Unix Domain Sockets.
119 // The minimal requirement is Windows 10.0.17063.
120 var SupportUnixSocket = sync.OnceValue(func() bool {
121 var size uint32
122 // First call to get the required buffer size in bytes.
123 // Ignore the error, it will always fail.
124 _, _ = syscall.WSAEnumProtocols(nil, nil, &size)
125 n := int32(size) / int32(unsafe.Sizeof(syscall.WSAProtocolInfo{}))
126 // Second call to get the actual protocols.
127 buf := make([]syscall.WSAProtocolInfo, n)
128 n, err := syscall.WSAEnumProtocols(nil, &buf[0], &size)
129 if err != nil {
130 return false
131 }
132 for i := int32(0); i < n; i++ {
133 if buf[i].AddressFamily == syscall.AF_UNIX {
134 return true
135 }
136 }
137 return false
138 })
139