wgengine/magicsock: don't block in Send waiting for derphttp.Send
Fixes
Updates
Updates
Updates
@@ -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)
- select {
- case <-c.donec():
- return errConnClosed
- case ch <- derpWriteRequest{addr, pubKey, b, errc}:
+
+ // 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 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
- }
}
}
}
