control/controlclient: fix deadlock in timeout+keepalive race

Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
pull/321/head
Brad Fitzpatrick 5 years ago committed by Dave Anderson
parent d052586da7
commit b8594dc937

@ -499,21 +499,25 @@ func (c *Direct) PollNetMap(ctx context.Context, maxPolls int, cb func(*NetworkM
const pollTimeout = 120 * time.Second const pollTimeout = 120 * time.Second
timeout := time.NewTimer(pollTimeout) timeout := time.NewTimer(pollTimeout)
timeoutReset := make(chan struct{}) timeoutReset := make(chan struct{})
defer close(timeoutReset) pollDone := make(chan struct{})
defer close(pollDone)
go func() { go func() {
for { for {
select { select {
case <-pollDone:
vlogf("netmap: ending timeout goroutine")
return
case <-timeout.C: case <-timeout.C:
c.logf("map response long-poll timed out!") c.logf("map response long-poll timed out!")
cancel() cancel()
return return
case _, ok := <-timeoutReset: case <-timeoutReset:
if !ok {
vlogf("netmap: ending timeout goroutine")
return // channel closed, shut down goroutine
}
if !timeout.Stop() { if !timeout.Stop() {
<-timeout.C select {
case <-timeout.C:
case <-pollDone:
return
}
} }
vlogf("netmap: reset timeout timer") vlogf("netmap: reset timeout timer")
timeout.Reset(pollTimeout) timeout.Reset(pollTimeout)
@ -551,7 +555,13 @@ func (c *Direct) PollNetMap(ctx context.Context, maxPolls int, cb func(*NetworkM
} }
if resp.KeepAlive { if resp.KeepAlive {
vlogf("netmap: got keep-alive") vlogf("netmap: got keep-alive")
timeoutReset <- struct{}{} select {
case timeoutReset <- struct{}{}:
vlogf("netmap: sent keep-alive timer reset")
case <-ctx.Done():
c.logf("netmap: not resetting timer for keep-alive due to: %v", ctx.Err())
return ctx.Err()
}
continue continue
} }
vlogf("netmap: got new map") vlogf("netmap: got new map")

Loading…
Cancel
Save