golang.org/x/net@v0.25.1-0.20240516223405-c87a5b62e243/quic/conn_close_test.go (about) 1 // Copyright 2023 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 //go:build go1.21 6 7 package quic 8 9 import ( 10 "context" 11 "crypto/tls" 12 "errors" 13 "testing" 14 "time" 15 ) 16 17 func TestConnCloseResponseBackoff(t *testing.T) { 18 tc := newTestConn(t, clientSide, func(c *Config) { 19 clear(c.StatelessResetKey[:]) 20 }) 21 tc.handshake() 22 23 tc.conn.Abort(nil) 24 tc.wantFrame("aborting connection generates CONN_CLOSE", 25 packetType1RTT, debugFrameConnectionCloseTransport{ 26 code: errNo, 27 }) 28 29 waiting := runAsync(tc, func(ctx context.Context) (struct{}, error) { 30 return struct{}{}, tc.conn.Wait(ctx) 31 }) 32 if _, err := waiting.result(); err != errNotDone { 33 t.Errorf("conn.Wait() = %v, want still waiting", err) 34 } 35 36 tc.writeFrames(packetType1RTT, debugFramePing{}) 37 tc.wantIdle("packets received immediately after CONN_CLOSE receive no response") 38 39 tc.advance(1100 * time.Microsecond) 40 tc.writeFrames(packetType1RTT, debugFramePing{}) 41 tc.wantFrame("receiving packet 1.1ms after CONN_CLOSE generates another CONN_CLOSE", 42 packetType1RTT, debugFrameConnectionCloseTransport{ 43 code: errNo, 44 }) 45 46 tc.advance(1100 * time.Microsecond) 47 tc.writeFrames(packetType1RTT, debugFramePing{}) 48 tc.wantIdle("no response to packet, because CONN_CLOSE backoff is now 2ms") 49 50 tc.advance(1000 * time.Microsecond) 51 tc.writeFrames(packetType1RTT, debugFramePing{}) 52 tc.wantFrame("2ms since last CONN_CLOSE, receiving a packet generates another CONN_CLOSE", 53 packetType1RTT, debugFrameConnectionCloseTransport{ 54 code: errNo, 55 }) 56 if _, err := waiting.result(); err != errNotDone { 57 t.Errorf("conn.Wait() = %v, want still waiting", err) 58 } 59 60 tc.advance(100000 * time.Microsecond) 61 tc.writeFrames(packetType1RTT, debugFramePing{}) 62 tc.wantIdle("drain timer expired, no more responses") 63 64 if _, err := waiting.result(); !errors.Is(err, errNoPeerResponse) { 65 t.Errorf("blocked conn.Wait() = %v, want errNoPeerResponse", err) 66 } 67 if err := tc.conn.Wait(canceledContext()); !errors.Is(err, errNoPeerResponse) { 68 t.Errorf("non-blocking conn.Wait() = %v, want errNoPeerResponse", err) 69 } 70 } 71 72 func TestConnCloseWithPeerResponse(t *testing.T) { 73 qr := &qlogRecord{} 74 tc := newTestConn(t, clientSide, qr.config) 75 tc.handshake() 76 77 tc.conn.Abort(nil) 78 tc.wantFrame("aborting connection generates CONN_CLOSE", 79 packetType1RTT, debugFrameConnectionCloseTransport{ 80 code: errNo, 81 }) 82 83 waiting := runAsync(tc, func(ctx context.Context) (struct{}, error) { 84 return struct{}{}, tc.conn.Wait(ctx) 85 }) 86 if _, err := waiting.result(); err != errNotDone { 87 t.Errorf("conn.Wait() = %v, want still waiting", err) 88 } 89 90 tc.writeFrames(packetType1RTT, debugFrameConnectionCloseApplication{ 91 code: 20, 92 }) 93 94 wantErr := &ApplicationError{ 95 Code: 20, 96 } 97 if _, err := waiting.result(); !errors.Is(err, wantErr) { 98 t.Errorf("blocked conn.Wait() = %v, want %v", err, wantErr) 99 } 100 if err := tc.conn.Wait(canceledContext()); !errors.Is(err, wantErr) { 101 t.Errorf("non-blocking conn.Wait() = %v, want %v", err, wantErr) 102 } 103 104 tc.advance(1 * time.Second) // long enough to exit the draining state 105 qr.wantEvents(t, jsonEvent{ 106 "name": "connectivity:connection_closed", 107 "data": map[string]any{ 108 "trigger": "application", 109 }, 110 }) 111 } 112 113 func TestConnClosePeerCloses(t *testing.T) { 114 qr := &qlogRecord{} 115 tc := newTestConn(t, clientSide, qr.config) 116 tc.handshake() 117 118 wantErr := &ApplicationError{ 119 Code: 42, 120 Reason: "why?", 121 } 122 tc.writeFrames(packetType1RTT, debugFrameConnectionCloseApplication{ 123 code: wantErr.Code, 124 reason: wantErr.Reason, 125 }) 126 tc.wantIdle("CONN_CLOSE response not sent until user closes this side") 127 128 if err := tc.conn.Wait(canceledContext()); !errors.Is(err, wantErr) { 129 t.Errorf("conn.Wait() = %v, want %v", err, wantErr) 130 } 131 132 tc.conn.Abort(&ApplicationError{ 133 Code: 9, 134 Reason: "because", 135 }) 136 tc.wantFrame("CONN_CLOSE sent after user closes connection", 137 packetType1RTT, debugFrameConnectionCloseApplication{ 138 code: 9, 139 reason: "because", 140 }) 141 142 tc.advance(1 * time.Second) // long enough to exit the draining state 143 qr.wantEvents(t, jsonEvent{ 144 "name": "connectivity:connection_closed", 145 "data": map[string]any{ 146 "trigger": "application", 147 }, 148 }) 149 } 150 151 func TestConnCloseReceiveInInitial(t *testing.T) { 152 tc := newTestConn(t, clientSide) 153 tc.wantFrame("client sends Initial CRYPTO frame", 154 packetTypeInitial, debugFrameCrypto{ 155 data: tc.cryptoDataOut[tls.QUICEncryptionLevelInitial], 156 }) 157 tc.writeFrames(packetTypeInitial, debugFrameConnectionCloseTransport{ 158 code: errConnectionRefused, 159 }) 160 tc.wantIdle("CONN_CLOSE response not sent until user closes this side") 161 162 wantErr := peerTransportError{code: errConnectionRefused} 163 if err := tc.conn.Wait(canceledContext()); !errors.Is(err, wantErr) { 164 t.Errorf("conn.Wait() = %v, want %v", err, wantErr) 165 } 166 167 tc.conn.Abort(&ApplicationError{Code: 1}) 168 tc.wantFrame("CONN_CLOSE in Initial frame is APPLICATION_ERROR", 169 packetTypeInitial, debugFrameConnectionCloseTransport{ 170 code: errApplicationError, 171 }) 172 tc.wantIdle("no more frames to send") 173 } 174 175 func TestConnCloseReceiveInHandshake(t *testing.T) { 176 tc := newTestConn(t, clientSide) 177 tc.ignoreFrame(frameTypeAck) 178 tc.wantFrame("client sends Initial CRYPTO frame", 179 packetTypeInitial, debugFrameCrypto{ 180 data: tc.cryptoDataOut[tls.QUICEncryptionLevelInitial], 181 }) 182 tc.writeFrames(packetTypeInitial, debugFrameCrypto{ 183 data: tc.cryptoDataIn[tls.QUICEncryptionLevelInitial], 184 }) 185 tc.writeFrames(packetTypeHandshake, debugFrameConnectionCloseTransport{ 186 code: errConnectionRefused, 187 }) 188 tc.wantIdle("CONN_CLOSE response not sent until user closes this side") 189 190 wantErr := peerTransportError{code: errConnectionRefused} 191 if err := tc.conn.Wait(canceledContext()); !errors.Is(err, wantErr) { 192 t.Errorf("conn.Wait() = %v, want %v", err, wantErr) 193 } 194 195 // The conn has Initial and Handshake keys, so it will send CONN_CLOSE in both spaces. 196 tc.conn.Abort(&ApplicationError{Code: 1}) 197 tc.wantFrame("CONN_CLOSE in Initial frame is APPLICATION_ERROR", 198 packetTypeInitial, debugFrameConnectionCloseTransport{ 199 code: errApplicationError, 200 }) 201 tc.wantFrame("CONN_CLOSE in Handshake frame is APPLICATION_ERROR", 202 packetTypeHandshake, debugFrameConnectionCloseTransport{ 203 code: errApplicationError, 204 }) 205 tc.wantIdle("no more frames to send") 206 } 207 208 func TestConnCloseClosedByEndpoint(t *testing.T) { 209 ctx := canceledContext() 210 tc := newTestConn(t, clientSide) 211 tc.handshake() 212 213 tc.endpoint.e.Close(ctx) 214 tc.wantFrame("endpoint closes connection before exiting", 215 packetType1RTT, debugFrameConnectionCloseTransport{ 216 code: errNo, 217 }) 218 } 219 220 func testConnCloseUnblocks(t *testing.T, f func(context.Context, *testConn) error, opts ...any) { 221 tc := newTestConn(t, clientSide, opts...) 222 tc.handshake() 223 op := runAsync(tc, func(ctx context.Context) (struct{}, error) { 224 return struct{}{}, f(ctx, tc) 225 }) 226 if _, err := op.result(); err != errNotDone { 227 t.Fatalf("before abort, op = %v, want errNotDone", err) 228 } 229 tc.conn.Abort(nil) 230 if _, err := op.result(); err == nil || err == errNotDone { 231 t.Fatalf("after abort, op = %v, want error", err) 232 } 233 } 234 235 func TestConnCloseUnblocksAcceptStream(t *testing.T) { 236 testConnCloseUnblocks(t, func(ctx context.Context, tc *testConn) error { 237 _, err := tc.conn.AcceptStream(ctx) 238 return err 239 }, permissiveTransportParameters) 240 } 241 242 func TestConnCloseUnblocksNewStream(t *testing.T) { 243 testConnCloseUnblocks(t, func(ctx context.Context, tc *testConn) error { 244 _, err := tc.conn.NewStream(ctx) 245 return err 246 }) 247 } 248 249 func TestConnCloseUnblocksStreamRead(t *testing.T) { 250 testConnCloseUnblocks(t, func(ctx context.Context, tc *testConn) error { 251 s := newLocalStream(t, tc, bidiStream) 252 s.SetReadContext(ctx) 253 buf := make([]byte, 16) 254 _, err := s.Read(buf) 255 return err 256 }, permissiveTransportParameters) 257 } 258 259 func TestConnCloseUnblocksStreamWrite(t *testing.T) { 260 testConnCloseUnblocks(t, func(ctx context.Context, tc *testConn) error { 261 s := newLocalStream(t, tc, bidiStream) 262 s.SetWriteContext(ctx) 263 buf := make([]byte, 32) 264 _, err := s.Write(buf) 265 return err 266 }, permissiveTransportParameters, func(c *Config) { 267 c.MaxStreamWriteBufferSize = 16 268 }) 269 } 270 271 func TestConnCloseUnblocksStreamClose(t *testing.T) { 272 testConnCloseUnblocks(t, func(ctx context.Context, tc *testConn) error { 273 s := newLocalStream(t, tc, bidiStream) 274 s.SetWriteContext(ctx) 275 buf := make([]byte, 16) 276 _, err := s.Write(buf) 277 if err != nil { 278 return err 279 } 280 return s.Close() 281 }, permissiveTransportParameters) 282 }