@@ -4,7 +4,9 @@ use serde::{Deserialize, Serialize};
44
55use super :: super :: * ;
66
7- #[ derive( Serialize , Deserialize , Debug , Clone ) ]
7+ pub const INITIAL_RECV_BUFFER_CAPACITY : usize = 0x40000 ; // 256kb
8+
9+ #[ derive( Serialize , Deserialize , Debug , Clone , Default ) ]
810pub struct P2pNetworkYamuxState {
911 pub message_size_limit : Limit < usize > ,
1012 pub pending_outgoing_limit : Limit < usize > ,
@@ -15,20 +17,6 @@ pub struct P2pNetworkYamuxState {
1517 pub init : bool ,
1618}
1719
18- impl Default for P2pNetworkYamuxState {
19- fn default ( ) -> Self {
20- Self {
21- message_size_limit : Default :: default ( ) ,
22- pending_outgoing_limit : Default :: default ( ) ,
23- buffer : Vec :: with_capacity ( 0x40000 ) , // 256kb
24- incoming : VecDeque :: with_capacity ( 10 ) , // TODO: measure and see what is a good default
25- streams : Default :: default ( ) ,
26- terminated : Default :: default ( ) ,
27- init : Default :: default ( ) ,
28- }
29- }
30- }
31-
3220impl P2pNetworkYamuxState {
3321 /// Calculates and returns the next available stream ID for outgoing
3422 /// communication.
@@ -58,6 +46,147 @@ impl P2pNetworkYamuxState {
5846
5947 windows + headers * SIZE_OF_HEADER
6048 }
49+
50+ pub fn set_err ( & mut self , err : YamuxFrameParseError ) {
51+ self . terminated = Some ( Err ( err) ) ;
52+ }
53+
54+ pub fn set_res ( & mut self , res : Result < ( ) , YamuxSessionError > ) {
55+ self . terminated = Some ( Ok ( res) ) ;
56+ }
57+
58+ /// Attempts to parse a Yamux frame from the buffer starting at the given offset.
59+ /// Returns the number of bytes consumed if a frame was successfully parsed.
60+ pub fn try_parse_frame ( & mut self , offset : usize ) -> Option < usize > {
61+ let buf = & self . buffer [ offset..] ;
62+ if buf. len ( ) < 12 {
63+ return None ;
64+ }
65+
66+ let _version = match buf[ 0 ] {
67+ 0 => 0 ,
68+ unknown => {
69+ self . set_err ( YamuxFrameParseError :: Version ( unknown) ) ;
70+ return None ;
71+ }
72+ } ;
73+
74+ let flags = u16:: from_be_bytes ( buf[ 2 ..4 ] . try_into ( ) . expect ( "cannot fail" ) ) ;
75+ let Some ( flags) = YamuxFlags :: from_bits ( flags) else {
76+ self . set_err ( YamuxFrameParseError :: Flags ( flags) ) ;
77+ return None ;
78+ } ;
79+ let stream_id = u32:: from_be_bytes ( buf[ 4 ..8 ] . try_into ( ) . expect ( "cannot fail" ) ) ;
80+ let b = buf[ 8 ..12 ] . try_into ( ) . expect ( "cannot fail" ) ;
81+
82+ match buf[ 1 ] {
83+ // Data frame - contains actual payload data for the stream
84+ 0 => {
85+ let len = u32:: from_be_bytes ( b) as usize ;
86+ if len > self . message_size_limit {
87+ self . set_res ( Err ( YamuxSessionError :: Internal ) ) ;
88+ return None ;
89+ }
90+ if buf. len ( ) >= 12 + len {
91+ let frame = YamuxFrame {
92+ flags,
93+ stream_id,
94+ inner : YamuxFrameInner :: Data ( buf[ 12 ..( 12 + len) ] . to_vec ( ) . into ( ) ) ,
95+ } ;
96+ self . incoming . push_back ( frame) ;
97+ Some ( 12 + len)
98+ } else {
99+ None
100+ }
101+ }
102+ // Window Update frame - used for flow control, updates available window size
103+ 1 => {
104+ let difference = u32:: from_be_bytes ( b) ;
105+ let frame = YamuxFrame {
106+ flags,
107+ stream_id,
108+ inner : YamuxFrameInner :: WindowUpdate { difference } ,
109+ } ;
110+ self . incoming . push_back ( frame) ;
111+ Some ( 12 )
112+ }
113+ // Ping frame - used for keepalive and round-trip time measurements
114+ 2 => {
115+ let opaque = u32:: from_be_bytes ( b) ;
116+ let frame = YamuxFrame {
117+ flags,
118+ stream_id,
119+ inner : YamuxFrameInner :: Ping { opaque } ,
120+ } ;
121+ self . incoming . push_back ( frame) ;
122+ Some ( 12 )
123+ }
124+ // GoAway frame - signals session termination with optional error code
125+ 3 => {
126+ let code = u32:: from_be_bytes ( b) ;
127+ let result = match code {
128+ 0 => Ok ( ( ) ) , // Normal termination
129+ 1 => Err ( YamuxSessionError :: Protocol ) , // Protocol error
130+ 2 => Err ( YamuxSessionError :: Internal ) , // Internal error
131+ unknown => {
132+ self . set_err ( YamuxFrameParseError :: ErrorCode ( unknown) ) ;
133+ return None ;
134+ }
135+ } ;
136+ let frame = YamuxFrame {
137+ flags,
138+ stream_id,
139+ inner : YamuxFrameInner :: GoAway ( result) ,
140+ } ;
141+ self . incoming . push_back ( frame) ;
142+ Some ( 12 )
143+ }
144+ // Unknown frame type
145+ unknown => {
146+ self . set_err ( YamuxFrameParseError :: Type ( unknown) ) ;
147+ None
148+ }
149+ }
150+ }
151+
152+ /// Attempts to parse all available complete frames from the buffer,
153+ /// then shifts and compacts the buffer as needed.
154+ pub fn parse_frames ( & mut self ) {
155+ let mut offset = 0 ;
156+ while let Some ( consumed) = self . try_parse_frame ( offset) {
157+ offset += consumed;
158+ }
159+ self . shift_and_compact_buffer ( offset) ;
160+ }
161+
162+ fn shift_and_compact_buffer ( & mut self , offset : usize ) {
163+ let new_len = self . buffer . len ( ) - offset;
164+ if self . buffer . capacity ( ) > INITIAL_RECV_BUFFER_CAPACITY * 2
165+ && new_len < INITIAL_RECV_BUFFER_CAPACITY / 2
166+ {
167+ let old_buffer = & self . buffer ;
168+ let mut new_buffer = Vec :: with_capacity ( INITIAL_RECV_BUFFER_CAPACITY ) ;
169+ new_buffer. extend_from_slice ( & old_buffer[ offset..] ) ;
170+ self . buffer = new_buffer;
171+ } else {
172+ self . buffer . copy_within ( offset.., 0 ) ;
173+ self . buffer . truncate ( new_len) ;
174+ }
175+ }
176+
177+ /// Extends the internal buffer with new data, ensuring it has appropriate capacity.
178+ /// On first use, reserves the initial capacity.
179+ pub fn extend_buffer ( & mut self , data : & [ u8 ] ) {
180+ if self . buffer . capacity ( ) == 0 {
181+ self . buffer . reserve ( INITIAL_RECV_BUFFER_CAPACITY ) ;
182+ }
183+ self . buffer . extend_from_slice ( data) ;
184+ }
185+
186+ /// Returns the number of incoming frames that have been parsed and are ready for processing.
187+ pub fn incoming_frame_count ( & self ) -> usize {
188+ self . incoming . len ( )
189+ }
61190}
62191
63192#[ derive( Serialize , Deserialize , Debug , Clone ) ]
0 commit comments