golang.org/x/net@v0.25.1-0.20240516223405-c87a5b62e243/quic/conn_flow_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 "testing" 12 ) 13 14 func TestConnInflowReturnOnRead(t *testing.T) { 15 tc, s := newTestConnAndRemoteStream(t, serverSide, uniStream, func(c *Config) { 16 c.MaxConnReadBufferSize = 64 17 }) 18 tc.writeFrames(packetType1RTT, debugFrameStream{ 19 id: s.id, 20 data: make([]byte, 8), 21 }) 22 if n, err := s.Read(make([]byte, 8)); n != 8 || err != nil { 23 t.Fatalf("s.Read() = %v, %v; want %v, nil", n, err, 8) 24 } 25 tc.wantFrame("available window increases, send a MAX_DATA", 26 packetType1RTT, debugFrameMaxData{ 27 max: 64 + 8, 28 }) 29 // Peer can write up to the new limit. 30 tc.writeFrames(packetType1RTT, debugFrameStream{ 31 id: s.id, 32 off: 8, 33 data: make([]byte, 64), 34 }) 35 if n, err := s.Read(make([]byte, 64+1)); n != 64 { 36 t.Fatalf("s.Read() = %v, %v; want %v, anything", n, err, 64) 37 } 38 tc.wantFrame("available window increases, send a MAX_DATA", 39 packetType1RTT, debugFrameMaxData{ 40 max: 64 + 8 + 64, 41 }) 42 tc.wantIdle("connection is idle") 43 } 44 45 func TestConnInflowReturnOnRacingReads(t *testing.T) { 46 // Perform two reads at the same time, 47 // one for half of MaxConnReadBufferSize 48 // and one for one byte. 49 // 50 // We should observe a single MAX_DATA update. 51 // Depending on the ordering of events, 52 // this may include the credit from just the larger read 53 // or the credit from both. 54 ctx := canceledContext() 55 tc := newTestConn(t, serverSide, func(c *Config) { 56 c.MaxConnReadBufferSize = 64 57 }) 58 tc.handshake() 59 tc.ignoreFrame(frameTypeAck) 60 tc.writeFrames(packetType1RTT, debugFrameStream{ 61 id: newStreamID(clientSide, uniStream, 0), 62 data: make([]byte, 16), 63 }) 64 tc.writeFrames(packetType1RTT, debugFrameStream{ 65 id: newStreamID(clientSide, uniStream, 1), 66 data: make([]byte, 1), 67 }) 68 s1, err := tc.conn.AcceptStream(ctx) 69 if err != nil { 70 t.Fatalf("conn.AcceptStream() = %v", err) 71 } 72 s2, err := tc.conn.AcceptStream(ctx) 73 if err != nil { 74 t.Fatalf("conn.AcceptStream() = %v", err) 75 } 76 read1 := runAsync(tc, func(ctx context.Context) (int, error) { 77 return s1.Read(make([]byte, 16)) 78 }) 79 read2 := runAsync(tc, func(ctx context.Context) (int, error) { 80 return s2.Read(make([]byte, 1)) 81 }) 82 // This MAX_DATA might extend the window by 16 or 17, depending on 83 // whether the second write occurs before the update happens. 84 tc.wantFrameType("MAX_DATA update is sent", 85 packetType1RTT, debugFrameMaxData{}) 86 tc.wantIdle("redundant MAX_DATA is not sent") 87 if _, err := read1.result(); err != nil { 88 t.Errorf("Read #1 = %v", err) 89 } 90 if _, err := read2.result(); err != nil { 91 t.Errorf("Read #2 = %v", err) 92 } 93 } 94 95 func TestConnInflowReturnOnClose(t *testing.T) { 96 tc, s := newTestConnAndRemoteStream(t, serverSide, uniStream, func(c *Config) { 97 c.MaxConnReadBufferSize = 64 98 }) 99 tc.ignoreFrame(frameTypeStopSending) 100 tc.writeFrames(packetType1RTT, debugFrameStream{ 101 id: s.id, 102 data: make([]byte, 64), 103 }) 104 s.CloseRead() 105 tc.wantFrame("closing stream updates connection-level flow control", 106 packetType1RTT, debugFrameMaxData{ 107 max: 128, 108 }) 109 } 110 111 func TestConnInflowReturnOnReset(t *testing.T) { 112 tc, s := newTestConnAndRemoteStream(t, serverSide, uniStream, func(c *Config) { 113 c.MaxConnReadBufferSize = 64 114 }) 115 tc.ignoreFrame(frameTypeStopSending) 116 tc.writeFrames(packetType1RTT, debugFrameStream{ 117 id: s.id, 118 data: make([]byte, 32), 119 }) 120 tc.writeFrames(packetType1RTT, debugFrameResetStream{ 121 id: s.id, 122 finalSize: 64, 123 }) 124 s.CloseRead() 125 tc.wantFrame("receiving stream reseet updates connection-level flow control", 126 packetType1RTT, debugFrameMaxData{ 127 max: 128, 128 }) 129 } 130 131 func TestConnInflowStreamViolation(t *testing.T) { 132 tc := newTestConn(t, serverSide, func(c *Config) { 133 c.MaxConnReadBufferSize = 100 134 }) 135 tc.handshake() 136 tc.ignoreFrame(frameTypeAck) 137 // Total MAX_DATA consumed: 50 138 tc.writeFrames(packetType1RTT, debugFrameStream{ 139 id: newStreamID(clientSide, bidiStream, 0), 140 data: make([]byte, 50), 141 }) 142 // Total MAX_DATA consumed: 80 143 tc.writeFrames(packetType1RTT, debugFrameStream{ 144 id: newStreamID(clientSide, uniStream, 0), 145 off: 20, 146 data: make([]byte, 10), 147 }) 148 // Total MAX_DATA consumed: 100 149 tc.writeFrames(packetType1RTT, debugFrameStream{ 150 id: newStreamID(clientSide, bidiStream, 0), 151 off: 70, 152 fin: true, 153 }) 154 // This stream has already consumed quota for these bytes. 155 // Total MAX_DATA consumed: 100 156 tc.writeFrames(packetType1RTT, debugFrameStream{ 157 id: newStreamID(clientSide, uniStream, 0), 158 data: make([]byte, 20), 159 }) 160 tc.wantIdle("peer has consumed all MAX_DATA quota") 161 162 // Total MAX_DATA consumed: 101 163 tc.writeFrames(packetType1RTT, debugFrameStream{ 164 id: newStreamID(clientSide, bidiStream, 2), 165 data: make([]byte, 1), 166 }) 167 tc.wantFrame("peer violates MAX_DATA limit", 168 packetType1RTT, debugFrameConnectionCloseTransport{ 169 code: errFlowControl, 170 }) 171 } 172 173 func TestConnInflowResetViolation(t *testing.T) { 174 tc := newTestConn(t, serverSide, func(c *Config) { 175 c.MaxConnReadBufferSize = 100 176 }) 177 tc.handshake() 178 tc.ignoreFrame(frameTypeAck) 179 tc.writeFrames(packetType1RTT, debugFrameStream{ 180 id: newStreamID(clientSide, bidiStream, 0), 181 data: make([]byte, 100), 182 }) 183 tc.wantIdle("peer has consumed all MAX_DATA quota") 184 185 tc.writeFrames(packetType1RTT, debugFrameResetStream{ 186 id: newStreamID(clientSide, uniStream, 0), 187 finalSize: 0, 188 }) 189 tc.wantIdle("stream reset does not consume MAX_DATA quota, no error") 190 191 tc.writeFrames(packetType1RTT, debugFrameResetStream{ 192 id: newStreamID(clientSide, uniStream, 1), 193 finalSize: 1, 194 }) 195 tc.wantFrame("RESET_STREAM final size violates MAX_DATA limit", 196 packetType1RTT, debugFrameConnectionCloseTransport{ 197 code: errFlowControl, 198 }) 199 } 200 201 func TestConnInflowMultipleStreams(t *testing.T) { 202 tc := newTestConn(t, serverSide, func(c *Config) { 203 c.MaxConnReadBufferSize = 128 204 }) 205 tc.handshake() 206 tc.ignoreFrame(frameTypeAck) 207 208 var streams []*Stream 209 for _, id := range []streamID{ 210 newStreamID(clientSide, uniStream, 0), 211 newStreamID(clientSide, uniStream, 1), 212 newStreamID(clientSide, bidiStream, 0), 213 newStreamID(clientSide, bidiStream, 1), 214 } { 215 tc.writeFrames(packetType1RTT, debugFrameStream{ 216 id: id, 217 data: make([]byte, 1), 218 }) 219 s := tc.acceptStream() 220 streams = append(streams, s) 221 if n, err := s.Read(make([]byte, 1)); err != nil || n != 1 { 222 t.Fatalf("s.Read() = %v, %v; want 1, nil", n, err) 223 } 224 } 225 tc.wantIdle("streams have read data, but not enough to update MAX_DATA") 226 227 for _, s := range streams { 228 tc.writeFrames(packetType1RTT, debugFrameStream{ 229 id: s.id, 230 off: 1, 231 data: make([]byte, 31), 232 }) 233 } 234 235 if n, err := streams[0].Read(make([]byte, 32)); n != 31 { 236 t.Fatalf("s.Read() = %v, %v; want 31, anything", n, err) 237 } 238 tc.wantFrame("read enough data to trigger a MAX_DATA update", 239 packetType1RTT, debugFrameMaxData{ 240 max: 128 + 32 + 1 + 1 + 1, 241 }) 242 243 tc.ignoreFrame(frameTypeStopSending) 244 streams[2].CloseRead() 245 tc.wantFrame("closed stream triggers another MAX_DATA update", 246 packetType1RTT, debugFrameMaxData{ 247 max: 128 + 32 + 1 + 32 + 1, 248 }) 249 } 250 251 func TestConnOutflowBlocked(t *testing.T) { 252 tc, s := newTestConnAndLocalStream(t, clientSide, uniStream, 253 permissiveTransportParameters, 254 func(p *transportParameters) { 255 p.initialMaxData = 10 256 }) 257 tc.ignoreFrame(frameTypeAck) 258 259 data := makeTestData(32) 260 n, err := s.Write(data) 261 if n != len(data) || err != nil { 262 t.Fatalf("s.Write() = %v, %v; want %v, nil", n, err, len(data)) 263 } 264 s.Flush() 265 266 tc.wantFrame("stream writes data up to MAX_DATA limit", 267 packetType1RTT, debugFrameStream{ 268 id: s.id, 269 data: data[:10], 270 }) 271 tc.wantIdle("stream is blocked by MAX_DATA limit") 272 273 tc.writeFrames(packetType1RTT, debugFrameMaxData{ 274 max: 20, 275 }) 276 tc.wantFrame("stream writes data up to new MAX_DATA limit", 277 packetType1RTT, debugFrameStream{ 278 id: s.id, 279 off: 10, 280 data: data[10:20], 281 }) 282 tc.wantIdle("stream is blocked by new MAX_DATA limit") 283 284 tc.writeFrames(packetType1RTT, debugFrameMaxData{ 285 max: 100, 286 }) 287 tc.wantFrame("stream writes remaining data", 288 packetType1RTT, debugFrameStream{ 289 id: s.id, 290 off: 20, 291 data: data[20:], 292 }) 293 } 294 295 func TestConnOutflowMaxDataDecreases(t *testing.T) { 296 tc, s := newTestConnAndLocalStream(t, clientSide, uniStream, 297 permissiveTransportParameters, 298 func(p *transportParameters) { 299 p.initialMaxData = 10 300 }) 301 tc.ignoreFrame(frameTypeAck) 302 303 // Decrease in MAX_DATA is ignored. 304 tc.writeFrames(packetType1RTT, debugFrameMaxData{ 305 max: 5, 306 }) 307 308 data := makeTestData(32) 309 n, err := s.Write(data) 310 if n != len(data) || err != nil { 311 t.Fatalf("s.Write() = %v, %v; want %v, nil", n, err, len(data)) 312 } 313 s.Flush() 314 315 tc.wantFrame("stream writes data up to MAX_DATA limit", 316 packetType1RTT, debugFrameStream{ 317 id: s.id, 318 data: data[:10], 319 }) 320 } 321 322 func TestConnOutflowMaxDataRoundRobin(t *testing.T) { 323 ctx := canceledContext() 324 tc := newTestConn(t, clientSide, permissiveTransportParameters, 325 func(p *transportParameters) { 326 p.initialMaxData = 0 327 }) 328 tc.handshake() 329 tc.ignoreFrame(frameTypeAck) 330 331 s1, err := tc.conn.newLocalStream(ctx, uniStream) 332 if err != nil { 333 t.Fatalf("conn.newLocalStream(%v) = %v", uniStream, err) 334 } 335 s2, err := tc.conn.newLocalStream(ctx, uniStream) 336 if err != nil { 337 t.Fatalf("conn.newLocalStream(%v) = %v", uniStream, err) 338 } 339 340 s1.Write(make([]byte, 10)) 341 s1.Flush() 342 s2.Write(make([]byte, 10)) 343 s2.Flush() 344 345 tc.writeFrames(packetType1RTT, debugFrameMaxData{ 346 max: 1, 347 }) 348 tc.wantFrame("stream 1 writes data up to MAX_DATA limit", 349 packetType1RTT, debugFrameStream{ 350 id: s1.id, 351 data: []byte{0}, 352 }) 353 354 tc.writeFrames(packetType1RTT, debugFrameMaxData{ 355 max: 2, 356 }) 357 tc.wantFrame("stream 2 writes data up to MAX_DATA limit", 358 packetType1RTT, debugFrameStream{ 359 id: s2.id, 360 data: []byte{0}, 361 }) 362 363 tc.writeFrames(packetType1RTT, debugFrameMaxData{ 364 max: 3, 365 }) 366 tc.wantFrame("stream 1 writes data up to MAX_DATA limit", 367 packetType1RTT, debugFrameStream{ 368 id: s1.id, 369 off: 1, 370 data: []byte{0}, 371 }) 372 } 373 374 func TestConnOutflowMetaAndData(t *testing.T) { 375 tc, s := newTestConnAndLocalStream(t, clientSide, bidiStream, 376 permissiveTransportParameters, 377 func(p *transportParameters) { 378 p.initialMaxData = 0 379 }) 380 tc.ignoreFrame(frameTypeAck) 381 382 data := makeTestData(32) 383 s.Write(data) 384 s.Flush() 385 386 s.CloseRead() 387 tc.wantFrame("CloseRead sends a STOP_SENDING, not flow controlled", 388 packetType1RTT, debugFrameStopSending{ 389 id: s.id, 390 }) 391 392 tc.writeFrames(packetType1RTT, debugFrameMaxData{ 393 max: 100, 394 }) 395 tc.wantFrame("unblocked MAX_DATA", 396 packetType1RTT, debugFrameStream{ 397 id: s.id, 398 data: data, 399 }) 400 } 401 402 func TestConnOutflowResentData(t *testing.T) { 403 tc, s := newTestConnAndLocalStream(t, clientSide, bidiStream, 404 permissiveTransportParameters, 405 func(p *transportParameters) { 406 p.initialMaxData = 10 407 }) 408 tc.ignoreFrame(frameTypeAck) 409 410 data := makeTestData(15) 411 s.Write(data[:8]) 412 s.Flush() 413 tc.wantFrame("data is under MAX_DATA limit, all sent", 414 packetType1RTT, debugFrameStream{ 415 id: s.id, 416 data: data[:8], 417 }) 418 419 // Lose the last STREAM packet. 420 const pto = false 421 tc.triggerLossOrPTO(packetType1RTT, false) 422 tc.wantFrame("lost STREAM data is retransmitted", 423 packetType1RTT, debugFrameStream{ 424 id: s.id, 425 data: data[:8], 426 }) 427 428 s.Write(data[8:]) 429 s.Flush() 430 tc.wantFrame("new data is sent up to the MAX_DATA limit", 431 packetType1RTT, debugFrameStream{ 432 id: s.id, 433 off: 8, 434 data: data[8:10], 435 }) 436 }