mirror of
https://github.com/tailscale/tailscale.git
synced 2024-11-26 03:25:35 +00:00
ffa70a617d
The Engine.LinkChange method was recently removed in
e3df29d488
while misremembering how
Android's link state mechanism worked.
Rather than do some last minute rearchitecting of link state on
Android before Tailscale 1.6, restore the old Engine.LinkChange hook
for now so the Android client doesn't need any changes. But change how
it's implemented to instead inject an event into the link monitor.
Fixes #1427
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
129 lines
3.7 KiB
Go
129 lines
3.7 KiB
Go
// Copyright (c) 2020 Tailscale Inc & AUTHORS All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package wgengine
|
|
|
|
import (
|
|
"log"
|
|
"os"
|
|
"runtime/pprof"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"inet.af/netaddr"
|
|
"tailscale.com/ipn/ipnstate"
|
|
"tailscale.com/tailcfg"
|
|
"tailscale.com/types/netmap"
|
|
"tailscale.com/wgengine/filter"
|
|
"tailscale.com/wgengine/monitor"
|
|
"tailscale.com/wgengine/router"
|
|
"tailscale.com/wgengine/tsdns"
|
|
"tailscale.com/wgengine/wgcfg"
|
|
)
|
|
|
|
// NewWatchdog wraps an Engine and makes sure that all methods complete
|
|
// within a reasonable amount of time.
|
|
//
|
|
// If they do not, the watchdog crashes the process.
|
|
func NewWatchdog(e Engine) Engine {
|
|
if v, _ := strconv.ParseBool(os.Getenv("TS_DEBUG_DISABLE_WATCHDOG")); v {
|
|
return e
|
|
}
|
|
return &watchdogEngine{
|
|
wrap: e,
|
|
logf: log.Printf,
|
|
fatalf: log.Fatalf,
|
|
maxWait: 45 * time.Second,
|
|
}
|
|
}
|
|
|
|
type watchdogEngine struct {
|
|
wrap Engine
|
|
logf func(format string, args ...interface{})
|
|
fatalf func(format string, args ...interface{})
|
|
maxWait time.Duration
|
|
}
|
|
|
|
func (e *watchdogEngine) watchdogErr(name string, fn func() error) error {
|
|
errCh := make(chan error)
|
|
go func() {
|
|
errCh <- fn()
|
|
}()
|
|
t := time.NewTimer(e.maxWait)
|
|
select {
|
|
case err := <-errCh:
|
|
t.Stop()
|
|
return err
|
|
case <-t.C:
|
|
buf := new(strings.Builder)
|
|
pprof.Lookup("goroutine").WriteTo(buf, 1)
|
|
e.logf("wgengine watchdog stacks:\n%s", buf.String())
|
|
e.fatalf("wgengine: watchdog timeout on %s", name)
|
|
return nil
|
|
}
|
|
}
|
|
|
|
func (e *watchdogEngine) watchdog(name string, fn func()) {
|
|
e.watchdogErr(name, func() error {
|
|
fn()
|
|
return nil
|
|
})
|
|
}
|
|
|
|
func (e *watchdogEngine) Reconfig(cfg *wgcfg.Config, routerCfg *router.Config) error {
|
|
return e.watchdogErr("Reconfig", func() error { return e.wrap.Reconfig(cfg, routerCfg) })
|
|
}
|
|
func (e *watchdogEngine) GetLinkMonitor() *monitor.Mon {
|
|
return e.wrap.GetLinkMonitor()
|
|
}
|
|
func (e *watchdogEngine) GetFilter() *filter.Filter {
|
|
return e.wrap.GetFilter()
|
|
}
|
|
func (e *watchdogEngine) SetFilter(filt *filter.Filter) {
|
|
e.watchdog("SetFilter", func() { e.wrap.SetFilter(filt) })
|
|
}
|
|
func (e *watchdogEngine) SetDNSMap(dm *tsdns.Map) {
|
|
e.watchdog("SetDNSMap", func() { e.wrap.SetDNSMap(dm) })
|
|
}
|
|
func (e *watchdogEngine) SetStatusCallback(cb StatusCallback) {
|
|
e.watchdog("SetStatusCallback", func() { e.wrap.SetStatusCallback(cb) })
|
|
}
|
|
func (e *watchdogEngine) UpdateStatus(sb *ipnstate.StatusBuilder) {
|
|
e.watchdog("UpdateStatus", func() { e.wrap.UpdateStatus(sb) })
|
|
}
|
|
func (e *watchdogEngine) SetNetInfoCallback(cb NetInfoCallback) {
|
|
e.watchdog("SetNetInfoCallback", func() { e.wrap.SetNetInfoCallback(cb) })
|
|
}
|
|
func (e *watchdogEngine) RequestStatus() {
|
|
e.watchdog("RequestStatus", func() { e.wrap.RequestStatus() })
|
|
}
|
|
func (e *watchdogEngine) LinkChange(isExpensive bool) {
|
|
e.watchdog("LinkChange", func() { e.wrap.LinkChange(isExpensive) })
|
|
}
|
|
func (e *watchdogEngine) SetDERPMap(m *tailcfg.DERPMap) {
|
|
e.watchdog("SetDERPMap", func() { e.wrap.SetDERPMap(m) })
|
|
}
|
|
func (e *watchdogEngine) SetNetworkMap(nm *netmap.NetworkMap) {
|
|
e.watchdog("SetNetworkMap", func() { e.wrap.SetNetworkMap(nm) })
|
|
}
|
|
func (e *watchdogEngine) AddNetworkMapCallback(callback NetworkMapCallback) func() {
|
|
var fn func()
|
|
e.watchdog("AddNetworkMapCallback", func() { fn = e.wrap.AddNetworkMapCallback(callback) })
|
|
return func() { e.watchdog("RemoveNetworkMapCallback", fn) }
|
|
}
|
|
func (e *watchdogEngine) DiscoPublicKey() (k tailcfg.DiscoKey) {
|
|
e.watchdog("DiscoPublicKey", func() { k = e.wrap.DiscoPublicKey() })
|
|
return k
|
|
}
|
|
func (e *watchdogEngine) Ping(ip netaddr.IP, cb func(*ipnstate.PingResult)) {
|
|
e.watchdog("Ping", func() { e.wrap.Ping(ip, cb) })
|
|
}
|
|
func (e *watchdogEngine) Close() {
|
|
e.watchdog("Close", e.wrap.Close)
|
|
}
|
|
func (e *watchdogEngine) Wait() {
|
|
e.wrap.Wait()
|
|
}
|