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