wgengine/magicsock: don't block in Send waiting for derphttp.Send

Fixes #137
Updates #109
Updates #162
Updates #163

Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
pull/182/head
Brad Fitzpatrick 4 years ago committed by Brad Fitzpatrick
parent 8807913be9
commit bc73dcf204

@ -666,17 +666,20 @@ func (c *Conn) sendAddr(addr *net.UDPAddr, pubKey key.Public, b []byte) error {
if ch == nil {
return nil
}
errc := make(chan error, 1)
// TODO(bradfitz): this makes garbage for now; we could use a
// buffer pool later. Previously we passed ownership of this
// to derpWriteRequest and waited for derphttp.Client.Send to
// complete, but that's too slow while holding wireguard-go
// internal locks.
pkt := make([]byte, len(b))
copy(pkt, b)
select {
case <-c.donec():
return errConnClosed
case ch <- derpWriteRequest{addr, pubKey, b, errc}:
select {
case <-c.donec():
return errConnClosed
case err := <-errc:
return err // usually nil
}
case ch <- derpWriteRequest{addr, pubKey, pkt}:
return nil
default:
// Too many writes queued. Drop packet.
return errDropDerpPacket
@ -838,8 +841,7 @@ func (c *Conn) runDerpReader(ctx context.Context, derpFakeAddr *net.UDPAddr, dc
type derpWriteRequest struct {
addr *net.UDPAddr
pubKey key.Public
b []byte
errc chan<- error
b []byte // copied; ownership passed to receiver
}
// runDerpWriter runs in a goroutine for the life of a DERP
@ -861,11 +863,6 @@ func (c *Conn) runDerpWriter(ctx context.Context, derpFakeAddr *net.UDPAddr, dc
if err != nil {
c.logf("magicsock: derp.Send(%v): %v", wr.addr, err)
}
select {
case wr.errc <- err:
case <-c.donec(): // Note: not ctx.Done: sendAddr (receiver) has different lifetime than ctx.
return
}
}
}
}

Loading…
Cancel
Save