@@ -68,6 +68,11 @@ pub struct StreamManager {
6868 acceptor : QuicStreamAcceptor ,
6969 cmd_send : mpsc:: UnboundedSender < Cmd > ,
7070 cmd_recv : mpsc:: UnboundedReceiver < Cmd > ,
71+ maps : StreamMaps ,
72+ }
73+
74+ #[ derive( Default ) ]
75+ struct StreamMaps {
7176 pending : HashMap < UniqueId , StreamSend > ,
7277 accepted : HashMap < UniqueId , ( QuicRecvStream , usize ) > ,
7378}
@@ -150,8 +155,7 @@ impl StreamManager {
150155 acceptor,
151156 cmd_send,
152157 cmd_recv,
153- pending : Default :: default ( ) ,
154- accepted : Default :: default ( ) ,
158+ maps : Default :: default ( ) ,
155159 }
156160 }
157161
@@ -171,47 +175,32 @@ impl StreamManager {
171175 Self :: accepted( stream, self . cmd_send. clone( ) ) ;
172176 }
173177 Ok ( None ) => {
174- debug!( "remote closed" ) ;
175- return ;
178+ debug!( "remote closed, draining pending commands " ) ;
179+ break ;
176180 }
177181 Err ( err) => {
178- error!( %err, "unable to accept stream" ) ;
179- return ;
182+ error!( %err, "unable to accept stream, draining pending commands " ) ;
183+ break ;
180184 }
181185 }
182186 }
183187 Some ( cmd) = self . cmd_recv. recv( ) => { // recv() is cancel safe
184188 debug!( ?cmd, "received cmd" ) ;
185- match cmd {
186- Cmd :: NewStream { uid, stream_return} => {
187- if let Some ( accepted) = self . accepted. remove( & uid) {
188- if stream_return. send( accepted) . is_err( ) {
189- debug!( "accepted remote stream but local receiver is closed" ) ;
190- }
191- debug!( "sending new stream to receiver" ) ;
192- continue ;
193- }
194- match self . pending. entry( uid) {
195- Entry :: Occupied ( occupied_entry) => {
196- panic!( "Duplicate unique id: {:?}" , occupied_entry. key( ) )
197- } ,
198- Entry :: Vacant ( vacant_entry) => { vacant_entry. insert( stream_return) ; } ,
199- }
200- }
201- Cmd :: AcceptedStream { uid, stream, bytes_read} => {
202- if let Some ( stream_ret) = self . pending. remove( & uid) {
203- if stream_ret. send( ( stream, bytes_read) ) . is_err( ) {
204- debug!( "accepted remote stream but local receiver is closed" ) ;
205- }
206- } else {
207- debug!( "accepted stream but no pending" ) ;
208- self . accepted. insert( uid, ( stream, bytes_read) ) ;
209- }
210- }
211- }
189+ self . maps. handle_cmd( cmd) ;
212190 }
213191 }
214192 }
193+ // The QUIC acceptor is done (remote closed or error), but there may be
194+ // in-flight `Self::accepted` tasks that already received a stream and
195+ // are reading the UniqueId. Drain remaining commands so those streams
196+ // are matched with pending requests.
197+ while let Ok ( cmd) = self . cmd_recv . try_recv ( ) {
198+ debug ! ( ?cmd, "received cmd (draining)" ) ;
199+ self . maps . handle_cmd ( cmd) ;
200+ if self . maps . pending . is_empty ( ) {
201+ break ;
202+ }
203+ }
215204 }
216205
217206 // not taking &self to work around borrow issue
@@ -224,17 +213,54 @@ impl StreamManager {
224213 return ;
225214 }
226215 } ;
227- cmd_send
228- . send ( Cmd :: AcceptedStream {
229- uid,
230- stream,
231- bytes_read,
232- } )
233- . expect ( "cmd_rcv is owned by StreamManager" )
216+ // StreamManager may have already exited if the connection closed
217+ let _ = cmd_send. send ( Cmd :: AcceptedStream {
218+ uid,
219+ stream,
220+ bytes_read,
221+ } ) ;
234222 } ) ;
235223 }
236224}
237225
226+ impl StreamMaps {
227+ fn handle_cmd ( & mut self , cmd : Cmd ) {
228+ match cmd {
229+ Cmd :: NewStream { uid, stream_return } => {
230+ if let Some ( accepted) = self . accepted . remove ( & uid) {
231+ if stream_return. send ( accepted) . is_err ( ) {
232+ debug ! ( "accepted remote stream but local receiver is closed" ) ;
233+ }
234+ debug ! ( "sending new stream to receiver" ) ;
235+ return ;
236+ }
237+ match self . pending . entry ( uid) {
238+ Entry :: Occupied ( occupied_entry) => {
239+ panic ! ( "Duplicate unique id: {:?}" , occupied_entry. key( ) )
240+ }
241+ Entry :: Vacant ( vacant_entry) => {
242+ vacant_entry. insert ( stream_return) ;
243+ }
244+ }
245+ }
246+ Cmd :: AcceptedStream {
247+ uid,
248+ stream,
249+ bytes_read,
250+ } => {
251+ if let Some ( stream_ret) = self . pending . remove ( & uid) {
252+ if stream_ret. send ( ( stream, bytes_read) ) . is_err ( ) {
253+ debug ! ( "accepted remote stream but local receiver is closed" ) ;
254+ }
255+ } else {
256+ debug ! ( "accepted stream but no pending" ) ;
257+ self . accepted . insert ( uid, ( stream, bytes_read) ) ;
258+ }
259+ }
260+ }
261+ }
262+ }
263+
238264/// Possible connection errors.
239265#[ derive( thiserror:: Error , Debug ) ]
240266pub enum ConnectionError {
0 commit comments