@@ -97,6 +97,7 @@ impl<C> Debug for CommonSession<C> {
9797 }
9898}
9999
100+ #[ must_use]
100101#[ derive( Debug , Clone , Copy ) ]
101102pub ( crate ) enum ChannelFlushResult {
102103 Incomplete {
@@ -115,11 +116,12 @@ impl ChannelFlushResult {
115116 ChannelFlushResult :: Complete { wrote, .. } => * wrote,
116117 }
117118 }
118- pub ( crate ) fn complete ( wrote : usize , channel : & ChannelParams ) -> Self {
119+ pub ( crate ) fn complete ( wrote : usize , channel : & mut ChannelParams ) -> Self {
120+ let ( pending_eof, pending_close) = channel. take_pending_controls ( ) ;
119121 ChannelFlushResult :: Complete {
120122 wrote,
121- pending_eof : channel . pending_eof ,
122- pending_close : channel . pending_close ,
123+ pending_eof,
124+ pending_close,
123125 }
124126 }
125127}
@@ -352,23 +354,19 @@ impl Encrypted {
352354 }
353355
354356 pub fn flush_pending ( & mut self , channel : ChannelId ) -> Result < usize , crate :: Error > {
355- let mut pending_size = 0 ;
356- let mut maybe_flush_result = Option :: < ChannelFlushResult > :: None ;
357-
358- if let Some ( channel) = self . channels . get_mut ( & channel) {
359- let flush_result = Self :: flush_channel ( & mut self . write , channel) ?;
360- pending_size += flush_result. wrote ( ) ;
361- maybe_flush_result = Some ( flush_result) ;
362- }
363- if let Some ( flush_result) = maybe_flush_result {
364- self . handle_flushed_channel ( channel, flush_result) ?
365- }
366- Ok ( pending_size)
357+ let flush_result = match self . channels . get_mut ( & channel) {
358+ Some ( ch) => Self :: flush_channel ( & mut self . write , ch) ?,
359+ None => return Ok ( 0 ) ,
360+ } ;
361+ let wrote = flush_result. wrote ( ) ;
362+ self . handle_flushed_channel ( channel, flush_result) ?;
363+ Ok ( wrote)
367364 }
368365
369366 pub fn flush_all_pending ( & mut self ) -> Result < ( ) , crate :: Error > {
370- for channel in self . channels . values_mut ( ) {
371- Self :: flush_channel ( & mut self . write , channel) ?;
367+ let channel_ids: Vec < ChannelId > = self . channels . keys ( ) . copied ( ) . collect ( ) ;
368+ for channel_id in channel_ids {
369+ self . flush_pending ( channel_id) ?;
372370 }
373371 Ok ( ( ) )
374372 }
@@ -616,3 +614,226 @@ pub(crate) enum GlobalRequestResponse {
616614 StreamLocalForward ( oneshot:: Sender < bool > ) ,
617615 CancelStreamLocalForward ( oneshot:: Sender < bool > ) ,
618616}
617+
618+ #[ cfg( test) ]
619+ mod tests {
620+ use std:: collections:: { HashMap , VecDeque } ;
621+ use std:: num:: Wrapping ;
622+
623+ use byteorder:: { BigEndian , ByteOrder } ;
624+ use bytes:: Bytes ;
625+
626+ use super :: { Encrypted , EncryptedState , Exchange } ;
627+ use crate :: compression:: { Compression , Decompress } ;
628+ use crate :: kex:: { KEXES , NONE } ;
629+ use crate :: { ChannelId , ChannelParams , CryptoVec , mac, msg} ;
630+
631+ fn test_encrypted ( ) -> Encrypted {
632+ Encrypted {
633+ state : EncryptedState :: Authenticated ,
634+ exchange : Some ( Exchange :: default ( ) ) ,
635+ kex : KEXES . get ( & NONE ) . unwrap ( ) . make ( ) ,
636+ key : 0 ,
637+ client_mac : mac:: NONE ,
638+ server_mac : mac:: NONE ,
639+ session_id : CryptoVec :: new ( ) ,
640+ channels : HashMap :: new ( ) ,
641+ last_channel_id : Wrapping ( 0 ) ,
642+ write : Vec :: new ( ) ,
643+ write_cursor : 0 ,
644+ last_rekey : russh_util:: time:: Instant :: now ( ) ,
645+ server_compression : Compression :: None ,
646+ client_compression : Compression :: None ,
647+ decompress : Decompress :: None ,
648+ rekey_wanted : false ,
649+ received_extensions : Vec :: new ( ) ,
650+ extension_info_awaiters : HashMap :: new ( ) ,
651+ }
652+ }
653+
654+ fn test_channel (
655+ sender_channel : ChannelId ,
656+ recipient_channel : u32 ,
657+ pending_eof : bool ,
658+ pending_close : bool ,
659+ ) -> ChannelParams {
660+ ChannelParams {
661+ recipient_channel,
662+ sender_channel,
663+ recipient_window_size : 1024 ,
664+ sender_window_size : 1024 ,
665+ recipient_maximum_packet_size : 1024 ,
666+ sender_maximum_packet_size : 1024 ,
667+ confirmed : true ,
668+ wants_reply : false ,
669+ pending_data : VecDeque :: from ( [ ( Bytes :: from_static ( b"hello" ) , None , 0 ) ] ) ,
670+ pending_eof,
671+ pending_close,
672+ }
673+ }
674+
675+ fn packet_types ( buf : & [ u8 ] ) -> Vec < u8 > {
676+ let mut packet_types = Vec :: new ( ) ;
677+ let mut cursor = 0 ;
678+
679+ while cursor < buf. len ( ) {
680+ let packet_len = BigEndian :: read_u32 ( & buf[ cursor..cursor + 4 ] ) as usize ;
681+ packet_types. push ( buf[ cursor + 4 ] ) ;
682+ cursor += 4 + packet_len;
683+ }
684+
685+ packet_types
686+ }
687+
688+ fn test_channel_windowed (
689+ sender_channel : ChannelId ,
690+ recipient_channel : u32 ,
691+ window_size : u32 ,
692+ pending_eof : bool ,
693+ pending_close : bool ,
694+ ) -> ChannelParams {
695+ ChannelParams {
696+ recipient_channel,
697+ sender_channel,
698+ recipient_window_size : window_size,
699+ sender_window_size : 1024 ,
700+ recipient_maximum_packet_size : 1024 ,
701+ sender_maximum_packet_size : 1024 ,
702+ confirmed : true ,
703+ wants_reply : false ,
704+ pending_data : VecDeque :: from ( [ ( Bytes :: from_static ( b"hello" ) , None , 0 ) ] ) ,
705+ pending_eof,
706+ pending_close,
707+ }
708+ }
709+
710+ // flush_pending (single-channel path)
711+
712+ #[ test]
713+ fn flush_pending_replays_deferred_eof_once ( ) {
714+ let channel_id = ChannelId ( 10 ) ;
715+ let mut encrypted = test_encrypted ( ) ;
716+ encrypted
717+ . channels
718+ . insert ( channel_id, test_channel ( channel_id, 42 , true , false ) ) ;
719+
720+ encrypted. flush_pending ( channel_id) . unwrap ( ) ;
721+ assert_eq ! (
722+ packet_types( & encrypted. write) ,
723+ vec![ msg:: CHANNEL_DATA , msg:: CHANNEL_EOF ]
724+ ) ;
725+ assert ! ( !encrypted. channels[ & channel_id] . pending_eof) ;
726+
727+ // Second flush must not re-emit EOF.
728+ encrypted. flush_pending ( channel_id) . unwrap ( ) ;
729+ assert_eq ! (
730+ packet_types( & encrypted. write) ,
731+ vec![ msg:: CHANNEL_DATA , msg:: CHANNEL_EOF ]
732+ ) ;
733+ }
734+
735+ #[ test]
736+ fn flush_pending_replays_deferred_close_and_removes_channel ( ) {
737+ let channel_id = ChannelId ( 11 ) ;
738+ let mut encrypted = test_encrypted ( ) ;
739+ encrypted
740+ . channels
741+ . insert ( channel_id, test_channel ( channel_id, 43 , true , true ) ) ;
742+
743+ encrypted. flush_pending ( channel_id) . unwrap ( ) ;
744+ assert_eq ! (
745+ packet_types( & encrypted. write) ,
746+ vec![ msg:: CHANNEL_DATA , msg:: CHANNEL_EOF , msg:: CHANNEL_CLOSE ]
747+ ) ;
748+ assert ! ( !encrypted. channels. contains_key( & channel_id) ) ;
749+ }
750+
751+ #[ test]
752+ fn flush_pending_no_controls_when_incomplete ( ) {
753+ // Window smaller than data: flush is incomplete, EOF/CLOSE must not be sent.
754+ let channel_id = ChannelId ( 12 ) ;
755+ let mut encrypted = test_encrypted ( ) ;
756+ encrypted. channels . insert (
757+ channel_id,
758+ test_channel_windowed ( channel_id, 44 , 3 , true , true ) ,
759+ ) ;
760+
761+ encrypted. flush_pending ( channel_id) . unwrap ( ) ;
762+ // Only partial data fits; no EOF or CLOSE yet.
763+ assert_eq ! ( packet_types( & encrypted. write) , vec![ msg:: CHANNEL_DATA ] ) ;
764+ assert ! ( encrypted. channels. contains_key( & channel_id) ) ;
765+ assert ! ( encrypted. channels[ & channel_id] . pending_eof) ;
766+ assert ! ( encrypted. channels[ & channel_id] . pending_close) ;
767+ }
768+
769+ // flush_all_pending (multi-channel path)
770+
771+ #[ test]
772+ fn flush_all_pending_replays_deferred_eof_once ( ) {
773+ let channel_id = ChannelId ( 1 ) ;
774+ let mut encrypted = test_encrypted ( ) ;
775+ encrypted
776+ . channels
777+ . insert ( channel_id, test_channel ( channel_id, 42 , true , false ) ) ;
778+
779+ encrypted. flush_all_pending ( ) . unwrap ( ) ;
780+ assert_eq ! (
781+ packet_types( & encrypted. write) ,
782+ vec![ msg:: CHANNEL_DATA , msg:: CHANNEL_EOF ]
783+ ) ;
784+ assert ! ( !encrypted. channels[ & channel_id] . pending_eof) ;
785+
786+ encrypted. flush_all_pending ( ) . unwrap ( ) ;
787+ assert_eq ! (
788+ packet_types( & encrypted. write) ,
789+ vec![ msg:: CHANNEL_DATA , msg:: CHANNEL_EOF ]
790+ ) ;
791+ }
792+
793+ #[ test]
794+ fn flush_all_pending_replays_deferred_close_and_removes_channel ( ) {
795+ let channel_id = ChannelId ( 2 ) ;
796+ let mut encrypted = test_encrypted ( ) ;
797+ encrypted
798+ . channels
799+ . insert ( channel_id, test_channel ( channel_id, 43 , true , true ) ) ;
800+
801+ encrypted. flush_all_pending ( ) . unwrap ( ) ;
802+ assert_eq ! (
803+ packet_types( & encrypted. write) ,
804+ vec![ msg:: CHANNEL_DATA , msg:: CHANNEL_EOF , msg:: CHANNEL_CLOSE ]
805+ ) ;
806+ assert ! ( !encrypted. channels. contains_key( & channel_id) ) ;
807+ }
808+
809+ #[ test]
810+ fn flush_all_pending_handles_multiple_channels_independently ( ) {
811+ let eof_only = ChannelId ( 3 ) ;
812+ let close_too = ChannelId ( 4 ) ;
813+ let mut encrypted = test_encrypted ( ) ;
814+ encrypted
815+ . channels
816+ . insert ( eof_only, test_channel ( eof_only, 50 , true , false ) ) ;
817+ encrypted
818+ . channels
819+ . insert ( close_too, test_channel ( close_too, 51 , true , true ) ) ;
820+
821+ encrypted. flush_all_pending ( ) . unwrap ( ) ;
822+
823+ // eof_only: data + EOF, channel still present
824+ assert ! ( encrypted. channels. contains_key( & eof_only) ) ;
825+ assert ! ( !encrypted. channels[ & eof_only] . pending_eof) ;
826+
827+ // close_too: data + EOF + CLOSE, channel removed
828+ assert ! ( !encrypted. channels. contains_key( & close_too) ) ;
829+
830+ // Combined wire output contains both sets of packets (order may vary by map iteration).
831+ let types = packet_types ( & encrypted. write ) ;
832+ assert_eq ! ( types. iter( ) . filter( |&&t| t == msg:: CHANNEL_DATA ) . count( ) , 2 ) ;
833+ assert_eq ! ( types. iter( ) . filter( |&&t| t == msg:: CHANNEL_EOF ) . count( ) , 2 ) ;
834+ assert_eq ! (
835+ types. iter( ) . filter( |&&t| t == msg:: CHANNEL_CLOSE ) . count( ) ,
836+ 1
837+ ) ;
838+ }
839+ }
0 commit comments