package tcp import ( "net" "os" "strings" "syscall" reuseport "github.com/jbenet/go-reuseport" ) // envReuseport is the env variable name used to turn off reuse port. // It default to true. const envReuseport = "IPFS_REUSEPORT" // envReuseportVal stores the value of envReuseport. defaults to true. var envReuseportVal = true func init() { v := strings.ToLower(os.Getenv(envReuseport)) if v == "false" || v == "f" || v == "0" { envReuseportVal = false log.Infof("REUSEPORT disabled (IPFS_REUSEPORT=%s)", v) } } // reuseportIsAvailable returns whether reuseport is available to be used. This // is here because we want to be able to turn reuseport on and off selectively. // For now we use an ENV variable, as this handles our pressing need: // // IPFS_REUSEPORT=false ipfs daemon // // If this becomes a sought after feature, we could add this to the config. // In the end, reuseport is a stop-gap. func ReuseportIsAvailable() bool { return envReuseportVal && reuseport.Available() } // ReuseErrShouldRetry diagnoses whether to retry after a reuse error. // if we failed to bind, we should retry. if bind worked and this is a // real dial error (remote end didnt answer) then we should not retry. func ReuseErrShouldRetry(err error) bool { if err == nil { return false // hey, it worked! no need to retry. } // if it's a network timeout error, it's a legitimate failure. if nerr, ok := err.(net.Error); ok && nerr.Timeout() { return false } errno, ok := err.(syscall.Errno) if !ok { // not an errno? who knows what this is. retry. return true } switch errno { case syscall.EADDRINUSE, syscall.EADDRNOTAVAIL: return true // failure to bind. retry. case syscall.ECONNREFUSED: return false // real dial error default: return true // optimistically default to retry. } }