1
2
3
4
5 package quic
6
7 import (
8 "context"
9 "errors"
10 "time"
11 )
12
13
14 type connState int
15
16 const (
17
18 connStateAlive = connState(iota)
19
20
21
22
23
24 connStatePeerClosed
25
26
27
28
29
30
31
32
33
34
35 connStateClosing
36
37
38
39
40
41
42
43 connStateDraining
44
45
46 connStateDone
47 )
48
49
50
51
52
53 type lifetimeState struct {
54 state connState
55
56 readyc chan struct{}
57 donec chan struct{}
58
59 localErr error
60 finalErr error
61
62 connCloseSentTime time.Time
63 connCloseDelay time.Duration
64 drainEndTime time.Time
65 }
66
67 func (c *Conn) lifetimeInit() {
68 c.lifetime.readyc = make(chan struct{})
69 c.lifetime.donec = make(chan struct{})
70 }
71
72 var (
73 errNoPeerResponse = errors.New("peer did not respond to CONNECTION_CLOSE")
74 errConnClosed = errors.New("connection closed")
75 )
76
77
78 func (c *Conn) lifetimeAdvance(now time.Time) (done bool) {
79 if c.lifetime.drainEndTime.IsZero() || c.lifetime.drainEndTime.After(now) {
80 return false
81 }
82
83
84 c.lifetime.drainEndTime = time.Time{}
85 if c.lifetime.state != connStateDraining {
86
87 c.setFinalError(errNoPeerResponse)
88 }
89 c.setState(now, connStateDone)
90 return true
91 }
92
93
94 func (c *Conn) setState(now time.Time, state connState) {
95 if c.lifetime.state == state {
96 return
97 }
98 c.lifetime.state = state
99 switch state {
100 case connStateClosing, connStateDraining:
101 if c.lifetime.drainEndTime.IsZero() {
102 c.lifetime.drainEndTime = now.Add(3 * c.loss.ptoBasePeriod())
103 }
104 case connStateDone:
105 c.setFinalError(nil)
106 }
107 if state != connStateAlive {
108 c.restartIdleTimer(now)
109 c.streamsCleanup()
110 }
111 }
112
113
114 func (c *Conn) handshakeDone() {
115 close(c.lifetime.readyc)
116 }
117
118
119
120
121
122
123
124
125
126 func (c *Conn) isDraining() bool {
127 switch c.lifetime.state {
128 case connStateDraining, connStateDone:
129 return true
130 }
131 return false
132 }
133
134
135 func (c *Conn) isAlive() bool {
136 return c.lifetime.state == connStateAlive
137 }
138
139
140 func (c *Conn) sendOK(now time.Time) bool {
141 switch c.lifetime.state {
142 case connStateAlive:
143 return true
144 case connStatePeerClosed:
145 if c.lifetime.localErr == nil {
146
147
148 return false
149 }
150
151 return true
152 case connStateClosing:
153 if c.lifetime.connCloseSentTime.IsZero() {
154 return true
155 }
156 maxRecvTime := c.acks[initialSpace].maxRecvTime
157 if t := c.acks[handshakeSpace].maxRecvTime; t.After(maxRecvTime) {
158 maxRecvTime = t
159 }
160 if t := c.acks[appDataSpace].maxRecvTime; t.After(maxRecvTime) {
161 maxRecvTime = t
162 }
163 if maxRecvTime.Before(c.lifetime.connCloseSentTime.Add(c.lifetime.connCloseDelay)) {
164
165
166
167 return false
168 }
169 return true
170 case connStateDraining:
171
172 return false
173 case connStateDone:
174 return false
175 default:
176 panic("BUG: unhandled connection state")
177 }
178 }
179
180
181 func (c *Conn) sentConnectionClose(now time.Time) {
182 switch c.lifetime.state {
183 case connStatePeerClosed:
184 c.enterDraining(now)
185 }
186 if c.lifetime.connCloseSentTime.IsZero() {
187
188
189
190
191
192
193 c.lifetime.connCloseDelay = c.loss.rtt.smoothedRTT + max(4*c.loss.rtt.rttvar, timerGranularity)
194 } else if !c.lifetime.connCloseSentTime.Equal(now) {
195
196
197 c.lifetime.connCloseDelay *= 2
198 }
199 c.lifetime.connCloseSentTime = now
200 }
201
202
203 func (c *Conn) handlePeerConnectionClose(now time.Time, err error) {
204 c.setFinalError(err)
205 switch c.lifetime.state {
206 case connStateAlive:
207 c.setState(now, connStatePeerClosed)
208 case connStatePeerClosed:
209
210 case connStateClosing:
211 if c.lifetime.connCloseSentTime.IsZero() {
212 c.setState(now, connStatePeerClosed)
213 } else {
214 c.setState(now, connStateDraining)
215 }
216 case connStateDraining:
217 case connStateDone:
218 }
219 }
220
221
222 func (c *Conn) setFinalError(err error) {
223 select {
224 case <-c.lifetime.donec:
225 return
226 default:
227 }
228 c.lifetime.finalErr = err
229 close(c.lifetime.donec)
230 }
231
232
233
234 func (c *Conn) finalError() error {
235 select {
236 case <-c.lifetime.donec:
237 return c.lifetime.finalErr
238 default:
239 }
240 return nil
241 }
242
243 func (c *Conn) waitReady(ctx context.Context) error {
244 select {
245 case <-c.lifetime.readyc:
246 return nil
247 case <-c.lifetime.donec:
248 return c.lifetime.finalErr
249 default:
250 }
251 select {
252 case <-c.lifetime.readyc:
253 return nil
254 case <-c.lifetime.donec:
255 return c.lifetime.finalErr
256 case <-ctx.Done():
257 return ctx.Err()
258 }
259 }
260
261
262
263
264
265
266
267 func (c *Conn) Close() error {
268 c.Abort(nil)
269 <-c.lifetime.donec
270 return c.lifetime.finalErr
271 }
272
273
274
275
276
277
278
279
280
281
282 func (c *Conn) Wait(ctx context.Context) error {
283 if err := c.waitOnDone(ctx, c.lifetime.donec); err != nil {
284 return err
285 }
286 return c.lifetime.finalErr
287 }
288
289
290
291
292
293
294 func (c *Conn) Abort(err error) {
295 if err == nil {
296 err = localTransportError{code: errNo}
297 }
298 c.sendMsg(func(now time.Time, c *Conn) {
299 c.enterClosing(now, err)
300 })
301 }
302
303
304 func (c *Conn) abort(now time.Time, err error) {
305 c.setFinalError(err)
306 c.enterClosing(now, err)
307 }
308
309
310
311 func (c *Conn) abortImmediately(now time.Time, err error) {
312 c.setFinalError(err)
313 c.setState(now, connStateDone)
314 }
315
316
317
318 func (c *Conn) enterClosing(now time.Time, err error) {
319 switch c.lifetime.state {
320 case connStateAlive:
321 c.lifetime.localErr = err
322 c.setState(now, connStateClosing)
323 case connStatePeerClosed:
324 c.lifetime.localErr = err
325 }
326 }
327
328
329 func (c *Conn) enterDraining(now time.Time) {
330 switch c.lifetime.state {
331 case connStateAlive, connStatePeerClosed, connStateClosing:
332 c.setState(now, connStateDraining)
333 }
334 }
335
336
337 func (c *Conn) exit() {
338 c.sendMsg(func(now time.Time, c *Conn) {
339 c.abortImmediately(now, errors.New("connection closed"))
340 })
341 }
342
View as plain text