mirror of https://github.com/golang/go.git
net: avoid using Windows' TransmitFile on non-server machines
This commit is contained in:
parent
c8bf388bad
commit
315ddc0cd8
|
|
@ -256,3 +256,7 @@ type FILE_COMPLETION_INFORMATION struct {
|
||||||
Port syscall.Handle
|
Port syscall.Handle
|
||||||
Key uintptr
|
Key uintptr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-osversioninfoexa
|
||||||
|
// https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_osversioninfoexw
|
||||||
|
const VER_NT_WORKSTATION = 0x0000001
|
||||||
|
|
|
||||||
|
|
@ -11,28 +11,53 @@ import (
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
// https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_osversioninfow
|
// https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_osversioninfoexw
|
||||||
type _OSVERSIONINFOW struct {
|
type _OSVERSIONINFOEXW struct {
|
||||||
osVersionInfoSize uint32
|
osVersionInfoSize uint32
|
||||||
majorVersion uint32
|
majorVersion uint32
|
||||||
minorVersion uint32
|
minorVersion uint32
|
||||||
buildNumber uint32
|
buildNumber uint32
|
||||||
platformId uint32
|
platformId uint32
|
||||||
csdVersion [128]uint16
|
csdVersion [128]uint16
|
||||||
|
servicePackMajor uint16
|
||||||
|
servicePackMinor uint16
|
||||||
|
suiteMask uint16
|
||||||
|
productType byte
|
||||||
|
reserved byte
|
||||||
}
|
}
|
||||||
|
|
||||||
// According to documentation, RtlGetVersion function always succeeds.
|
// According to documentation, RtlGetVersion function always succeeds.
|
||||||
//sys rtlGetVersion(info *_OSVERSIONINFOW) = ntdll.RtlGetVersion
|
//sys rtlGetVersion(info *_OSVERSIONINFOEXW) = ntdll.RtlGetVersion
|
||||||
|
|
||||||
|
// Retrieves version information of the current Windows OS
|
||||||
|
// from the RtlGetVersion API.
|
||||||
|
func getVersionInfo() *_OSVERSIONINFOEXW {
|
||||||
|
info := _OSVERSIONINFOEXW{}
|
||||||
|
info.osVersionInfoSize = uint32(unsafe.Sizeof(info))
|
||||||
|
rtlGetVersion(&info)
|
||||||
|
return &info
|
||||||
|
}
|
||||||
|
|
||||||
// Version retrieves the major, minor, and build version numbers
|
// Version retrieves the major, minor, and build version numbers
|
||||||
// of the current Windows OS from the RtlGetVersion API.
|
// of the current Windows OS from the RtlGetVersion API.
|
||||||
func Version() (major, minor, build uint32) {
|
func Version() (major, minor, build uint32) {
|
||||||
info := _OSVERSIONINFOW{}
|
info := getVersionInfo()
|
||||||
info.osVersionInfoSize = uint32(unsafe.Sizeof(info))
|
|
||||||
rtlGetVersion(&info)
|
|
||||||
return info.majorVersion, info.minorVersion, info.buildNumber
|
return info.majorVersion, info.minorVersion, info.buildNumber
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SupportUnlimitedTransmitFile indicates whether the current
|
||||||
|
// Windows version's TransmitFile function imposes any
|
||||||
|
// concurrent operation limits.
|
||||||
|
// Workstation and client versions of Windows limit the number
|
||||||
|
// of concurrent TransmitFile operations allowed on the system
|
||||||
|
// to a maximum of two. Please see:
|
||||||
|
// https://learn.microsoft.com/en-us/windows/win32/api/mswsock/nf-mswsock-transmitfile
|
||||||
|
// https://golang.org/issue/73746
|
||||||
|
var SupportUnlimitedTransmitFile = sync.OnceValue(func() bool {
|
||||||
|
info := getVersionInfo()
|
||||||
|
return info.productType != VER_NT_WORKSTATION
|
||||||
|
})
|
||||||
|
|
||||||
var (
|
var (
|
||||||
supportTCPKeepAliveIdle bool
|
supportTCPKeepAliveIdle bool
|
||||||
supportTCPKeepAliveInterval bool
|
supportTCPKeepAliveInterval bool
|
||||||
|
|
|
||||||
|
|
@ -539,7 +539,7 @@ func NtSetInformationFile(handle syscall.Handle, iosb *IO_STATUS_BLOCK, inBuffer
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func rtlGetVersion(info *_OSVERSIONINFOW) {
|
func rtlGetVersion(info *_OSVERSIONINFOEXW) {
|
||||||
syscall.Syscall(procRtlGetVersion.Addr(), 1, uintptr(unsafe.Pointer(info)), 0, 0)
|
syscall.Syscall(procRtlGetVersion.Addr(), 1, uintptr(unsafe.Pointer(info)), 0, 0)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,6 @@ import (
|
||||||
"syscall"
|
"syscall"
|
||||||
)
|
)
|
||||||
|
|
||||||
const supportsSendfile = true
|
|
||||||
|
|
||||||
// sendFile copies the contents of r to c using the sendfile
|
// sendFile copies the contents of r to c using the sendfile
|
||||||
// system call to minimize copies.
|
// system call to minimize copies.
|
||||||
//
|
//
|
||||||
|
|
@ -22,6 +20,9 @@ const supportsSendfile = true
|
||||||
//
|
//
|
||||||
// if handled == false, sendFile performed no work.
|
// if handled == false, sendFile performed no work.
|
||||||
func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) {
|
func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) {
|
||||||
|
if !supportsSendfile() {
|
||||||
|
return 0, nil, false
|
||||||
|
}
|
||||||
var remain int64 = 0 // 0 writes the entire file
|
var remain int64 = 0 // 0 writes the entire file
|
||||||
lr, ok := r.(*io.LimitedReader)
|
lr, ok := r.(*io.LimitedReader)
|
||||||
if ok {
|
if ok {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
// Copyright 2025 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.
|
||||||
|
|
||||||
|
//go:build linux || (darwin && !ios) || dragonfly || freebsd || solaris
|
||||||
|
|
||||||
|
package net
|
||||||
|
|
||||||
|
// Always true except for workstation and client versions of Windows
|
||||||
|
func supportsSendfile() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
@ -8,7 +8,9 @@ package net
|
||||||
|
|
||||||
import "io"
|
import "io"
|
||||||
|
|
||||||
const supportsSendfile = false
|
func supportsSendfile() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func sendFile(c *netFD, r io.Reader) (n int64, err error, handled bool) {
|
func sendFile(c *netFD, r io.Reader) (n int64, err error, handled bool) {
|
||||||
return 0, nil, false
|
return 0, nil, false
|
||||||
|
|
|
||||||
|
|
@ -31,11 +31,11 @@ const (
|
||||||
// expectSendfile runs f, and verifies that internal/poll.SendFile successfully handles
|
// expectSendfile runs f, and verifies that internal/poll.SendFile successfully handles
|
||||||
// a write to wantConn during f's execution.
|
// a write to wantConn during f's execution.
|
||||||
//
|
//
|
||||||
// On platforms where supportsSendfile is false, expectSendfile runs f but does not
|
// On platforms where supportsSendfile() is false, expectSendfile runs f but does not
|
||||||
// expect a call to SendFile.
|
// expect a call to SendFile.
|
||||||
func expectSendfile(t *testing.T, wantConn Conn, f func()) {
|
func expectSendfile(t *testing.T, wantConn Conn, f func()) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
if !supportsSendfile {
|
if !supportsSendfile() {
|
||||||
f()
|
f()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
// Copyright 2025 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 net
|
||||||
|
|
||||||
|
import "internal/syscall/windows"
|
||||||
|
|
||||||
|
// Workstation and client versions of Windows limit the number
|
||||||
|
// of concurrent TransmitFile operations allowed on the system
|
||||||
|
// to a maximum of two. Please see:
|
||||||
|
// https://learn.microsoft.com/en-us/windows/win32/api/mswsock/nf-mswsock-transmitfile
|
||||||
|
// https://golang.org/issue/73746
|
||||||
|
func supportsSendfile() bool {
|
||||||
|
return windows.SupportUnlimitedTransmitFile()
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue