// 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) } } }