mirror of https://go.googlesource.com/go
191 lines
4.2 KiB
Go
191 lines
4.2 KiB
Go
// Copyright 2023 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 aix || darwin || dragonfly || freebsd || linux || netbsd || solaris || windows
|
|
|
|
package net
|
|
|
|
import (
|
|
"runtime"
|
|
"testing"
|
|
)
|
|
|
|
func TestTCPConnKeepAliveConfigDialer(t *testing.T) {
|
|
maybeSkipKeepAliveTest(t)
|
|
|
|
t.Cleanup(func() {
|
|
testPreHookSetKeepAlive = func(*netFD) {}
|
|
})
|
|
var (
|
|
errHook error
|
|
oldCfg KeepAliveConfig
|
|
)
|
|
testPreHookSetKeepAlive = func(nfd *netFD) {
|
|
oldCfg, errHook = getCurrentKeepAliveSettings(fdType(nfd.pfd.Sysfd))
|
|
}
|
|
|
|
handler := func(ls *localServer, ln Listener) {
|
|
for {
|
|
c, err := ln.Accept()
|
|
if err != nil {
|
|
return
|
|
}
|
|
c.Close()
|
|
}
|
|
}
|
|
ln := newLocalListener(t, "tcp", &ListenConfig{
|
|
KeepAlive: -1, // prevent calling hook from accepting
|
|
})
|
|
ls := (&streamListener{Listener: ln}).newLocalServer()
|
|
defer ls.teardown()
|
|
if err := ls.buildup(handler); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
for _, cfg := range testConfigs {
|
|
d := Dialer{
|
|
KeepAlive: defaultTCPKeepAliveIdle, // should be ignored
|
|
KeepAliveConfig: cfg}
|
|
c, err := d.Dial("tcp", ls.Listener.Addr().String())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer c.Close()
|
|
|
|
if errHook != nil {
|
|
t.Fatal(errHook)
|
|
}
|
|
|
|
sc, err := c.(*TCPConn).SyscallConn()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := sc.Control(func(fd uintptr) {
|
|
verifyKeepAliveSettings(t, fdType(fd), oldCfg, cfg)
|
|
}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestTCPConnKeepAliveConfigListener(t *testing.T) {
|
|
maybeSkipKeepAliveTest(t)
|
|
|
|
t.Cleanup(func() {
|
|
testPreHookSetKeepAlive = func(*netFD) {}
|
|
})
|
|
var (
|
|
errHook error
|
|
oldCfg KeepAliveConfig
|
|
)
|
|
testPreHookSetKeepAlive = func(nfd *netFD) {
|
|
oldCfg, errHook = getCurrentKeepAliveSettings(fdType(nfd.pfd.Sysfd))
|
|
}
|
|
|
|
ch := make(chan Conn, 1)
|
|
handler := func(ls *localServer, ln Listener) {
|
|
c, err := ln.Accept()
|
|
if err != nil {
|
|
return
|
|
}
|
|
ch <- c
|
|
}
|
|
for _, cfg := range testConfigs {
|
|
ln := newLocalListener(t, "tcp", &ListenConfig{
|
|
KeepAlive: defaultTCPKeepAliveIdle, // should be ignored
|
|
KeepAliveConfig: cfg})
|
|
ls := (&streamListener{Listener: ln}).newLocalServer()
|
|
defer ls.teardown()
|
|
if err := ls.buildup(handler); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
d := Dialer{KeepAlive: -1} // prevent calling hook from dialing
|
|
c, err := d.Dial("tcp", ls.Listener.Addr().String())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer c.Close()
|
|
|
|
cc := <-ch
|
|
defer cc.Close()
|
|
if errHook != nil {
|
|
t.Fatal(errHook)
|
|
}
|
|
sc, err := cc.(*TCPConn).SyscallConn()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := sc.Control(func(fd uintptr) {
|
|
verifyKeepAliveSettings(t, fdType(fd), oldCfg, cfg)
|
|
}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestTCPConnKeepAliveConfig(t *testing.T) {
|
|
maybeSkipKeepAliveTest(t)
|
|
|
|
handler := func(ls *localServer, ln Listener) {
|
|
for {
|
|
c, err := ln.Accept()
|
|
if err != nil {
|
|
return
|
|
}
|
|
c.Close()
|
|
}
|
|
}
|
|
ls := newLocalServer(t, "tcp")
|
|
defer ls.teardown()
|
|
if err := ls.buildup(handler); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, cfg := range testConfigs {
|
|
d := Dialer{KeepAlive: -1} // avoid setting default values before the test
|
|
c, err := d.Dial("tcp", ls.Listener.Addr().String())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer c.Close()
|
|
|
|
sc, err := c.(*TCPConn).SyscallConn()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
var (
|
|
errHook error
|
|
oldCfg KeepAliveConfig
|
|
)
|
|
if err := sc.Control(func(fd uintptr) {
|
|
oldCfg, errHook = getCurrentKeepAliveSettings(fdType(fd))
|
|
}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if errHook != nil {
|
|
t.Fatal(errHook)
|
|
}
|
|
|
|
err = c.(*TCPConn).SetKeepAliveConfig(cfg)
|
|
if err != nil {
|
|
if runtime.GOOS == "solaris" {
|
|
// Solaris prior to 11.4 does not support TCP_KEEPINTVL and TCP_KEEPCNT,
|
|
// so it will return syscall.ENOPROTOOPT when only one of Interval and Count
|
|
// is negative. This is expected, so skip the error check in this case.
|
|
if cfg.Interval >= 0 && cfg.Count >= 0 {
|
|
t.Fatal(err)
|
|
}
|
|
} else {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
if err := sc.Control(func(fd uintptr) {
|
|
verifyKeepAliveSettings(t, fdType(fd), oldCfg, cfg)
|
|
}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
}
|