blob: 8eb6f2ea4e81d0045272d88eea0d66fa431cab39 [file] [log] [blame]
// 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 "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)
}
ra, err := ResolveTCPAddr("tcp", ls.Listener.Addr().String())
if err != nil {
t.Fatal(err)
}
for _, cfg := range testConfigs {
c, err := DialTCP("tcp", nil, ra)
if err != nil {
t.Fatal(err)
}
defer c.Close()
sc, err := c.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)
}
if err := c.SetKeepAliveConfig(cfg); err != nil {
t.Fatal(err)
}
if err := sc.Control(func(fd uintptr) {
verifyKeepAliveSettings(t, fdType(fd), oldCfg, cfg)
}); err != nil {
t.Fatal(err)
}
}
}