Source file src/net/tcpsockopt_solaris.go

     1  // Copyright 2015 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  
     7  package net
     8  
     9  import (
    10  	"internal/syscall/unix"
    11  	"runtime"
    12  	"syscall"
    13  	"time"
    14  )
    15  
    16  // Some macros of TCP Keep-Alive options on Solaris 11.4 may
    17  // differ from those on OpenSolaris-based derivatives.
    18  const (
    19  	sysTCP_KEEPIDLE  = 0x1D
    20  	sysTCP_KEEPINTVL = 0x1E
    21  	sysTCP_KEEPCNT   = 0x1F
    22  )
    23  
    24  func setKeepAliveIdle(fd *netFD, d time.Duration) error {
    25  	if !unix.SupportTCPKeepAliveIdleIntvlCNT() {
    26  		return setKeepAliveIdleAndIntervalAndCount(fd, d, -1, -1)
    27  	}
    28  
    29  	if d == 0 {
    30  		d = defaultTCPKeepAliveIdle
    31  	} else if d < 0 {
    32  		return nil
    33  	}
    34  	// The kernel expects seconds so round to next highest second.
    35  	secs := int(roundDurationUp(d, time.Second))
    36  	err := fd.pfd.SetsockoptInt(syscall.IPPROTO_TCP, sysTCP_KEEPIDLE, secs)
    37  	runtime.KeepAlive(fd)
    38  	return wrapSyscallError("setsockopt", err)
    39  }
    40  
    41  func setKeepAliveInterval(fd *netFD, d time.Duration) error {
    42  	if !unix.SupportTCPKeepAliveIdleIntvlCNT() {
    43  		return syscall.EPROTOTYPE
    44  	}
    45  
    46  	if d == 0 {
    47  		d = defaultTCPKeepAliveInterval
    48  	} else if d < 0 {
    49  		return nil
    50  	}
    51  	// The kernel expects seconds so round to next highest second.
    52  	secs := int(roundDurationUp(d, time.Second))
    53  	err := fd.pfd.SetsockoptInt(syscall.IPPROTO_TCP, sysTCP_KEEPINTVL, secs)
    54  	runtime.KeepAlive(fd)
    55  	return wrapSyscallError("setsockopt", err)
    56  }
    57  
    58  func setKeepAliveCount(fd *netFD, n int) error {
    59  	if !unix.SupportTCPKeepAliveIdleIntvlCNT() {
    60  		return syscall.EPROTOTYPE
    61  	}
    62  
    63  	if n == 0 {
    64  		n = defaultTCPKeepAliveCount
    65  	} else if n < 0 {
    66  		return nil
    67  	}
    68  	err := fd.pfd.SetsockoptInt(syscall.IPPROTO_TCP, sysTCP_KEEPCNT, n)
    69  	runtime.KeepAlive(fd)
    70  	return wrapSyscallError("setsockopt", err)
    71  }
    72  
    73  // setKeepAliveIdleAndIntervalAndCount serves for Solaris prior to 11.4 by simulating
    74  // the TCP_KEEPIDLE, TCP_KEEPINTVL, and TCP_KEEPCNT with `TCP_KEEPALIVE_THRESHOLD` + `TCP_KEEPALIVE_ABORT_THRESHOLD`.
    75  func setKeepAliveIdleAndIntervalAndCount(fd *netFD, idle, interval time.Duration, count int) error {
    76  	if idle == 0 {
    77  		idle = defaultTCPKeepAliveIdle
    78  	}
    79  
    80  	// The kernel expects milliseconds so round to next highest
    81  	// millisecond.
    82  	if idle > 0 {
    83  		msecs := int(roundDurationUp(idle, time.Millisecond))
    84  		err := fd.pfd.SetsockoptInt(syscall.IPPROTO_TCP, syscall.TCP_KEEPALIVE_THRESHOLD, msecs)
    85  		runtime.KeepAlive(fd)
    86  		if err != nil {
    87  			return wrapSyscallError("setsockopt", err)
    88  		}
    89  	}
    90  
    91  	if interval == 0 {
    92  		interval = defaultTCPKeepAliveInterval
    93  	}
    94  	if count == 0 {
    95  		count = defaultTCPKeepAliveCount
    96  	}
    97  	// TCP_KEEPINTVL and TCP_KEEPCNT are not available on Solaris
    98  	// prior to 11.4, so it's pointless to "leave it unchanged"
    99  	// with negative value for only one of them. On the other hand,
   100  	// setting both to negative values should pragmatically leave the
   101  	// TCP_KEEPALIVE_ABORT_THRESHOLD unchanged.
   102  	abortIdle := int(roundDurationUp(interval, time.Millisecond)) * count
   103  	if abortIdle < 0 {
   104  		return syscall.ENOPROTOOPT
   105  	}
   106  	if interval < 0 && count < 0 {
   107  		abortIdle = -1
   108  	}
   109  
   110  	if abortIdle > 0 {
   111  		// Note that the consequent probes will not be sent at equal intervals on Solaris,
   112  		// but will be sent using the exponential backoff algorithm.
   113  		err := fd.pfd.SetsockoptInt(syscall.IPPROTO_TCP, syscall.TCP_KEEPALIVE_ABORT_THRESHOLD, abortIdle)
   114  		runtime.KeepAlive(fd)
   115  		return wrapSyscallError("setsockopt", err)
   116  	}
   117  
   118  	return nil
   119  }
   120  

View as plain text