Skip to content

Commit 1965256

Browse files
panjf2000pull[bot]
authored andcommitted
net: support TCP_KEEPIDLE, TCP_KEEPINTVL and TCP_KEEPCNT on newer Windows
Follows up CL 542275 Fixes #65817 Change-Id: I0b77c23f15d595d58492dfa20839a08e8670448b Reviewed-on: https://go-review.googlesource.com/c/go/+/565495 Reviewed-by: Quim Muntal <[email protected]> Reviewed-by: Michael Knyszek <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Damien Neil <[email protected]>
1 parent f09e323 commit 1965256

16 files changed

+311
-275
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
The [`GetsockoptInt`](/syscall#GetsockoptInt) function is now supported on Windows.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
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+
// Socket related.
8+
const (
9+
TCP_KEEPIDLE = 0x03
10+
TCP_KEEPCNT = 0x10
11+
TCP_KEEPINTVL = 0x11
12+
)
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
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 "sync"
8+
9+
// Version retrieves the major, minor, and build version numbers
10+
// of the current Windows OS from the RtlGetNtVersionNumbers API
11+
// and parse the results properly.
12+
func Version() (major, minor, build uint32) {
13+
rtlGetNtVersionNumbers(&major, &minor, &build)
14+
build &= 0x7fff
15+
return
16+
}
17+
18+
// SupportFullTCPKeepAlive indicates whether the current Windows version
19+
// supports the full TCP keep-alive configurations, the minimal requirement
20+
// is Windows 10, version 1709.
21+
var SupportFullTCPKeepAlive = sync.OnceValue(func() bool {
22+
major, _, build := Version()
23+
return major >= 10 && build >= 16299
24+
})
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
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+
//go:build darwin
6+
7+
package net
8+
9+
import (
10+
"syscall"
11+
"testing"
12+
)
13+
14+
const (
15+
syscall_TCP_KEEPIDLE = syscall.TCP_KEEPALIVE
16+
syscall_TCP_KEEPCNT = sysTCP_KEEPCNT
17+
syscall_TCP_KEEPINTVL = sysTCP_KEEPINTVL
18+
)
19+
20+
type fdType = int
21+
22+
func maybeSkipKeepAliveTest(_ *testing.T) {}
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
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+
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || windows
6+
7+
package net
8+
9+
import "time"
10+
11+
var testConfigs = []KeepAliveConfig{
12+
{
13+
Enable: true,
14+
Idle: 5 * time.Second,
15+
Interval: 3 * time.Second,
16+
Count: 10,
17+
},
18+
{
19+
Enable: true,
20+
Idle: 0,
21+
Interval: 0,
22+
Count: 0,
23+
},
24+
{
25+
Enable: true,
26+
Idle: -1,
27+
Interval: -1,
28+
Count: -1,
29+
},
30+
{
31+
Enable: true,
32+
Idle: -1,
33+
Interval: 3 * time.Second,
34+
Count: 10,
35+
},
36+
{
37+
Enable: true,
38+
Idle: 5 * time.Second,
39+
Interval: -1,
40+
Count: 10,
41+
},
42+
{
43+
Enable: true,
44+
Idle: 5 * time.Second,
45+
Interval: 3 * time.Second,
46+
Count: -1,
47+
},
48+
{
49+
Enable: true,
50+
Idle: -1,
51+
Interval: -1,
52+
Count: 10,
53+
},
54+
{
55+
Enable: true,
56+
Idle: -1,
57+
Interval: 3 * time.Second,
58+
Count: -1,
59+
},
60+
{
61+
Enable: true,
62+
Idle: 5 * time.Second,
63+
Interval: -1,
64+
Count: -1,
65+
},
66+
{
67+
Enable: true,
68+
Idle: 0,
69+
Interval: 3 * time.Second,
70+
Count: 10,
71+
},
72+
{
73+
Enable: true,
74+
Idle: 5 * time.Second,
75+
Interval: 0,
76+
Count: 10,
77+
},
78+
{
79+
Enable: true,
80+
Idle: 5 * time.Second,
81+
Interval: 3 * time.Second,
82+
Count: 0,
83+
},
84+
{
85+
Enable: true,
86+
Idle: 0,
87+
Interval: 0,
88+
Count: 10,
89+
},
90+
{
91+
Enable: true,
92+
Idle: 0,
93+
Interval: 3 * time.Second,
94+
Count: 0,
95+
},
96+
{
97+
Enable: true,
98+
Idle: 5 * time.Second,
99+
Interval: 0,
100+
Count: 0,
101+
},
102+
}

src/net/tcpconn_keepalive_conf_unix_test.go

Lines changed: 20 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -2,101 +2,28 @@
22
// Use of this source code is governed by a BSD-style
33
// license that can be found in the LICENSE file.
44

5-
//go:build aix || freebsd || linux || netbsd || darwin || dragonfly
5+
//go:build aix || dragonfly || freebsd || linux || netbsd || solaris
66

77
package net
88

9-
import "time"
9+
import (
10+
"runtime"
11+
"syscall"
12+
"testing"
13+
)
1014

11-
var testConfigs = []KeepAliveConfig{
12-
{
13-
Enable: true,
14-
Idle: 5 * time.Second,
15-
Interval: 3 * time.Second,
16-
Count: 10,
17-
},
18-
{
19-
Enable: true,
20-
Idle: 0,
21-
Interval: 0,
22-
Count: 0,
23-
},
24-
{
25-
Enable: true,
26-
Idle: -1,
27-
Interval: -1,
28-
Count: -1,
29-
},
30-
{
31-
Enable: true,
32-
Idle: -1,
33-
Interval: 3 * time.Second,
34-
Count: 10,
35-
},
36-
{
37-
Enable: true,
38-
Idle: 5 * time.Second,
39-
Interval: -1,
40-
Count: 10,
41-
},
42-
{
43-
Enable: true,
44-
Idle: 5 * time.Second,
45-
Interval: 3 * time.Second,
46-
Count: -1,
47-
},
48-
{
49-
Enable: true,
50-
Idle: -1,
51-
Interval: -1,
52-
Count: 10,
53-
},
54-
{
55-
Enable: true,
56-
Idle: -1,
57-
Interval: 3 * time.Second,
58-
Count: -1,
59-
},
60-
{
61-
Enable: true,
62-
Idle: 5 * time.Second,
63-
Interval: -1,
64-
Count: -1,
65-
},
66-
{
67-
Enable: true,
68-
Idle: 0,
69-
Interval: 3 * time.Second,
70-
Count: 10,
71-
},
72-
{
73-
Enable: true,
74-
Idle: 5 * time.Second,
75-
Interval: 0,
76-
Count: 10,
77-
},
78-
{
79-
Enable: true,
80-
Idle: 5 * time.Second,
81-
Interval: 3 * time.Second,
82-
Count: 0,
83-
},
84-
{
85-
Enable: true,
86-
Idle: 0,
87-
Interval: 0,
88-
Count: 10,
89-
},
90-
{
91-
Enable: true,
92-
Idle: 0,
93-
Interval: 3 * time.Second,
94-
Count: 0,
95-
},
96-
{
97-
Enable: true,
98-
Idle: 5 * time.Second,
99-
Interval: 0,
100-
Count: 0,
101-
},
15+
const (
16+
syscall_TCP_KEEPIDLE = syscall.TCP_KEEPIDLE
17+
syscall_TCP_KEEPCNT = syscall.TCP_KEEPCNT
18+
syscall_TCP_KEEPINTVL = syscall.TCP_KEEPINTVL
19+
)
20+
21+
type fdType = int
22+
23+
func maybeSkipKeepAliveTest(t *testing.T) {
24+
// TODO(panjf2000): stop skipping this test on Solaris
25+
// when https://go.dev/issue/64251 is fixed.
26+
if runtime.GOOS == "solaris" {
27+
t.Skip("skipping on solaris for now")
28+
}
10229
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
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+
//go:build windows
6+
7+
package net
8+
9+
import (
10+
"internal/syscall/windows"
11+
"syscall"
12+
"testing"
13+
)
14+
15+
const (
16+
syscall_TCP_KEEPIDLE = windows.TCP_KEEPIDLE
17+
syscall_TCP_KEEPCNT = windows.TCP_KEEPCNT
18+
syscall_TCP_KEEPINTVL = windows.TCP_KEEPINTVL
19+
)
20+
21+
type fdType = syscall.Handle
22+
23+
func maybeSkipKeepAliveTest(t *testing.T) {
24+
// TODO(panjf2000): Unlike Unix-like OS's, old Windows (prior to Windows 10, version 1709)
25+
// doesn't provide any ways to retrieve the current TCP keep-alive settings, therefore
26+
// we're not able to run the test suite similar to Unix-like OS's on Windows.
27+
// Try to find another proper approach to test the keep-alive settings on old Windows.
28+
if !windows.SupportFullTCPKeepAlive() {
29+
t.Skip("skipping on windows")
30+
}
31+
}

src/net/tcpconn_keepalive_darwin_test.go renamed to src/net/tcpconn_keepalive_posix_test.go

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// Use of this source code is governed by a BSD-style
33
// license that can be found in the LICENSE file.
44

5-
//go:build darwin
5+
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || windows
66

77
package net
88

@@ -12,20 +12,20 @@ import (
1212
"time"
1313
)
1414

15-
func getCurrentKeepAliveSettings(fd int) (cfg KeepAliveConfig, err error) {
15+
func getCurrentKeepAliveSettings(fd fdType) (cfg KeepAliveConfig, err error) {
1616
tcpKeepAlive, err := syscall.GetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_KEEPALIVE)
1717
if err != nil {
1818
return
1919
}
20-
tcpKeepAliveIdle, err := syscall.GetsockoptInt(fd, syscall.IPPROTO_TCP, syscall.TCP_KEEPALIVE)
20+
tcpKeepAliveIdle, err := syscall.GetsockoptInt(fd, syscall.IPPROTO_TCP, syscall_TCP_KEEPIDLE)
2121
if err != nil {
2222
return
2323
}
24-
tcpKeepAliveInterval, err := syscall.GetsockoptInt(fd, syscall.IPPROTO_TCP, sysTCP_KEEPINTVL)
24+
tcpKeepAliveInterval, err := syscall.GetsockoptInt(fd, syscall.IPPROTO_TCP, syscall_TCP_KEEPINTVL)
2525
if err != nil {
2626
return
2727
}
28-
tcpKeepAliveCount, err := syscall.GetsockoptInt(fd, syscall.IPPROTO_TCP, sysTCP_KEEPCNT)
28+
tcpKeepAliveCount, err := syscall.GetsockoptInt(fd, syscall.IPPROTO_TCP, syscall_TCP_KEEPCNT)
2929
if err != nil {
3030
return
3131
}
@@ -38,7 +38,7 @@ func getCurrentKeepAliveSettings(fd int) (cfg KeepAliveConfig, err error) {
3838
return
3939
}
4040

41-
func verifyKeepAliveSettings(t *testing.T, fd int, oldCfg, cfg KeepAliveConfig) {
41+
func verifyKeepAliveSettings(t *testing.T, fd fdType, oldCfg, cfg KeepAliveConfig) {
4242
if cfg.Idle == 0 {
4343
cfg.Idle = defaultTCPKeepAliveIdle
4444
}
@@ -66,23 +66,23 @@ func verifyKeepAliveSettings(t *testing.T, fd int, oldCfg, cfg KeepAliveConfig)
6666
t.Fatalf("SO_KEEPALIVE: got %t; want %t", tcpKeepAlive != 0, cfg.Enable)
6767
}
6868

69-
tcpKeepAliveIdle, err := syscall.GetsockoptInt(fd, syscall.IPPROTO_TCP, syscall.TCP_KEEPALIVE)
69+
tcpKeepAliveIdle, err := syscall.GetsockoptInt(fd, syscall.IPPROTO_TCP, syscall_TCP_KEEPIDLE)
7070
if err != nil {
7171
t.Fatal(err)
7272
}
7373
if time.Duration(tcpKeepAliveIdle)*time.Second != cfg.Idle {
7474
t.Fatalf("TCP_KEEPIDLE: got %ds; want %v", tcpKeepAliveIdle, cfg.Idle)
7575
}
7676

77-
tcpKeepAliveInterval, err := syscall.GetsockoptInt(fd, syscall.IPPROTO_TCP, sysTCP_KEEPINTVL)
77+
tcpKeepAliveInterval, err := syscall.GetsockoptInt(fd, syscall.IPPROTO_TCP, syscall_TCP_KEEPINTVL)
7878
if err != nil {
7979
t.Fatal(err)
8080
}
8181
if time.Duration(tcpKeepAliveInterval)*time.Second != cfg.Interval {
8282
t.Fatalf("TCP_KEEPINTVL: got %ds; want %v", tcpKeepAliveInterval, cfg.Interval)
8383
}
8484

85-
tcpKeepAliveCount, err := syscall.GetsockoptInt(fd, syscall.IPPROTO_TCP, sysTCP_KEEPCNT)
85+
tcpKeepAliveCount, err := syscall.GetsockoptInt(fd, syscall.IPPROTO_TCP, syscall_TCP_KEEPCNT)
8686
if err != nil {
8787
t.Fatal(err)
8888
}

0 commit comments

Comments
 (0)