fix: use shared idle tracker for relay connections

connIdleTimeout previously set per-direction deadlines independently.
During media downloads the client→telegram direction can be idle at the
application level while telegram→client is actively streaming data.
After IdleTimeout (default 1 min) the idle direction's ReadDeadline
fires, tearing down the entire relay and breaking media transfers.

Replace the per-direction timeout with a shared atomic timestamp that
both pump goroutines update on any successful Read or Write. When a
ReadDeadline fires on the idle direction, we check the shared tracker:
if the other direction was recently active, we retry instead of closing.
The connection is only torn down when both directions are idle for the
full timeout period.

This matches the documented IdleTimeout contract: "if we have any
message which will pass to either direction, a timer is reset."

Overhead: one atomic.Int64 (8 bytes) per connection pair, one
atomic.Store (~1 ns) per Read/Write with data, zero extra goroutines.

Fixes #423
This commit is contained in:
Alexey Dolotov
2026-03-30 10:34:16 +03:00
parent 0840c7e3e5
commit 4627910238
2 changed files with 61 additions and 9 deletions
+8 -4
View File
@@ -102,11 +102,13 @@ func (p *Proxy) ServeConn(conn essentials.Conn) {
return
}
tracker := newIdleTracker(p.idleTimeout)
relay.Relay(
ctx,
ctx.logger.Named("relay"),
connIdleTimeout{Conn: ctx.telegramConn, timeout: p.idleTimeout},
connIdleTimeout{Conn: ctx.clientConn, timeout: p.idleTimeout},
connIdleTimeout{Conn: ctx.telegramConn, tracker: tracker},
connIdleTimeout{Conn: ctx.clientConn, tracker: tracker},
)
}
@@ -305,11 +307,13 @@ func (p *Proxy) doDomainFronting(ctx *streamContext, conn *connRewind) {
stream: p.eventStream,
}
tracker := newIdleTracker(p.idleTimeout)
relay.Relay(
ctx,
ctx.logger.Named("domain-fronting"),
connIdleTimeout{Conn: frontConn, timeout: p.idleTimeout},
connIdleTimeout{Conn: conn, timeout: p.idleTimeout},
connIdleTimeout{Conn: frontConn, tracker: tracker},
connIdleTimeout{Conn: conn, tracker: tracker},
)
}