Source file src/net/tcpconn_keepalive_solaris_test.go

     1  // Copyright 2023 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 solaris && !illumos
     6  
     7  package net
     8  
     9  import (
    10  	"internal/syscall/unix"
    11  	"syscall"
    12  	"testing"
    13  	"time"
    14  )
    15  
    16  func getCurrentKeepAliveSettings(fd fdType) (cfg KeepAliveConfig, err error) {
    17  	tcpKeepAlive, err := syscall.GetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_KEEPALIVE)
    18  	if err != nil {
    19  		return
    20  	}
    21  
    22  	var (
    23  		tcpKeepAliveIdle         int
    24  		tcpKeepAliveInterval     int
    25  		tcpKeepAliveIdleTime     time.Duration
    26  		tcpKeepAliveIntervalTime time.Duration
    27  		tcpKeepAliveCount        int
    28  	)
    29  	if unix.SupportTCPKeepAliveIdleIntvlCNT() {
    30  		tcpKeepAliveIdle, err = syscall.GetsockoptInt(fd, syscall.IPPROTO_TCP, syscall_TCP_KEEPIDLE)
    31  		if err != nil {
    32  			return
    33  		}
    34  		tcpKeepAliveIdleTime = time.Duration(tcpKeepAliveIdle) * time.Second
    35  
    36  		tcpKeepAliveInterval, err = syscall.GetsockoptInt(fd, syscall.IPPROTO_TCP, syscall_TCP_KEEPINTVL)
    37  		if err != nil {
    38  			return
    39  		}
    40  		tcpKeepAliveIntervalTime = time.Duration(tcpKeepAliveInterval) * time.Second
    41  
    42  		tcpKeepAliveCount, err = syscall.GetsockoptInt(fd, syscall.IPPROTO_TCP, syscall_TCP_KEEPCNT)
    43  		if err != nil {
    44  			return
    45  		}
    46  	} else {
    47  		tcpKeepAliveIdle, err = syscall.GetsockoptInt(fd, syscall.IPPROTO_TCP, syscall.TCP_KEEPALIVE_THRESHOLD)
    48  		if err != nil {
    49  			return
    50  		}
    51  		tcpKeepAliveIdleTime = time.Duration(tcpKeepAliveIdle) * time.Millisecond
    52  
    53  		// TCP_KEEPINTVL and TCP_KEEPCNT are not available on Solaris prior to 11.4,
    54  		// so we have to use the value of TCP_KEEPALIVE_ABORT_THRESHOLD for Interval
    55  		// and 1 for Count to keep this test going.
    56  		tcpKeepAliveInterval, err = syscall.GetsockoptInt(fd, syscall.IPPROTO_TCP, syscall.TCP_KEEPALIVE_ABORT_THRESHOLD)
    57  		if err != nil {
    58  			return
    59  		}
    60  		tcpKeepAliveIntervalTime = time.Duration(tcpKeepAliveInterval) * time.Millisecond
    61  		tcpKeepAliveCount = 1
    62  	}
    63  	cfg = KeepAliveConfig{
    64  		Enable:   tcpKeepAlive != 0,
    65  		Idle:     tcpKeepAliveIdleTime,
    66  		Interval: tcpKeepAliveIntervalTime,
    67  		Count:    tcpKeepAliveCount,
    68  	}
    69  	return
    70  }
    71  
    72  func verifyKeepAliveSettings(t *testing.T, fd fdType, oldCfg, cfg KeepAliveConfig) {
    73  	const defaultTcpKeepAliveAbortThreshold = 8 * time.Minute // default value on Solaris
    74  
    75  	if cfg.Idle == 0 {
    76  		cfg.Idle = defaultTCPKeepAliveIdle
    77  	}
    78  	if cfg.Interval == 0 {
    79  		cfg.Interval = defaultTCPKeepAliveInterval
    80  	}
    81  	if cfg.Count == 0 {
    82  		cfg.Count = defaultTCPKeepAliveCount
    83  	}
    84  	if cfg.Idle == -1 {
    85  		cfg.Idle = oldCfg.Idle
    86  	}
    87  
    88  	tcpKeepAliveAbortThreshold := defaultTcpKeepAliveAbortThreshold
    89  	if unix.SupportTCPKeepAliveIdleIntvlCNT() {
    90  		// Check out the comment on KeepAliveConfig to understand the following logic.
    91  		switch {
    92  		case cfg.Interval == -1 && cfg.Count == -1:
    93  			cfg.Interval = oldCfg.Interval
    94  			cfg.Count = oldCfg.Count
    95  		case cfg.Interval == -1 && cfg.Count > 0:
    96  			cfg.Interval = defaultTcpKeepAliveAbortThreshold / time.Duration(cfg.Count)
    97  		case cfg.Count == -1 && cfg.Interval > 0:
    98  			cfg.Count = int(defaultTcpKeepAliveAbortThreshold / cfg.Interval)
    99  		case cfg.Interval > 0 && cfg.Count > 0:
   100  			// TCP_KEEPALIVE_ABORT_THRESHOLD will be recalculated only when both TCP_KEEPINTVL
   101  			// and TCP_KEEPCNT are set, otherwise it will remain the default value.
   102  			tcpKeepAliveAbortThreshold = cfg.Interval * time.Duration(cfg.Count)
   103  		}
   104  	} else {
   105  		cfg.Interval = cfg.Interval * time.Duration(cfg.Count)
   106  		// Either Interval or Count is set to a negative value, TCP_KEEPALIVE_ABORT_THRESHOLD
   107  		// will remain the default value, so use the old Interval for the subsequent test.
   108  		if cfg.Interval == -1 || cfg.Count == -1 {
   109  			cfg.Interval = oldCfg.Interval
   110  		}
   111  		cfg.Count = 1
   112  		tcpKeepAliveAbortThreshold = cfg.Interval
   113  	}
   114  
   115  	tcpKeepAlive, err := syscall.GetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_KEEPALIVE)
   116  	if err != nil {
   117  		t.Fatal(err)
   118  	}
   119  	if (tcpKeepAlive != 0) != cfg.Enable {
   120  		t.Fatalf("SO_KEEPALIVE: got %t; want %t", tcpKeepAlive != 0, cfg.Enable)
   121  	}
   122  
   123  	// TCP_KEEPALIVE_THRESHOLD and TCP_KEEPALIVE_ABORT_THRESHOLD are both available on Solaris 11.4
   124  	// and previous versions, so we can verify these two options regardless of the kernel version.
   125  	tcpKeepAliveThreshold, err := syscall.GetsockoptInt(fd, syscall.IPPROTO_TCP, syscall.TCP_KEEPALIVE_THRESHOLD)
   126  	if err != nil {
   127  		t.Fatal(err)
   128  	}
   129  	if time.Duration(tcpKeepAliveThreshold)*time.Millisecond != cfg.Idle {
   130  		t.Fatalf("TCP_KEEPIDLE: got %dms; want %v", tcpKeepAliveThreshold, cfg.Idle)
   131  	}
   132  
   133  	tcpKeepAliveAbortInterval, err := syscall.GetsockoptInt(fd, syscall.IPPROTO_TCP, syscall.TCP_KEEPALIVE_ABORT_THRESHOLD)
   134  	if err != nil {
   135  		t.Fatal(err)
   136  	}
   137  	if time.Duration(tcpKeepAliveAbortInterval)*time.Millisecond != tcpKeepAliveAbortThreshold {
   138  		t.Fatalf("TCP_KEEPALIVE_ABORT_THRESHOLD: got %dms; want %v", tcpKeepAliveAbortInterval, tcpKeepAliveAbortThreshold)
   139  	}
   140  
   141  	if unix.SupportTCPKeepAliveIdleIntvlCNT() {
   142  		tcpKeepAliveIdle, err := syscall.GetsockoptInt(fd, syscall.IPPROTO_TCP, syscall_TCP_KEEPIDLE)
   143  		if err != nil {
   144  			t.Fatal(err)
   145  		}
   146  		if time.Duration(tcpKeepAliveIdle)*time.Second != cfg.Idle {
   147  			t.Fatalf("TCP_KEEPIDLE: got %ds; want %v", tcpKeepAliveIdle, cfg.Idle)
   148  		}
   149  
   150  		tcpKeepAliveInterval, err := syscall.GetsockoptInt(fd, syscall.IPPROTO_TCP, syscall_TCP_KEEPINTVL)
   151  		if err != nil {
   152  			t.Fatal(err)
   153  		}
   154  		if time.Duration(tcpKeepAliveInterval)*time.Second != cfg.Interval {
   155  			t.Fatalf("TCP_KEEPINTVL: got %ds; want %v", tcpKeepAliveInterval, cfg.Interval)
   156  		}
   157  
   158  		tcpKeepAliveCount, err := syscall.GetsockoptInt(fd, syscall.IPPROTO_TCP, syscall_TCP_KEEPCNT)
   159  		if err != nil {
   160  			t.Fatal(err)
   161  		}
   162  		if tcpKeepAliveCount != cfg.Count {
   163  			t.Fatalf("TCP_KEEPCNT: got %d; want %d", tcpKeepAliveCount, cfg.Count)
   164  		}
   165  	} else {
   166  		if cfg.Count != 1 {
   167  			t.Fatalf("TCP_KEEPCNT: got %d; want 1", cfg.Count)
   168  		}
   169  	}
   170  }
   171  

View as plain text