@@ -2343,28 +2343,104 @@ impl Connection {
2343
2343
self . stats . borrow_mut ( ) . frame_tx . connection_close += 1 ;
2344
2344
}
2345
2345
2346
+ // TODO: There is a limit to the number of segments supported. E.g. you
2347
+ // can't pass 200 segments to the Linux Kernel.
2348
+ fn output_path < ' a > (
2349
+ & mut self ,
2350
+ path : & PathRef ,
2351
+ now : Instant ,
2352
+ closing_frame : & Option < ClosingFrame > ,
2353
+ out : & ' a mut Vec < u8 > ,
2354
+ ) -> Res < SendOption < ' a > > {
2355
+ assert_eq ! ( out. len( ) , 0 ) ;
2356
+
2357
+ qinfo ! ( "\n ===== output_path" ) ;
2358
+ let mut initial_capacity = out. capacity ( ) ;
2359
+ // TODO
2360
+ if initial_capacity == 0 {
2361
+ initial_capacity = usize:: MAX ;
2362
+ }
2363
+ qinfo ! ( "initial_capacity: {initial_capacity}" ) ;
2364
+ let mut segment_size = None ;
2365
+
2366
+ loop {
2367
+ let limit = segment_size. map ( |s| min ( s, initial_capacity - out. len ( ) ) ) ;
2368
+ if limit < segment_size {
2369
+ qinfo ! ( "no more space for another segment" ) ;
2370
+ break ;
2371
+ }
2372
+ qinfo ! ( "limit: {limit:?}, out len: {}" , out. len( ) ) ;
2373
+ // Determine how we are sending packets (PTO, etc..).
2374
+ let profile = self
2375
+ . loss_recovery
2376
+ . send_profile_2 ( limit, & path. borrow ( ) , now) ;
2377
+ qinfo ! ( "output_path send_profile {:?}" , profile) ;
2378
+ qdebug ! ( [ self ] , "output_path send_profile {:?}" , profile) ;
2379
+
2380
+ let start = out. len ( ) ;
2381
+ if let Some ( pace) = self . output_path_segment ( profile, path, now, closing_frame, out) ? {
2382
+ qinfo ! ( "SendOption::No" ) ;
2383
+ if segment_size. is_none ( ) {
2384
+ return Ok ( SendOption :: No ( pace) ) ;
2385
+ }
2386
+ break ;
2387
+ }
2388
+ qinfo ! ( "SendOption::Yes" ) ;
2389
+
2390
+ if segment_size. is_none ( ) {
2391
+ segment_size = Some ( out. len ( ) ) ;
2392
+ if out. len ( ) < path. borrow ( ) . plpmtu ( ) / 2 {
2393
+ qinfo ! ( "Segment is smaller than half of the mtu: {}" , out. len( ) ) ;
2394
+ break ;
2395
+ }
2396
+ }
2397
+
2398
+ if out. len ( ) % segment_size. expect ( "TODO" ) != 0 {
2399
+ qinfo ! ( "Segment is smaller than previous" ) ;
2400
+ break ;
2401
+ }
2402
+
2403
+ if path. borrow ( ) . pmtud ( ) . needs_probe ( ) {
2404
+ qinfo ! ( "about to probe, thus larger than previous segment" ) ;
2405
+ break ;
2406
+ }
2407
+
2408
+ assert ! ( out. len( ) - start <= segment_size. unwrap( ) ) ;
2409
+ }
2410
+
2411
+ let mut dgram = path
2412
+ . borrow_mut ( )
2413
+ . datagram ( out, & mut self . stats . borrow_mut ( ) ) ;
2414
+ dgram. set_segment_size ( segment_size. expect ( "TODO" ) ) ;
2415
+
2416
+ qinfo ! (
2417
+ "Sending datagram: {} size {} segments" ,
2418
+ dgram. len( ) ,
2419
+ dgram. num_segments( )
2420
+ ) ;
2421
+
2422
+ return Ok ( SendOption :: Yes ( dgram) ) ;
2423
+ }
2424
+
2346
2425
/// Build a datagram, possibly from multiple packets (for different PN
2347
2426
/// spaces) and each containing 1+ frames.
2348
2427
#[ allow( clippy:: too_many_lines) ] // Yeah, that's just the way it is.
2349
- fn output_path < ' a > (
2428
+ fn output_path_segment < ' a > (
2350
2429
& mut self ,
2430
+ profile : SendProfile ,
2351
2431
path : & PathRef ,
2352
2432
now : Instant ,
2353
2433
closing_frame : & Option < ClosingFrame > ,
2354
2434
out : & ' a mut Vec < u8 > ,
2355
- ) -> Res < SendOption < ' a > > {
2435
+ // TODO: Option is misleading here.
2436
+ ) -> Res < Option < bool > > {
2356
2437
let mut initial_sent = None ;
2357
2438
let mut needs_padding = false ;
2358
2439
let grease_quic_bit = self . can_grease_quic_bit ( ) ;
2359
2440
let version = self . version ( ) ;
2360
2441
2361
- // Determine how we are sending packets (PTO, etc..).
2362
- let profile = self . loss_recovery . send_profile ( & path. borrow ( ) , now) ;
2363
- qdebug ! ( [ self ] , "output_path send_profile {:?}" , profile) ;
2364
-
2365
2442
// Frames for different epochs must go in different packets, but then these
2366
2443
// packets can go in a single datagram
2367
- assert_eq ! ( out. len( ) , 0 ) ;
2368
2444
let mut encoder = Encoder :: new ( out) ;
2369
2445
for space in PacketNumberSpace :: iter ( ) {
2370
2446
// Ensure we have tx crypto state for this epoch, or skip it.
@@ -2492,30 +2568,26 @@ impl Connection {
2492
2568
2493
2569
if encoder. is_empty ( ) {
2494
2570
qdebug ! ( "TX blocked, profile={:?}" , profile) ;
2495
- Ok ( SendOption :: No ( profile. paced ( ) ) )
2571
+ Ok ( Some ( profile. paced ( ) ) )
2496
2572
} else {
2497
2573
// Perform additional padding for Initial packets as necessary.
2498
- let packets: & mut Vec < u8 > = encoder. into ( ) ;
2499
2574
if let Some ( mut initial) = initial_sent. take ( ) {
2500
2575
if needs_padding {
2501
2576
qdebug ! (
2502
2577
[ self ] ,
2503
2578
"pad Initial from {} to PLPMTU {}" ,
2504
- packets . len( ) ,
2579
+ encoder . len( ) ,
2505
2580
profile. limit( )
2506
2581
) ;
2507
- initial. track_padding ( profile. limit ( ) - packets . len ( ) ) ;
2582
+ initial. track_padding ( profile. limit ( ) - encoder . len ( ) ) ;
2508
2583
// These zeros aren't padding frames, they are an invalid all-zero coalesced
2509
2584
// packet, which is why we don't increase `frame_tx.padding` count here.
2510
- packets . resize ( profile. limit ( ) , 0 ) ;
2585
+ encoder . pad_to ( profile. limit ( ) , 0 ) ;
2511
2586
}
2512
2587
self . loss_recovery . on_packet_sent ( path, initial) ;
2513
2588
}
2514
- path. borrow_mut ( ) . add_sent ( packets. len ( ) ) ;
2515
- Ok ( SendOption :: Yes (
2516
- path. borrow_mut ( )
2517
- . datagram ( packets, & mut self . stats . borrow_mut ( ) ) ,
2518
- ) )
2589
+ path. borrow_mut ( ) . add_sent ( encoder. len ( ) ) ;
2590
+ Ok ( None )
2519
2591
}
2520
2592
}
2521
2593
0 commit comments