@@ -26,22 +26,17 @@ type Conn struct {
2626 testHooks connTestHooks
2727 peerAddr netip.AddrPort
2828
29- msgc chan any
30- donec chan struct {} // closed when conn loop exits
31- exited bool // set to make the conn loop exit immediately
29+ msgc chan any
30+ donec chan struct {} // closed when conn loop exits
3231
3332 w packetWriter
3433 acks [numberSpaceCount ]ackState // indexed by number space
3534 lifetime lifetimeState
35+ idle idleState
3636 connIDState connIDState
3737 loss lossState
3838 streams streamsState
3939
40- // idleTimeout is the time at which the connection will be closed due to inactivity.
41- // https://www.rfc-editor.org/rfc/rfc9000#section-10.1
42- maxIdleTimeout time.Duration
43- idleTimeout time.Time
44-
4540 // Packet protection keys, CRYPTO streams, and TLS state.
4641 keysInitial fixedKeyPair
4742 keysHandshake fixedKeyPair
@@ -105,8 +100,6 @@ func newConn(now time.Time, side connSide, cids newServerConnIDs, peerAddr netip
105100 peerAddr : peerAddr ,
106101 msgc : make (chan any , 1 ),
107102 donec : make (chan struct {}),
108- maxIdleTimeout : defaultMaxIdleTimeout ,
109- idleTimeout : now .Add (defaultMaxIdleTimeout ),
110103 peerAckDelayExponent : - 1 ,
111104 }
112105 defer func () {
@@ -151,6 +144,7 @@ func newConn(now time.Time, side connSide, cids newServerConnIDs, peerAddr netip
151144 c .loss .init (c .side , maxDatagramSize , now )
152145 c .streamsInit ()
153146 c .lifetimeInit ()
147+ c .restartIdleTimer (now )
154148
155149 if err := c .startTLS (now , initialConnID , transportParameters {
156150 initialSrcConnID : c .connIDState .srcConnID (),
@@ -202,6 +196,7 @@ func (c *Conn) confirmHandshake(now time.Time) {
202196 // don't need to send anything.
203197 c .handshakeConfirmed .setReceived ()
204198 }
199+ c .restartIdleTimer (now )
205200 c .loss .confirmHandshake ()
206201 // "An endpoint MUST discard its Handshake keys when the TLS handshake is confirmed"
207202 // https://www.rfc-editor.org/rfc/rfc9001#section-4.9.2-1
@@ -232,6 +227,7 @@ func (c *Conn) receiveTransportParameters(p transportParameters) error {
232227 c .streams .peerInitialMaxStreamDataBidiLocal = p .initialMaxStreamDataBidiLocal
233228 c .streams .peerInitialMaxStreamDataRemote [bidiStream ] = p .initialMaxStreamDataBidiRemote
234229 c .streams .peerInitialMaxStreamDataRemote [uniStream ] = p .initialMaxStreamDataUni
230+ c .receivePeerMaxIdleTimeout (p .maxIdleTimeout )
235231 c .peerAckDelayExponent = p .ackDelayExponent
236232 c .loss .setMaxAckDelay (p .maxAckDelay )
237233 if err := c .connIDState .setPeerActiveConnIDLimit (c , p .activeConnIDLimit ); err != nil {
@@ -248,7 +244,6 @@ func (c *Conn) receiveTransportParameters(p transportParameters) error {
248244 return err
249245 }
250246 }
251- // TODO: max_idle_timeout
252247 // TODO: stateless_reset_token
253248 // TODO: max_udp_payload_size
254249 // TODO: disable_active_migration
@@ -261,6 +256,8 @@ type (
261256 wakeEvent struct {}
262257)
263258
259+ var errIdleTimeout = errors .New ("idle timeout" )
260+
264261// loop is the connection main loop.
265262//
266263// Except where otherwise noted, all connection state is owned by the loop goroutine.
@@ -288,14 +285,14 @@ func (c *Conn) loop(now time.Time) {
288285 defer timer .Stop ()
289286 }
290287
291- for ! c . exited {
288+ for c . lifetime . state != connStateDone {
292289 sendTimeout := c .maybeSend (now ) // try sending
293290
294291 // Note that we only need to consider the ack timer for the App Data space,
295292 // since the Initial and Handshake spaces always ack immediately.
296293 nextTimeout := sendTimeout
297- nextTimeout = firstTime (nextTimeout , c .idleTimeout )
298- if ! c . isClosingOrDraining () {
294+ nextTimeout = firstTime (nextTimeout , c .idle . nextTimeout )
295+ if c . isAlive () {
299296 nextTimeout = firstTime (nextTimeout , c .loss .timer )
300297 nextTimeout = firstTime (nextTimeout , c .acks [appDataSpace ].nextAck )
301298 } else {
@@ -329,11 +326,9 @@ func (c *Conn) loop(now time.Time) {
329326 m .recycle ()
330327 case timerEvent :
331328 // A connection timer has expired.
332- if ! now .Before (c .idleTimeout ) {
333- // "[...] the connection is silently closed and
334- // its state is discarded [...]"
335- // https://www.rfc-editor.org/rfc/rfc9000#section-10.1-1
336- c .exited = true
329+ if c .idleAdvance (now ) {
330+ // The connection idle timer has expired.
331+ c .abortImmediately (now , errIdleTimeout )
337332 return
338333 }
339334 c .loss .advance (now , c .handleAckOrLoss )
0 commit comments