fix(dialer): detect dead QUIC sessions in ICMP/QUIC dialer caches

When a QUIC session's MaxIdleTimeout expires, the underlying *quic.Conn dies
but the dead quicSession stays in the sessions map. The next Dial() finds
it and calls session.GetConn() which calls OpenStreamSync(context.Background())
against the dead connection — blocking indefinitely.

Add IsClosed() to both quicSession types (using the session context's Done()
channel) and add the liveness guard in both Dial() methods, matching the
existing pattern in KCP and MASQUE dialers.

Fixes go-gost/gost#225
This commit is contained in:
ginuerzh
2026-06-20 20:25:18 +08:00
parent e583f5b538
commit 548471717a
4 changed files with 26 additions and 0 deletions
+9
View File
@@ -23,6 +23,15 @@ func (session *quicSession) GetConn() (*quicConn, error) {
}, nil
}
func (session *quicSession) IsClosed() bool {
select {
case <-session.session.Context().Done():
return true
default:
return false
}
}
func (session *quicSession) Close() error {
return session.session.CloseWithError(quic.ApplicationErrorCode(0), "closed")
}
+4
View File
@@ -61,6 +61,10 @@ func (d *quicDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialO
defer d.sessionMutex.Unlock()
session, ok := d.sessions[addr]
if session != nil && session.IsClosed() {
delete(d.sessions, addr) // session is dead
ok = false
}
if !ok {
options := &dialer.DialOptions{}
for _, opt := range opts {