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 illumos 6 7package net 8 9import ( 10 "syscall" 11 "testing" 12 "time" 13) 14 15func getCurrentKeepAliveSettings(fd fdType) (cfg KeepAliveConfig, err error) { 16 tcpKeepAlive, err := syscall.GetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_KEEPALIVE) 17 if err != nil { 18 return 19 } 20 tcpKeepAliveIdle, err := syscall.GetsockoptInt(fd, syscall.IPPROTO_TCP, syscall_TCP_KEEPIDLE) 21 if err != nil { 22 return 23 } 24 tcpKeepAliveInterval, err := syscall.GetsockoptInt(fd, syscall.IPPROTO_TCP, syscall_TCP_KEEPINTVL) 25 if err != nil { 26 return 27 } 28 tcpKeepAliveCount, err := syscall.GetsockoptInt(fd, syscall.IPPROTO_TCP, syscall_TCP_KEEPCNT) 29 if err != nil { 30 return 31 } 32 cfg = KeepAliveConfig{ 33 Enable: tcpKeepAlive != 0, 34 Idle: time.Duration(tcpKeepAliveIdle) * time.Second, 35 Interval: time.Duration(tcpKeepAliveInterval) * time.Second, 36 Count: tcpKeepAliveCount, 37 } 38 return 39} 40 41func verifyKeepAliveSettings(t *testing.T, fd fdType, oldCfg, cfg KeepAliveConfig) { 42 const defaultTcpKeepAliveAbortThreshold = 8 * time.Minute // default value on illumos 43 44 if cfg.Idle == 0 { 45 cfg.Idle = defaultTCPKeepAliveIdle 46 } 47 if cfg.Interval == 0 { 48 cfg.Interval = defaultTCPKeepAliveInterval 49 } 50 if cfg.Count == 0 { 51 cfg.Count = defaultTCPKeepAliveCount 52 } 53 54 if cfg.Idle == -1 { 55 cfg.Idle = oldCfg.Idle 56 } 57 // Check out the comment on KeepAliveConfig and the illumos code: 58 // https://github.com/illumos/illumos-gate/blob/0886dcadf4b2cd677c3b944167f0d16ccb243616/usr/src/uts/common/inet/tcp/tcp_opt_data.c#L786-L861 59 tcpKeepAliveAbortThreshold := defaultTcpKeepAliveAbortThreshold 60 switch { 61 case cfg.Interval == -1 && cfg.Count == -1: 62 cfg.Interval = oldCfg.Interval 63 cfg.Count = oldCfg.Count 64 case cfg.Interval == -1 && cfg.Count > 0: 65 cfg.Interval = defaultTcpKeepAliveAbortThreshold / time.Duration(cfg.Count) 66 case cfg.Count == -1 && cfg.Interval > 0: 67 cfg.Count = int(defaultTcpKeepAliveAbortThreshold / cfg.Interval) 68 case cfg.Interval > 0 && cfg.Count > 0: 69 // TCP_KEEPALIVE_ABORT_THRESHOLD will be recalculated only when both TCP_KEEPINTVL 70 // and TCP_KEEPCNT are set, otherwise it will remain the default value. 71 tcpKeepAliveAbortThreshold = cfg.Interval * time.Duration(cfg.Count) 72 } 73 74 tcpKeepAlive, err := syscall.GetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_KEEPALIVE) 75 if err != nil { 76 t.Fatal(err) 77 } 78 if (tcpKeepAlive != 0) != cfg.Enable { 79 t.Fatalf("SO_KEEPALIVE: got %t; want %t", tcpKeepAlive != 0, cfg.Enable) 80 } 81 82 tcpKeepAliveIdle, err := syscall.GetsockoptInt(fd, syscall.IPPROTO_TCP, syscall_TCP_KEEPIDLE) 83 if err != nil { 84 t.Fatal(err) 85 } 86 if time.Duration(tcpKeepAliveIdle)*time.Second != cfg.Idle { 87 t.Fatalf("TCP_KEEPIDLE: got %ds; want %v", tcpKeepAliveIdle, cfg.Idle) 88 } 89 tcpKeepAliveThreshold, err := syscall.GetsockoptInt(fd, syscall.IPPROTO_TCP, syscall.TCP_KEEPALIVE_THRESHOLD) 90 if err != nil { 91 t.Fatal(err) 92 } 93 if time.Duration(tcpKeepAliveThreshold)*time.Millisecond != cfg.Idle { 94 t.Fatalf("TCP_KEEPALIVE_THRESHOLD: got %dms; want %v", tcpKeepAliveThreshold, cfg.Idle) 95 } 96 97 tcpKeepAliveInterval, err := syscall.GetsockoptInt(fd, syscall.IPPROTO_TCP, syscall_TCP_KEEPINTVL) 98 if err != nil { 99 t.Fatal(err) 100 } 101 if time.Duration(tcpKeepAliveInterval)*time.Second != cfg.Interval { 102 t.Fatalf("TCP_KEEPINTVL: got %ds; want %v", tcpKeepAliveInterval, cfg.Interval) 103 } 104 105 tcpKeepAliveCount, err := syscall.GetsockoptInt(fd, syscall.IPPROTO_TCP, syscall_TCP_KEEPCNT) 106 if err != nil { 107 t.Fatal(err) 108 } 109 if tcpKeepAliveCount != cfg.Count { 110 t.Fatalf("TCP_KEEPCNT: got %d; want %d", tcpKeepAliveCount, cfg.Count) 111 } 112 113 tcpKeepAliveAbortInterval, err := syscall.GetsockoptInt(fd, syscall.IPPROTO_TCP, syscall.TCP_KEEPALIVE_ABORT_THRESHOLD) 114 if err != nil { 115 t.Fatal(err) 116 } 117 if time.Duration(tcpKeepAliveAbortInterval)*time.Millisecond != tcpKeepAliveAbortThreshold { 118 t.Fatalf("TCP_KEEPALIVE_ABORT_THRESHOLD: got %dms; want %v", tcpKeepAliveAbortInterval, tcpKeepAliveAbortThreshold) 119 } 120} 121