Adjust default backoff max to just over 1 hour, add ?maxbackoff= peer option (#1124)

Co-authored-by: Neil Alexander <neilalexander@users.noreply.github.com>
This commit is contained in:
Neil 2024-01-15 23:09:07 +00:00 committed by GitHub
parent 9f4c89acad
commit 180d7bf499
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -6,7 +6,6 @@ import (
"encoding/hex" "encoding/hex"
"fmt" "fmt"
"io" "io"
"math"
"net" "net"
"net/netip" "net/netip"
"net/url" "net/url"
@ -28,6 +27,9 @@ const (
linkTypeIncoming // Incoming connection linkTypeIncoming // Incoming connection
) )
const defaultBackoffLimit = time.Second << 12 // 1h8m16s
const minimumBackoffLimit = time.Second * 30
type links struct { type links struct {
phony.Inbox phony.Inbox
core *Core core *Core
@ -69,6 +71,7 @@ type linkOptions struct {
priority uint8 priority uint8
tlsSNI string tlsSNI string
password []byte password []byte
maxBackoff time.Duration
} }
type Listener struct { type Listener struct {
@ -136,6 +139,7 @@ const ErrLinkPriorityInvalid = linkError("priority value is invalid")
const ErrLinkPinnedKeyInvalid = linkError("pinned public key is invalid") const ErrLinkPinnedKeyInvalid = linkError("pinned public key is invalid")
const ErrLinkPasswordInvalid = linkError("password is invalid") const ErrLinkPasswordInvalid = linkError("password is invalid")
const ErrLinkUnrecognisedSchema = linkError("link schema unknown") const ErrLinkUnrecognisedSchema = linkError("link schema unknown")
const ErrLinkMaxBackoffInvalid = linkError("max backoff duration invalid")
func (l *links) add(u *url.URL, sintf string, linkType linkType) error { func (l *links) add(u *url.URL, sintf string, linkType linkType) error {
var retErr error var retErr error
@ -150,7 +154,9 @@ func (l *links) add(u *url.URL, sintf string, linkType linkType) error {
// Collect together the link options, these are global options // Collect together the link options, these are global options
// that are not specific to any given protocol. // that are not specific to any given protocol.
var options linkOptions options := linkOptions{
maxBackoff: defaultBackoffLimit,
}
for _, pubkey := range u.Query()["key"] { for _, pubkey := range u.Query()["key"] {
sigPub, err := hex.DecodeString(pubkey) sigPub, err := hex.DecodeString(pubkey)
if err != nil { if err != nil {
@ -179,6 +185,14 @@ func (l *links) add(u *url.URL, sintf string, linkType linkType) error {
} }
options.password = []byte(p) options.password = []byte(p)
} }
if p := u.Query().Get("maxbackoff"); p != "" {
d, err := time.ParseDuration(p)
if err != nil || d < minimumBackoffLimit {
retErr = ErrLinkMaxBackoffInvalid
return
}
options.maxBackoff = d
}
// SNI headers must contain hostnames and not IP addresses, so we must make sure // SNI headers must contain hostnames and not IP addresses, so we must make sure
// that we do not populate the SNI with an IP literal. We do this by splitting // that we do not populate the SNI with an IP literal. We do this by splitting
// the host-port combo from the query option and then seeing if it parses to an // the host-port combo from the query option and then seeing if it parses to an
@ -235,10 +249,13 @@ func (l *links) add(u *url.URL, sintf string, linkType linkType) error {
// The caller should check the return value to decide whether // The caller should check the return value to decide whether
// or not to give up trying. // or not to give up trying.
backoffNow := func() bool { backoffNow := func() bool {
if backoff < 14 { // Cap at roughly 4.5 hours maximum. if backoff < 32 {
backoff++ backoff++
} }
duration := time.Second * time.Duration(math.Exp2(float64(backoff))) duration := time.Second << backoff
if duration > options.maxBackoff {
duration = options.maxBackoff
}
select { select {
case <-state.kick: case <-state.kick:
return true return true