Source file src/internal/syscall/windows/version_windows.go

     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  

View as plain text