wgengine/magicsock: if UDP blocked, pick DERP where most peers are

Updates #207

Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
Brad Fitzpatrick 2020-03-24 22:24:59 -07:00 committed by Brad Fitzpatrick
parent f53e78e0d5
commit 6284454ae5

View File

@ -389,6 +389,26 @@ func (c *Conn) pickDERPFallback() int {
return 0 return 0
} }
// See where our peers are. Pick wherever the most nodes are.
var (
peersOnDerp = map[int]int{}
best int
bestCount int
)
for _, as := range c.addrsByKey {
if id := as.derpID(); id != 0 {
peersOnDerp[id]++
if v := peersOnDerp[id]; v > bestCount {
bestCount = v
best = id
}
}
}
if best != 0 {
return best
}
// Otherwise just pick something randomly.
h := fnv.New64() h := fnv.New64()
h.Write([]byte(fmt.Sprintf("%p/%d", c, processStartUnixNano))) // arbitrary h.Write([]byte(fmt.Sprintf("%p/%d", c, processStartUnixNano))) // arbitrary
return ids[rand.New(rand.NewSource(int64(h.Sum64()))).Intn(len(ids))] return ids[rand.New(rand.NewSource(int64(h.Sum64()))).Intn(len(ids))]
@ -1487,6 +1507,16 @@ type AddrSet struct {
lastSpray time.Time lastSpray time.Time
} }
// derpID returns this AddrSet's home DERP node, or 0 if none is found.
func (as *AddrSet) derpID() int {
for _, ua := range as.addrs {
if ua.IP.Equal(derpMagicIP) {
return ua.Port
}
}
return 0
}
func (as *AddrSet) timeNow() time.Time { func (as *AddrSet) timeNow() time.Time {
if as.clock != nil { if as.clock != nil {
return as.clock() return as.clock()