mirror of
https://github.com/golang/go.git
synced 2025-10-19 11:03:18 +00:00
net: avoid using Windows' TransmitFile on non-server machines
This commit is contained in:
parent
c8bf388bad
commit
315ddc0cd8
8 changed files with 72 additions and 12 deletions
|
@ -256,3 +256,7 @@ type FILE_COMPLETION_INFORMATION struct {
|
|||
Port syscall.Handle
|
||||
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"
|
||||
)
|
||||
|
||||
// https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_osversioninfow
|
||||
type _OSVERSIONINFOW struct {
|
||||
// https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_osversioninfoexw
|
||||
type _OSVERSIONINFOEXW struct {
|
||||
osVersionInfoSize uint32
|
||||
majorVersion uint32
|
||||
minorVersion uint32
|
||||
buildNumber uint32
|
||||
platformId uint32
|
||||
csdVersion [128]uint16
|
||||
servicePackMajor uint16
|
||||
servicePackMinor uint16
|
||||
suiteMask uint16
|
||||
productType byte
|
||||
reserved byte
|
||||
}
|
||||
|
||||
// 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
|
||||
// of the current Windows OS from the RtlGetVersion API.
|
||||
func Version() (major, minor, build uint32) {
|
||||
info := _OSVERSIONINFOW{}
|
||||
info.osVersionInfoSize = uint32(unsafe.Sizeof(info))
|
||||
rtlGetVersion(&info)
|
||||
info := getVersionInfo()
|
||||
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 (
|
||||
supportTCPKeepAliveIdle bool
|
||||
supportTCPKeepAliveInterval bool
|
||||
|
|
|
@ -539,7 +539,7 @@ func NtSetInformationFile(handle syscall.Handle, iosb *IO_STATUS_BLOCK, inBuffer
|
|||
return
|
||||
}
|
||||
|
||||
func rtlGetVersion(info *_OSVERSIONINFOW) {
|
||||
func rtlGetVersion(info *_OSVERSIONINFOEXW) {
|
||||
syscall.Syscall(procRtlGetVersion.Addr(), 1, uintptr(unsafe.Pointer(info)), 0, 0)
|
||||
return
|
||||
}
|
||||
|
|
|
@ -12,8 +12,6 @@ import (
|
|||
"syscall"
|
||||
)
|
||||
|
||||
const supportsSendfile = true
|
||||
|
||||
// sendFile copies the contents of r to c using the sendfile
|
||||
// system call to minimize copies.
|
||||
//
|
||||
|
@ -22,6 +20,9 @@ const supportsSendfile = true
|
|||
//
|
||||
// if handled == false, sendFile performed no work.
|
||||
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
|
||||
lr, ok := r.(*io.LimitedReader)
|
||||
if ok {
|
||||
|
|
12
src/net/sendfile_nonwindows.go
Normal file
12
src/net/sendfile_nonwindows.go
Normal file
|
@ -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"
|
||||
|
||||
const supportsSendfile = false
|
||||
func supportsSendfile() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func sendFile(c *netFD, r io.Reader) (n int64, err error, handled bool) {
|
||||
return 0, nil, false
|
||||
|
|
|
@ -31,11 +31,11 @@ const (
|
|||
// expectSendfile runs f, and verifies that internal/poll.SendFile successfully handles
|
||||
// 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.
|
||||
func expectSendfile(t *testing.T, wantConn Conn, f func()) {
|
||||
t.Helper()
|
||||
if !supportsSendfile {
|
||||
if !supportsSendfile() {
|
||||
f()
|
||||
return
|
||||
}
|
||||
|
|
16
src/net/sendfile_windows.go
Normal file
16
src/net/sendfile_windows.go
Normal file
|
@ -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…
Add table
Add a link
Reference in a new issue