@@ -49,14 +49,29 @@ pub enum CompletionReason {
4949 RoundTimeLimitExceeded ,
5050}
5151
52+ /// The action to take after the completion of a round.
53+ #[ derive( Debug , Copy , Clone , Eq , PartialEq ) ]
54+ pub enum Action {
55+ /// Continue tracing.
56+ Continue ,
57+ /// Stop tracing.
58+ Stop ,
59+ }
60+
61+ impl From < ( ) > for Action {
62+ fn from ( ( ) : ( ) ) -> Self {
63+ Self :: Continue
64+ }
65+ }
66+
5267/// Trace a path to a target.
5368#[ derive( Debug , Clone ) ]
5469pub struct Strategy < F > {
5570 config : StrategyConfig ,
5671 publish : F ,
5772}
5873
59- impl < F : Fn ( & Round < ' _ > ) > Strategy < F > {
74+ impl < F : Fn ( & Round < ' _ > ) -> Action > Strategy < F > {
6075 #[ instrument( skip_all, level = "trace" ) ]
6176 pub fn new ( config : & StrategyConfig , publish : F ) -> Self {
6277 tracing:: debug!( ?config) ;
@@ -192,8 +207,8 @@ impl<F: Fn(&Round<'_>)> Strategy<F> {
192207 let round_max = round_duration > self . config . max_round_duration ;
193208 let target_found = st. target_found ( ) ;
194209 if round_min && grace_exceeded && target_found || round_max {
195- self . publish_trace ( st) ;
196- st. advance_round ( self . config . first_ttl ) ;
210+ let action = self . publish_trace ( st) ;
211+ st. advance_round ( self . config . first_ttl , action ) ;
197212 }
198213 }
199214
@@ -202,7 +217,7 @@ impl<F: Fn(&Round<'_>)> Strategy<F> {
202217 /// If the round completed without receiving an `EchoReply` from the target host then we also
203218 /// publish the next `ProbeStatus` which is assumed to represent the TTL of the target host.
204219 #[ instrument( skip( self , state) , level = "trace" ) ]
205- fn publish_trace ( & self , state : & TracerState ) {
220+ fn publish_trace ( & self , state : & TracerState ) -> Action {
206221 let max_received_ttl = if let Some ( target_ttl) = state. target_ttl ( ) {
207222 target_ttl
208223 } else {
@@ -220,7 +235,7 @@ impl<F: Fn(&Round<'_>)> Strategy<F> {
220235 } else {
221236 CompletionReason :: RoundTimeLimitExceeded
222237 } ;
223- ( self . publish ) ( & Round :: new ( probes, largest_ttl, reason) ) ;
238+ ( self . publish ) ( & Round :: new ( probes, largest_ttl, reason) )
224239 }
225240
226241 /// Check if the `TraceId` matches the expected value for this tracer.
@@ -840,7 +855,7 @@ mod tests {
840855 protocol : Protocol :: Tcp ,
841856 ..Default :: default ( )
842857 } ;
843- let tracer = Strategy :: new ( & config, |_| { } ) ;
858+ let tracer = Strategy :: new ( & config, |_| Action :: Continue ) ;
844859 let mut state = TracerState :: new ( config) ;
845860 tracer. send_request ( & mut network, & mut state) ?;
846861 tracer. recv_response ( & mut network, & mut state) ?;
@@ -870,7 +885,7 @@ mod state {
870885 use crate :: probe:: { Probe , ProbeStatus } ;
871886 use crate :: strategy:: { StrategyConfig , StrategyResponse } ;
872887 use crate :: types:: { MaxRounds , Port , RoundId , Sequence , TimeToLive , TraceId } ;
873- use crate :: { Flags , MultipathStrategy , PortDirection , Protocol } ;
888+ use crate :: { Action , Flags , MultipathStrategy , PortDirection , Protocol } ;
874889 use std:: array:: from_fn;
875890 use std:: net:: IpAddr ;
876891 use std:: time:: SystemTime ;
@@ -929,6 +944,8 @@ mod state {
929944 target_ttl : Option < TimeToLive > ,
930945 /// The timestamp of the echo response packet.
931946 received_time : Option < SystemTime > ,
947+ /// The action to take before starting the next round.
948+ next_round_action : Action ,
932949 }
933950
934951 impl TracerState {
@@ -945,6 +962,7 @@ mod state {
945962 max_received_ttl : None ,
946963 target_ttl : None ,
947964 received_time : None ,
965+ next_round_action : Action :: Continue ,
948966 }
949967 }
950968
@@ -995,11 +1013,12 @@ mod state {
9951013 }
9961014
9971015 /// Are all rounds complete?
998- pub const fn finished ( & self , max_rounds : Option < MaxRounds > ) -> bool {
999- match max_rounds {
1000- None => false ,
1001- Some ( max_rounds) => self . round . 0 > max_rounds. 0 . get ( ) - 1 ,
1002- }
1016+ pub fn finished ( & self , max_rounds : Option < MaxRounds > ) -> bool {
1017+ self . next_round_action == Action :: Stop
1018+ || match max_rounds {
1019+ None => false ,
1020+ Some ( max_rounds) => self . round . 0 > max_rounds. 0 . get ( ) - 1 ,
1021+ }
10031022 }
10041023
10051024 /// Create and return the next `Probe` at the current `sequence` and `ttl`.
@@ -1257,7 +1276,8 @@ mod state {
12571276 /// reset it here. We do this here to avoid having to deal with the sequence number
12581277 /// wrapping during a round, which is more problematic.
12591278 #[ instrument( skip( self ) , level = "trace" ) ]
1260- pub fn advance_round ( & mut self , first_ttl : TimeToLive ) {
1279+ pub fn advance_round ( & mut self , first_ttl : TimeToLive , next_round_action : Action ) {
1280+ self . next_round_action = next_round_action;
12611281 if self . sequence >= self . max_sequence ( ) {
12621282 self . sequence = self . config . initial_sequence ;
12631283 }
@@ -1375,7 +1395,7 @@ mod state {
13751395 }
13761396
13771397 // Advance to the next round
1378- state. advance_round ( TimeToLive ( 1 ) ) ;
1398+ state. advance_round ( TimeToLive ( 1 ) , Action :: Continue ) ;
13791399
13801400 // Validate the `TracerState` after the round update
13811401 assert_eq ! ( state. round, RoundId ( 1 ) ) ;
@@ -1509,7 +1529,7 @@ mod state {
15091529 }
15101530
15111531 // Advance the round, which will wrap the sequence back to `initial_sequence`
1512- state. advance_round ( TimeToLive ( 1 ) ) ;
1532+ state. advance_round ( TimeToLive ( 1 ) , Action :: Continue ) ;
15131533 assert_eq ! ( state. round, RoundId ( 1 ) ) ;
15141534 assert_eq ! ( state. sequence, initial_sequence) ;
15151535 assert_eq ! ( state. round_sequence, initial_sequence) ;
@@ -1547,7 +1567,7 @@ mod state {
15471567 for _ in 0 ..max_probe_per_round {
15481568 let _probe = state. next_probe ( SystemTime :: now ( ) ) ;
15491569 }
1550- state. advance_round ( TimeToLive ( 1 ) ) ;
1570+ state. advance_round ( TimeToLive ( 1 ) , Action :: Continue ) ;
15511571 }
15521572 assert_eq ! ( state. round, RoundId ( 2000 ) ) ;
15531573 assert_eq ! ( state. round_sequence, Sequence ( 33434 ) ) ;
@@ -1564,7 +1584,7 @@ mod state {
15641584 for _ in 0 ..rng. random_range ( 0 ..max_probe_per_round) {
15651585 state. next_probe ( SystemTime :: now ( ) ) ;
15661586 }
1567- state. advance_round ( TimeToLive ( 1 ) ) ;
1587+ state. advance_round ( TimeToLive ( 1 ) , Action :: Continue ) ;
15681588 }
15691589 }
15701590
@@ -1578,7 +1598,7 @@ mod state {
15781598 _ = state. next_probe ( SystemTime :: now ( ) ) ;
15791599 _ = state. reissue_probe ( SystemTime :: now ( ) ) ;
15801600 }
1581- state. advance_round ( TimeToLive ( 1 ) ) ;
1601+ state. advance_round ( TimeToLive ( 1 ) , Action :: Continue ) ;
15821602 }
15831603 assert_eq ! ( state. round, RoundId ( 2000 ) ) ;
15841604 assert_eq ! ( state. round_sequence, Sequence ( 57310 ) ) ;
@@ -1600,7 +1620,7 @@ mod state {
16001620 for _ in 0 ..55 {
16011621 _ = state. next_probe ( SystemTime :: now ( ) ) ;
16021622 }
1603- state. advance_round ( TimeToLive ( 1 ) ) ;
1623+ state. advance_round ( TimeToLive ( 1 ) , Action :: Continue ) ;
16041624 assert ! ( !state. in_round( Sequence ( 64491 ) ) ) ;
16051625 }
16061626
0 commit comments