From 2d7ce00f5bdfdc460e9699fd1ae877c52c424902 Mon Sep 17 00:00:00 2001 From: David Fifield Date: Fri, 17 Apr 2026 14:56:05 +0000 Subject: [PATCH] Stop and drain the timer before Reset in sendLoop. Before go1.23, calling Stop, and draining the channel if the timer did not already fire, is necessary before calling Reset: https://pkg.go.dev/time@go1.22.12#Timer.Reset This changed in go1.23: now Reset automatically effectively drains the channel, and calling Stop is no longer necessary. https://pkg.go.dev/time@go1.23.9#Timer.Reset However, the changes in go1.23 only take effect if go.mod specifies 1.23 or later. We currently specify 1.21. https://go.dev/doc/go1.23#timer-changes For compatibility, do the Stop/drain procedure before calling Reset. We were already doing this for pollTimer in DNSPacketConn) sendLoop in dnstt-client. This change may not have any observable effect. The duration we Reset the timer to was 0, so if there had been a stale value in the channel because of a failure to drain it, the effect would be the same as waiting 0 seconds. We were already calling Stop when finished with the timer, so it would have been garbage-collectable even before go1.23. --- dnstt-server/main.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/dnstt-server/main.go b/dnstt-server/main.go index 047683c..19c8fdc 100644 --- a/dnstt-server/main.go +++ b/dnstt-server/main.go @@ -592,6 +592,7 @@ func sendLoop(dnsConn net.PacketConn, ttConn *turbotunnel.QueuePacketConn, ch <- // overflow the capacity of the DNS response, we stash // to be bundled into a future response. timer := time.NewTimer(maxResponseDelay) + timerExpired := false for { var p []byte unstash := ttConn.Unstash(rec.ClientID) @@ -612,6 +613,7 @@ func sendLoop(dnsConn net.PacketConn, ttConn *turbotunnel.QueuePacketConn, ch <- case p = <-unstash: case p = <-outgoing: case <-timer.C: + timerExpired = true case nextRec = <-ch: } } @@ -620,7 +622,11 @@ func sendLoop(dnsConn net.PacketConn, ttConn *turbotunnel.QueuePacketConn, ch <- // only. The second and later packets must be // immediately available or they will be omitted // from this bundle. + if !timerExpired && !timer.Stop() { + <-timer.C + } timer.Reset(0) + timerExpired = false if len(p) == 0 { // timer expired or receive on ch, we @@ -646,7 +652,9 @@ func sendLoop(dnsConn net.PacketConn, ttConn *turbotunnel.QueuePacketConn, ch <- binary.Write(&payload, binary.BigEndian, uint16(len(p))) payload.Write(p) } - timer.Stop() + if !timerExpired && !timer.Stop() { + <-timer.C + } rec.Resp.Answer[0].Data = dns.EncodeRDataTXT(payload.Bytes()) }