mirror of
https://github.com/cloudflare/cloudflared.git
synced 2025-05-11 02:56:35 +00:00

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.
89 lines
2.0 KiB
Go
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
|
|
}
|