11use std:: task:: Poll ;
22
33use iroh_base:: TransportAddr ;
4+ use n0_error:: stack_error;
45use n0_future:: time:: Duration ;
56use n0_watcher:: { Watchable , Watcher } ;
6- use quinn:: WeakPathHandle ;
77use quinn_proto:: PathId ;
88use smallvec:: SmallVec ;
99
1010use crate :: { endpoint:: PathStats , socket:: transports} ;
1111
12- /// List of [`PathInfo`] for a connection.
12+ /// List of [`PathInfo`] for the network paths of a [`Connection`].
13+ ///
14+ /// This struct implements [`IntoIterator`].
15+ ///
16+ /// [`Connection`]: crate::endpoint::Connection
1317#[ derive( Debug , Clone , Eq , PartialEq , Default ) ]
1418pub struct PathInfoList ( SmallVec < [ PathInfo ; 4 ] > ) ;
1519
20+ #[ derive( Debug , Clone , Eq , PartialEq , Default ) ]
21+ struct PathDataList ( SmallVec < [ PathData ; 4 ] > ) ;
22+
1623impl PathInfoList {
17- /// TODO
24+ /// Returns an iterator over the path infos.
1825 pub fn iter ( & self ) -> impl Iterator < Item = & PathInfo > {
1926 self . 0 . iter ( )
2027 }
@@ -51,39 +58,37 @@ impl Iterator for PathInfoListIntoIter {
5158 }
5259}
5360
61+ /// Watcher for the open paths and selected transmission path in a connection.
5462#[ derive( Clone , Debug ) ]
5563pub struct PathWatcher {
56- paths : n0_watcher:: Direct < PathInfoList > ,
64+ paths : n0_watcher:: Direct < PathDataList > ,
5765 selected_path : n0_watcher:: Direct < Option < transports:: Addr > > ,
5866 current : PathInfoList ,
5967}
6068
6169impl PathWatcher {
62- fn apply_selected_path ( & mut self ) {
63- if let Some ( selected_path) = self . selected_path . peek ( ) {
64- for path in self . current . 0 . iter_mut ( ) {
65- path. is_selected = selected_path. is_transport_addr ( & path. remote_addr ) ;
66- }
67- }
70+ fn update_current ( & mut self ) {
71+ let selected_path = self . selected_path . peek ( ) ;
72+ let data = self . paths . peek ( ) ;
73+ let current = data
74+ . 0
75+ . iter ( )
76+ . filter_map ( |data| PathInfo :: new ( data, selected_path. as_ref ( ) ) )
77+ . collect ( ) ;
78+ self . current = PathInfoList ( current)
6879 }
6980}
7081
7182impl Watcher for PathWatcher {
7283 type Value = PathInfoList ;
7384
7485 fn update ( & mut self ) -> bool {
75- let mut updated = false ;
76- if self . paths . update ( ) {
77- self . current = self . paths . peek ( ) . clone ( ) ;
78- updated = true ;
79- }
80- if self . selected_path . update ( ) {
81- updated = true ;
82- }
83- if updated {
84- self . apply_selected_path ( ) ;
86+ if self . paths . update ( ) || self . selected_path . update ( ) {
87+ self . update_current ( ) ;
88+ true
89+ } else {
90+ false
8591 }
86- updated
8792 }
8893
8994 fn peek ( & self ) -> & Self :: Value {
@@ -100,27 +105,55 @@ impl Watcher for PathWatcher {
100105 ) -> Poll < Result < ( ) , n0_watcher:: Disconnected > > {
101106 let poll_paths = self . paths . poll_updated ( cx) ?;
102107 let poll_selected = self . selected_path . poll_updated ( cx) ?;
103- if poll_paths. is_ready ( ) {
104- self . current = self . paths . peek ( ) . clone ( ) ;
105- self . apply_selected_path ( ) ;
106- Poll :: Ready ( Ok ( ( ) ) )
107- } else if poll_selected. is_ready ( ) {
108- self . apply_selected_path ( ) ;
108+ if poll_paths. is_ready ( ) || poll_selected. is_ready ( ) {
109+ self . update_current ( ) ;
109110 Poll :: Ready ( Ok ( ( ) ) )
110111 } else {
111112 Poll :: Pending
112113 }
113114 }
114115}
115116
116- /// TODO
117+ #[ derive( derive_more:: Debug , Clone ) ]
118+ struct PathData {
119+ handle : quinn:: WeakPathHandle ,
120+ remote_addr : TransportAddr ,
121+ is_closed : bool ,
122+ is_abandoned : bool ,
123+ }
124+
125+ impl PartialEq for PathData {
126+ fn eq ( & self , other : & Self ) -> bool {
127+ self . handle . id ( ) == other. handle . id ( )
128+ && self . remote_addr == other. remote_addr
129+ && self . is_closed == other. is_closed
130+ && self . is_abandoned == other. is_abandoned
131+ }
132+ }
133+ impl Eq for PathData { }
134+
135+ impl PathData {
136+ fn new ( conn : & quinn:: Connection , id : PathId , remote_addr : TransportAddr ) -> Option < Self > {
137+ let handle = conn. path ( id) ?;
138+ Some ( PathData {
139+ handle : handle. weak_handle ( ) ,
140+ remote_addr,
141+ is_closed : false ,
142+ is_abandoned : false ,
143+ } )
144+ }
145+ }
146+
147+ /// Information about a network transmission path used by a [`Connection`].
148+ ///
149+ /// [`Connection`]: crate::endpoint::Connection
117150#[ derive( derive_more:: Debug , Clone ) ]
118151pub struct PathInfo {
119- handle : WeakPathHandle ,
152+ handle : quinn :: Path ,
120153 remote_addr : TransportAddr ,
121154 is_selected : bool ,
122- pub ( super ) is_closed : bool ,
123- pub ( super ) is_abandoned : bool ,
155+ is_closed : bool ,
156+ is_abandoned : bool ,
124157}
125158
126159impl PartialEq for PathInfo {
@@ -136,27 +169,21 @@ impl PartialEq for PathInfo {
136169impl Eq for PathInfo { }
137170
138171impl PathInfo {
139- pub ( crate ) fn new (
140- conn : & quinn:: Connection ,
141- id : PathId ,
142- remote_addr : TransportAddr ,
143- selected_path : Option < & transports:: Addr > ,
144- ) -> Option < Self > {
145- let path = conn. path ( id) ?;
146- let is_closed = path. status ( ) . is_err ( ) ;
147- let handle = path. weak_handle ( ) ;
172+ fn new ( data : & PathData , selected_path : Option < & transports:: Addr > ) -> Option < Self > {
173+ let handle = data. handle . upgrade ( ) ?;
148174 let is_selected = selected_path
149175 . as_ref ( )
150- . map ( |addr| addr. is_transport_addr ( & remote_addr) )
176+ . map ( |addr| addr. is_transport_addr ( & data . remote_addr ) )
151177 . unwrap_or ( false ) ;
152178 Some ( PathInfo {
153179 handle,
154- remote_addr,
180+ remote_addr : data . remote_addr . clone ( ) ,
155181 is_selected,
156- is_closed,
157- is_abandoned : false ,
182+ is_closed : data . is_closed ,
183+ is_abandoned : data . is_abandoned ,
158184 } )
159185 }
186+
160187 /// Returns the [`PathId`] of this path.
161188 pub fn id ( & self ) -> PathId {
162189 self . handle . id ( )
@@ -191,20 +218,26 @@ impl PathInfo {
191218
192219 /// Returns stats for this transmission path.
193220 ///
194- /// Returns empty stats if the connection is dropped.
221+ /// Returns an error if the underlying connection has been dropped.
195222 pub fn stats ( & self ) -> PathStats {
196- self . handle . upgrade ( ) . map ( |p| p . stats ( ) ) . unwrap_or_default ( )
223+ self . handle . stats ( )
197224 }
198225
199226 /// Current best estimate of this paths's latency (round-trip-time)
227+ ///
228+ /// Returns an error if the underlying connection has been dropped.
200229 pub fn rtt ( & self ) -> Duration {
201230 self . stats ( ) . rtt
202231 }
203232}
204233
234+ #[ stack_error( derive, add_meta) ]
235+ #[ error( "Connection is dropped" ) ]
236+ pub struct ConnectionDroppedError ;
237+
205238#[ derive( Debug , Clone ) ]
206239pub ( crate ) struct PathWatchable {
207- paths : Watchable < PathInfoList > ,
240+ paths : Watchable < PathDataList > ,
208241 selected_path : Watchable < Option < transports:: Addr > > ,
209242}
210243
@@ -217,30 +250,30 @@ impl PathWatchable {
217250 }
218251
219252 pub ( super ) fn insert ( & self , conn : & quinn:: Connection , id : PathId , remote_addr : TransportAddr ) {
220- let info = PathInfo :: new ( conn, id, remote_addr, self . selected_path . get ( ) . as_ref ( ) ) ;
221- if let Some ( info ) = info {
222- self . update ( move |list| list. push ( info ) ) ;
253+ let data = PathData :: new ( conn, id, remote_addr) ;
254+ if let Some ( data ) = data {
255+ self . update ( move |list| list. push ( data ) ) ;
223256 }
224257 }
225258
226259 pub ( super ) fn set_closed ( & self , id : PathId ) {
227260 self . update ( |list| {
228- if let Some ( item) = list. iter_mut ( ) . find ( |p| p. id ( ) == id) {
261+ if let Some ( item) = list. iter_mut ( ) . find ( |p| p. handle . id ( ) == id) {
229262 item. is_closed = true ;
230263 }
231264 } ) ;
232265 }
233266
234267 pub ( super ) fn set_abandoned ( & self , id : PathId ) {
235268 self . update ( |list| {
236- if let Some ( item) = list. iter_mut ( ) . find ( |p| p. id ( ) == id) {
269+ if let Some ( item) = list. iter_mut ( ) . find ( |p| p. handle . id ( ) == id) {
237270 item. is_closed = true ;
238271 item. is_abandoned = true ;
239272 }
240273 } ) ;
241274 }
242275
243- fn update ( & self , f : impl FnOnce ( & mut SmallVec < [ PathInfo ; 4 ] > ) ) {
276+ fn update ( & self , f : impl FnOnce ( & mut SmallVec < [ PathData ; 4 ] > ) ) {
244277 let mut value = self . paths . get ( ) ;
245278 f ( & mut value. 0 ) ;
246279 if !self . paths . has_watchers ( ) {
@@ -250,14 +283,12 @@ impl PathWatchable {
250283 }
251284
252285 pub ( crate ) fn watch ( & self ) -> PathWatcher {
253- let paths = self . paths . watch ( ) ;
254- let current = paths. peek ( ) . clone ( ) ;
255286 let mut watcher = PathWatcher {
256- paths,
287+ paths : self . paths . watch ( ) ,
257288 selected_path : self . selected_path . watch ( ) ,
258- current,
289+ current : Default :: default ( ) ,
259290 } ;
260- watcher. apply_selected_path ( ) ;
291+ watcher. update_current ( ) ;
261292 watcher
262293 }
263294}
0 commit comments