tcpsockopt_solaris.mx raw

   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