@@ -26,22 +26,17 @@ type Conn struct {
26
26
testHooks connTestHooks
27
27
peerAddr netip.AddrPort
28
28
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
32
31
33
32
w packetWriter
34
33
acks [numberSpaceCount ]ackState // indexed by number space
35
34
lifetime lifetimeState
35
+ idle idleState
36
36
connIDState connIDState
37
37
loss lossState
38
38
streams streamsState
39
39
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
-
45
40
// Packet protection keys, CRYPTO streams, and TLS state.
46
41
keysInitial fixedKeyPair
47
42
keysHandshake fixedKeyPair
@@ -105,8 +100,6 @@ func newConn(now time.Time, side connSide, cids newServerConnIDs, peerAddr netip
105
100
peerAddr : peerAddr ,
106
101
msgc : make (chan any , 1 ),
107
102
donec : make (chan struct {}),
108
- maxIdleTimeout : defaultMaxIdleTimeout ,
109
- idleTimeout : now .Add (defaultMaxIdleTimeout ),
110
103
peerAckDelayExponent : - 1 ,
111
104
}
112
105
defer func () {
@@ -151,6 +144,7 @@ func newConn(now time.Time, side connSide, cids newServerConnIDs, peerAddr netip
151
144
c .loss .init (c .side , maxDatagramSize , now )
152
145
c .streamsInit ()
153
146
c .lifetimeInit ()
147
+ c .restartIdleTimer (now )
154
148
155
149
if err := c .startTLS (now , initialConnID , transportParameters {
156
150
initialSrcConnID : c .connIDState .srcConnID (),
@@ -202,6 +196,7 @@ func (c *Conn) confirmHandshake(now time.Time) {
202
196
// don't need to send anything.
203
197
c .handshakeConfirmed .setReceived ()
204
198
}
199
+ c .restartIdleTimer (now )
205
200
c .loss .confirmHandshake ()
206
201
// "An endpoint MUST discard its Handshake keys when the TLS handshake is confirmed"
207
202
// https://www.rfc-editor.org/rfc/rfc9001#section-4.9.2-1
@@ -232,6 +227,7 @@ func (c *Conn) receiveTransportParameters(p transportParameters) error {
232
227
c .streams .peerInitialMaxStreamDataBidiLocal = p .initialMaxStreamDataBidiLocal
233
228
c .streams .peerInitialMaxStreamDataRemote [bidiStream ] = p .initialMaxStreamDataBidiRemote
234
229
c .streams .peerInitialMaxStreamDataRemote [uniStream ] = p .initialMaxStreamDataUni
230
+ c .receivePeerMaxIdleTimeout (p .maxIdleTimeout )
235
231
c .peerAckDelayExponent = p .ackDelayExponent
236
232
c .loss .setMaxAckDelay (p .maxAckDelay )
237
233
if err := c .connIDState .setPeerActiveConnIDLimit (c , p .activeConnIDLimit ); err != nil {
@@ -248,7 +244,6 @@ func (c *Conn) receiveTransportParameters(p transportParameters) error {
248
244
return err
249
245
}
250
246
}
251
- // TODO: max_idle_timeout
252
247
// TODO: stateless_reset_token
253
248
// TODO: max_udp_payload_size
254
249
// TODO: disable_active_migration
@@ -261,6 +256,8 @@ type (
261
256
wakeEvent struct {}
262
257
)
263
258
259
+ var errIdleTimeout = errors .New ("idle timeout" )
260
+
264
261
// loop is the connection main loop.
265
262
//
266
263
// Except where otherwise noted, all connection state is owned by the loop goroutine.
@@ -288,14 +285,14 @@ func (c *Conn) loop(now time.Time) {
288
285
defer timer .Stop ()
289
286
}
290
287
291
- for ! c . exited {
288
+ for c . lifetime . state != connStateDone {
292
289
sendTimeout := c .maybeSend (now ) // try sending
293
290
294
291
// Note that we only need to consider the ack timer for the App Data space,
295
292
// since the Initial and Handshake spaces always ack immediately.
296
293
nextTimeout := sendTimeout
297
- nextTimeout = firstTime (nextTimeout , c .idleTimeout )
298
- if ! c . isClosingOrDraining () {
294
+ nextTimeout = firstTime (nextTimeout , c .idle . nextTimeout )
295
+ if c . isAlive () {
299
296
nextTimeout = firstTime (nextTimeout , c .loss .timer )
300
297
nextTimeout = firstTime (nextTimeout , c .acks [appDataSpace ].nextAck )
301
298
} else {
@@ -329,11 +326,9 @@ func (c *Conn) loop(now time.Time) {
329
326
m .recycle ()
330
327
case timerEvent :
331
328
// 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 )
337
332
return
338
333
}
339
334
c .loss .advance (now , c .handleAckOrLoss )
0 commit comments