cloudflared/vendor/github.com/lucas-clemente/quic-go/send_queue.go
Nuno Diegues 475939a77f TUN-6191: Update quic-go to v0.27.1 and with custom patch to allow keep alive period to be configurable
The idle period is set to 5sec.

We now also ping every second since last activity.
This makes the quic.Connection less prone to being closed with
no network activity, since we send multiple pings per idle
period, and thus a single packet loss cannot cause the problem.
2022-06-07 12:25:18 +01:00

89 lines
2.0 KiB
Go

package quic
type sender interface {
Send(p *packetBuffer)
Run() error
WouldBlock() bool
Available() <-chan struct{}
Close()
}
type sendQueue struct {
queue chan *packetBuffer
closeCalled chan struct{} // runStopped when Close() is called
runStopped chan struct{} // runStopped when the run loop returns
available chan struct{}
conn sendConn
}
var _ sender = &sendQueue{}
const sendQueueCapacity = 8
func newSendQueue(conn sendConn) sender {
return &sendQueue{
conn: conn,
runStopped: make(chan struct{}),
closeCalled: make(chan struct{}),
available: make(chan struct{}, 1),
queue: make(chan *packetBuffer, sendQueueCapacity),
}
}
// Send sends out a packet. It's guaranteed to not block.
// Callers need to make sure that there's actually space in the send queue by calling WouldBlock.
// Otherwise Send will panic.
func (h *sendQueue) Send(p *packetBuffer) {
select {
case h.queue <- p:
case <-h.runStopped:
default:
panic("sendQueue.Send would have blocked")
}
}
func (h *sendQueue) WouldBlock() bool {
return len(h.queue) == sendQueueCapacity
}
func (h *sendQueue) Available() <-chan struct{} {
return h.available
}
func (h *sendQueue) Run() error {
defer close(h.runStopped)
var shouldClose bool
for {
if shouldClose && len(h.queue) == 0 {
return nil
}
select {
case <-h.closeCalled:
h.closeCalled = nil // prevent this case from being selected again
// make sure that all queued packets are actually sent out
shouldClose = true
case p := <-h.queue:
if err := h.conn.Write(p.Data); err != nil {
// This additional check enables:
// 1. Checking for "datagram too large" message from the kernel, as such,
// 2. Path MTU discovery,and
// 3. Eventual detection of loss PingFrame.
if !isMsgSizeErr(err) {
return err
}
}
p.Release()
select {
case h.available <- struct{}{}:
default:
}
}
}
}
func (h *sendQueue) Close() {
close(h.closeCalled)
// wait until the run loop returned
<-h.runStopped
}