derp/derphttp: avoid endless reconnect race on failure
Originally from @stablebits (Dmitry Adamushko) in: https://github.com/tailscale/tailscale/pull/264pull/296/head
parent
347a926ac4
commit
614eec174f
|
@ -240,7 +240,7 @@ func (c *Client) Send(dstKey key.Public, b []byte) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := client.Send(dstKey, b); err != nil {
|
if err := client.Send(dstKey, b); err != nil {
|
||||||
c.closeForReconnect()
|
c.closeForReconnect(client)
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -259,7 +259,7 @@ func (c *Client) NotePreferred(v bool) {
|
||||||
|
|
||||||
if client != nil {
|
if client != nil {
|
||||||
if err := client.NotePreferred(v); err != nil {
|
if err := client.NotePreferred(v); err != nil {
|
||||||
c.closeForReconnect()
|
c.closeForReconnect(client)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -271,7 +271,7 @@ func (c *Client) Recv(b []byte) (derp.ReceivedMessage, error) {
|
||||||
}
|
}
|
||||||
m, err := client.Recv(b)
|
m, err := client.Recv(b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.closeForReconnect()
|
c.closeForReconnect(client)
|
||||||
}
|
}
|
||||||
return m, err
|
return m, err
|
||||||
}
|
}
|
||||||
|
@ -296,9 +296,19 @@ func (c *Client) Close() error {
|
||||||
// closeForReconnect closes the underlying network connection and
|
// closeForReconnect closes the underlying network connection and
|
||||||
// zeros out the client field so future calls to Connect will
|
// zeros out the client field so future calls to Connect will
|
||||||
// reconnect.
|
// reconnect.
|
||||||
func (c *Client) closeForReconnect() {
|
//
|
||||||
|
// The provided brokenClient is the client to forget. If current
|
||||||
|
// client is not brokenClient, closeForReconnect does nothing. (This
|
||||||
|
// prevents a send and receive goroutine from failing at the ~same
|
||||||
|
// time and both calling closeForReconnect and the caller goroutines
|
||||||
|
// forever calling closeForReconnect in lockstep endlessly;
|
||||||
|
// https://github.com/tailscale/tailscale/pull/264)
|
||||||
|
func (c *Client) closeForReconnect(brokenClient *derp.Client) {
|
||||||
c.mu.Lock()
|
c.mu.Lock()
|
||||||
defer c.mu.Unlock()
|
defer c.mu.Unlock()
|
||||||
|
if c.client != brokenClient {
|
||||||
|
return
|
||||||
|
}
|
||||||
if c.netConn != nil {
|
if c.netConn != nil {
|
||||||
c.netConn.Close()
|
c.netConn.Close()
|
||||||
c.netConn = nil
|
c.netConn = nil
|
||||||
|
|
Loading…
Reference in New Issue