mirror of
https://github.com/tailscale/tailscale.git
synced 2024-11-29 04:55:31 +00:00
tailcfg, control/controlclient: add MapResponse.PingRequest
So the control server can test whether a client's actually present. Most clients are over HTTP/2, so these pings (to the same host) are super cheap. This mimics the earlier goroutine dump mechanism. Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
parent
e453c7ca57
commit
f45a9e291b
@ -676,6 +676,10 @@ func (c *Direct) sendMapRequest(ctx context.Context, maxPolls int, cb func(*netm
|
||||
return err
|
||||
}
|
||||
|
||||
if pr := resp.PingRequest; pr != nil {
|
||||
go answerPing(c.logf, c.httpc, pr)
|
||||
}
|
||||
|
||||
if resp.KeepAlive {
|
||||
vlogf("netmap: got keep-alive")
|
||||
} else {
|
||||
@ -1204,3 +1208,29 @@ func ipForwardingBroken(routes []netaddr.IPPrefix) bool {
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func answerPing(logf logger.Logf, c *http.Client, pr *tailcfg.PingRequest) {
|
||||
if pr.URL == "" {
|
||||
logf("invalid PingRequest with no URL")
|
||||
return
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
|
||||
defer cancel()
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, "HEAD", pr.URL, nil)
|
||||
if err != nil {
|
||||
logf("http.NewRequestWithContext(%q): %v", pr.URL, err)
|
||||
return
|
||||
}
|
||||
if pr.Log {
|
||||
logf("answerPing: sending ping to %v ...", pr.URL)
|
||||
}
|
||||
t0 := time.Now()
|
||||
_, err = c.Do(req)
|
||||
d := time.Since(t0).Round(time.Millisecond)
|
||||
if err != nil {
|
||||
logf("answerPing error: %v to %v (after %v)", err, pr.URL, d)
|
||||
} else if pr.Log {
|
||||
logf("answerPing complete to %v (after %v)", pr.URL, d)
|
||||
}
|
||||
}
|
||||
|
@ -35,6 +35,7 @@
|
||||
// 9: 2020-12-30: client doesn't auto-add implicit search domains from peers; only DNSConfig.Domains
|
||||
// 10: 2021-01-17: client understands MapResponse.PeerSeenChange
|
||||
// 11: 2021-03-03: client understands IPv6, multiple default routes, and goroutine dumping
|
||||
// 12: 2021-03-04: client understands PingRequest
|
||||
const CurrentMapRequestVersion = 11
|
||||
|
||||
type StableID string
|
||||
@ -714,8 +715,30 @@ type DNSConfig struct {
|
||||
Proxied bool
|
||||
}
|
||||
|
||||
// PingRequest is a request to send an HTTP request to prove the
|
||||
// long-polling client is still connected.
|
||||
type PingRequest struct {
|
||||
// URL is the URL to send a HEAD request to.
|
||||
// It will be a unique URL each time. No auth headers are necessary.
|
||||
URL string
|
||||
|
||||
// Log is whether to log about this ping in the success case.
|
||||
// For failure cases, the client will log regardless.
|
||||
Log bool `json:",omitempty"`
|
||||
}
|
||||
|
||||
type MapResponse struct {
|
||||
KeepAlive bool `json:",omitempty"` // if set, all other fields are ignored
|
||||
// KeepAlive, if set, represents an empty message just to keep
|
||||
// the connection alive. When true, all other fields except
|
||||
// PingRequestURL are ignored.
|
||||
KeepAlive bool `json:",omitempty"`
|
||||
|
||||
// PingRequest, if non-empty, is a request to the client to
|
||||
// prove it's still there by sending an HTTP request to the
|
||||
// provided URL. No auth headers are necessary.
|
||||
// PingRequest may be sent on any MapResponse (ones with
|
||||
// KeepAlive true or false).
|
||||
PingRequest *PingRequest `json:",omitempty"`
|
||||
|
||||
// Networking
|
||||
Node *Node
|
||||
|
Loading…
Reference in New Issue
Block a user