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