Skip to content

Commit 3f6b8ea

Browse files
committed
net: bypass concurrency-limited WinAPI TransmitFile function
1 parent 42f9ee9 commit 3f6b8ea

File tree

7 files changed

+57
-9
lines changed

7 files changed

+57
-9
lines changed

src/internal/syscall/windows/types_windows.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,3 +256,7 @@ type FILE_COMPLETION_INFORMATION struct {
256256
Port syscall.Handle
257257
Key uintptr
258258
}
259+
260+
// https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-osversioninfoexa
261+
// https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_osversioninfoexw
262+
const VER_NT_WORKSTATION = 0x0000001

src/internal/syscall/windows/version_windows.go

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,28 +11,52 @@ import (
1111
"unsafe"
1212
)
1313

14-
// https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_osversioninfow
15-
type _OSVERSIONINFOW struct {
14+
// https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_osversioninfoexw
15+
type _OSVERSIONINFOEXW struct {
1616
osVersionInfoSize uint32
1717
majorVersion uint32
1818
minorVersion uint32
1919
buildNumber uint32
2020
platformId uint32
2121
csdVersion [128]uint16
22+
servicePackMajor uint16
23+
servicePackMinor uint16
24+
suiteMask uint16
25+
productType byte
26+
reserved byte
2227
}
2328

2429
// According to documentation, RtlGetVersion function always succeeds.
25-
//sys rtlGetVersion(info *_OSVERSIONINFOW) = ntdll.RtlGetVersion
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+
}
2640

2741
// Version retrieves the major, minor, and build version numbers
2842
// of the current Windows OS from the RtlGetVersion API.
2943
func Version() (major, minor, build uint32) {
30-
info := _OSVERSIONINFOW{}
31-
info.osVersionInfoSize = uint32(unsafe.Sizeof(info))
32-
rtlGetVersion(&info)
44+
info := getVersionInfo()
3345
return info.majorVersion, info.minorVersion, info.buildNumber
3446
}
3547

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.
54+
// See remarks under https://learn.microsoft.com/en-us/windows/win32/api/mswsock/nf-mswsock-transmitfile
55+
var SupportUnlimitedTransmitFile = sync.OnceValue(func() bool {
56+
info := getVersionInfo()
57+
return info.productType != VER_NT_WORKSTATION
58+
})
59+
3660
var (
3761
supportTCPKeepAliveIdle bool
3862
supportTCPKeepAliveInterval bool

src/internal/syscall/windows/zsyscall_windows.go

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/net/tcpsock_posix.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,10 @@ func (c *TCPConn) readFrom(r io.Reader) (int64, error) {
4848
if n, err, handled := spliceFrom(c.fd, r); handled {
4949
return n, err
5050
}
51-
if n, err, handled := sendFile(c.fd, r); handled {
52-
return n, err
51+
if osSupportsUnlimitedSendFile() {
52+
if n, err, handled := sendFile(c.fd, r); handled {
53+
return n, err
54+
}
5355
}
5456
return genericReadFrom(c, r)
5557
}

src/net/tcpsock_solaris.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,8 @@ func (c *TCPConn) SetKeepAliveConfig(config KeepAliveConfig) error {
3636

3737
return nil
3838
}
39+
40+
// Always true except for workstation and client versions of Windows
41+
func osSupportsUnlimitedSendFile() bool {
42+
return true
43+
}

src/net/tcpsock_unix.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,8 @@ func (c *TCPConn) SetKeepAliveConfig(config KeepAliveConfig) error {
2929

3030
return nil
3131
}
32+
33+
// Always true except for workstation and client versions of Windows
34+
func osSupportsUnlimitedSendFile() bool {
35+
return true
36+
}

src/net/tcpsock_windows.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,11 @@ func (c *TCPConn) SetKeepAliveConfig(config KeepAliveConfig) error {
3434

3535
return nil
3636
}
37+
38+
// Workstation and client versions of Windows limit the number
39+
// of concurrent TransmitFile operations allowed on the system
40+
// to a maximum of two.
41+
// See remarks under https://learn.microsoft.com/en-us/windows/win32/api/mswsock/nf-mswsock-transmitfile
42+
func osSupportsUnlimitedSendFile() bool {
43+
return windows.SupportUnlimitedTransmitFile()
44+
}

0 commit comments

Comments
 (0)