@@ -111,6 +111,12 @@ struct parsed_reply final {
111111 std::chrono::steady_clock::now ().time_since_epoch ()).count ();
112112}
113113
114+ [[nodiscard]] std::uint64_t unix_now_ms () noexcept
115+ {
116+ return static_cast <std::uint64_t >(std::chrono::duration_cast<std::chrono::milliseconds>(
117+ std::chrono::system_clock::now ().time_since_epoch ()).count ());
118+ }
119+
114120[[nodiscard]] WinMTRProbeOutcome classify_probe_outcome (DWORD status) noexcept
115121{
116122 switch (status) {
@@ -144,6 +150,13 @@ struct parsed_reply final {
144150 && outcome != WinMTRProbeOutcome::local_error;
145151}
146152
153+ [[nodiscard]] bool is_terminal_destination_outcome (
154+ WinMTRProbeOutcome outcome) noexcept
155+ {
156+ return outcome == WinMTRProbeOutcome::echo_reply
157+ || outcome == WinMTRProbeOutcome::destination_unreachable;
158+ }
159+
147160[[nodiscard]] std::size_t reply_buffer_size (ADDRESS_FAMILY family, std::size_t request_size) noexcept
148161{
149162 const auto reply_header = family == AF_INET
@@ -409,7 +422,7 @@ void CALLBACK probe_work_callback(PTP_CALLBACK_INSTANCE, void* context, PTP_WORK
409422 if (is_usable_trace_reply (request->outcome )
410423 && isValidAddress (request->parsed .address )) {
411424 request->completion_kind = winmtr::probe::CompletionKind::reply;
412- request->destination_reply = request->parsed . status == IP_SUCCESS
425+ request->destination_reply = is_terminal_destination_outcome ( request->outcome )
413426 && same_network_address (request->parsed .address , request->destination );
414427 }
415428 else if (request->probe .issued
@@ -515,8 +528,12 @@ WinMTRTraceResult WinMTRNet::DoTrace(std::stop_token stop_token, SOCKADDR_INET a
515528 bool session_had_usable_reply = false ;
516529 bool stopping = false ;
517530 bool exploration_cycle = true ;
531+ bool initial_discovery = true ;
518532 unsigned highest_response_ttl = 0 ;
519533 unsigned destination_ttl = 0 ;
534+ unsigned stable_ceiling = initial_ceiling;
535+ unsigned shrink_candidate = 0 ;
536+ unsigned shrink_confirmations = 0 ;
520537
521538 const auto notify_changed = [this ] {
522539 if (options != nullptr ) options->notifyTraceDataChanged ();
@@ -540,15 +557,42 @@ WinMTRTraceResult WinMTRNet::DoTrace(std::stop_token stop_token, SOCKADDR_INET a
540557 ? std::max (mandatory_ttl, destination_ttl)
541558 : std::min (trace_options.max_hops ,
542559 std::max (mandatory_ttl, tail_origin + trace_options.unknown_host_limit ));
543- scheduler.set_last_ttl (normal_ceiling, monotonic_now ());
560+ if (initial_discovery) {
561+ stable_ceiling = normal_ceiling;
562+ initial_discovery = false ;
563+ shrink_candidate = 0 ;
564+ shrink_confirmations = 0 ;
565+ }
566+ else if (normal_ceiling < stable_ceiling) {
567+ if (shrink_candidate == normal_ceiling) {
568+ ++shrink_confirmations;
569+ }
570+ else {
571+ shrink_candidate = normal_ceiling;
572+ shrink_confirmations = 1 ;
573+ }
574+ if (shrink_confirmations >= WinMTRUtils::PATH_SHRINK_CONFIRMATIONS ) {
575+ stable_ceiling = normal_ceiling;
576+ shrink_candidate = 0 ;
577+ shrink_confirmations = 0 ;
578+ }
579+ }
580+ else {
581+ stable_ceiling = normal_ceiling;
582+ shrink_candidate = 0 ;
583+ shrink_confirmations = 0 ;
584+ }
585+ scheduler.set_last_ttl (stable_ceiling, monotonic_now ());
544586 exploration_cycle = false ;
545587 }
546588 if (reported_cycles % WinMTRUtils::PATH_EXPLORATION_PERIOD == 0
547- && scheduler. active_last_ttl () < trace_options.max_hops ) {
589+ && stable_ceiling < trace_options.max_hops ) {
548590 exploration_cycle = true ;
549591 highest_response_ttl = 0 ;
550592 destination_ttl = 0 ;
551- scheduler.set_last_ttl (trace_options.max_hops , monotonic_now ());
593+ const auto frontier_ceiling = std::min (trace_options.max_hops ,
594+ stable_ceiling + WinMTRUtils::PATH_EXPLORATION_FRONTIER_TTLS );
595+ scheduler.set_last_ttl (frontier_ceiling, monotonic_now ());
552596 }
553597 }
554598 };
@@ -562,8 +606,12 @@ WinMTRTraceResult WinMTRNet::DoTrace(std::stop_token stop_token, SOCKADDR_INET a
562606 session_reached_destination = false ;
563607 session_had_usable_reply = false ;
564608 exploration_cycle = true ;
609+ initial_discovery = true ;
565610 highest_response_ttl = 0 ;
566611 destination_ttl = 0 ;
612+ stable_ceiling = initial_ceiling;
613+ shrink_candidate = 0 ;
614+ shrink_confirmations = 0 ;
567615 scheduler.restart (current_epoch, now);
568616 scheduler.set_last_ttl (initial_ceiling, now);
569617 }
@@ -573,6 +621,23 @@ WinMTRTraceResult WinMTRNet::DoTrace(std::stop_token stop_token, SOCKADDR_INET a
573621 if (found == requests.end ()) continue ;
574622 const auto disposition = scheduler.complete (request->token ,
575623 request->completion_kind , request->completed_at );
624+ const auto accepted_after_destination = destination_ttl != 0
625+ && request->token .ttl > std::max (mandatory_ttl, destination_ttl)
626+ && (disposition == winmtr::probe::CompletionDisposition::accepted_reply
627+ || disposition == winmtr::probe::CompletionDisposition::accepted_timeout
628+ || disposition == winmtr::probe::CompletionDisposition::accepted_local_error
629+ || disposition
630+ == winmtr::probe::CompletionDisposition::late_discarded_after_timeout);
631+ if (accepted_after_destination) {
632+ commitPostDestinationCompletion (request->token .ttl , request->token .epoch );
633+ if (disposition
634+ == winmtr::probe::CompletionDisposition::late_discarded_after_timeout) {
635+ commitLateCompletion (request->token .ttl , request->token .epoch );
636+ }
637+ notify_changed ();
638+ requests.erase (found);
639+ continue ;
640+ }
576641 switch (disposition) {
577642 case winmtr::probe::CompletionDisposition::accepted_reply: {
578643 commitReply (request->token .ttl , request->parsed .address ,
@@ -626,7 +691,13 @@ WinMTRTraceResult WinMTRNet::DoTrace(std::stop_token stop_token, SOCKADDR_INET a
626691 }
627692 if (!stopping) {
628693 for (const auto & expired : scheduler.expire (now)) {
629- commitTimeout (expired.ttl , expired.epoch );
694+ if (destination_ttl != 0
695+ && expired.ttl > std::max (mandatory_ttl, destination_ttl)) {
696+ commitPostDestinationCompletion (expired.ttl , expired.epoch );
697+ }
698+ else {
699+ commitTimeout (expired.ttl , expired.epoch );
700+ }
630701 notify_changed ();
631702 }
632703
@@ -733,6 +804,10 @@ void WinMTRNet::beginSession(const SOCKADDR_INET& address, std::wstring target,
733804 display_max_ttl = 0 ;
734805 reply_sequence = 0 ;
735806 completed_cycles = 0 ;
807+ session_started_at_unix_ms = unix_now_ms ();
808+ session_ended_at_unix_ms = 0 ;
809+ session_started_tick = GetTickCount64 ();
810+ session_ended_tick = 0 ;
736811 ++data_revision;
737812 for (unsigned index = 0 ; index < host.size (); ++index) {
738813 host[index].reset (index + 1 );
@@ -741,9 +816,12 @@ void WinMTRNet::beginSession(const SOCKADDR_INET& address, std::wstring target,
741816
742817void WinMTRNet::finishSession (std::uint64_t expected_session) noexcept
743818{
744- if (session_id.load (std::memory_order_acquire) == expected_session) {
745- tracing.store (false , std::memory_order_release);
746- }
819+ std::scoped_lock lock (ghMutex);
820+ if (session_id.load (std::memory_order_relaxed) != expected_session) return ;
821+ session_ended_at_unix_ms = unix_now_ms ();
822+ session_ended_tick = GetTickCount64 ();
823+ tracing.store (false , std::memory_order_release);
824+ ++data_revision;
747825}
748826
749827void WinMTRNet::ResetHops () noexcept
@@ -876,6 +954,16 @@ void WinMTRNet::commitLateCompletion(unsigned ttl,
876954 ++data_revision;
877955}
878956
957+ void WinMTRNet::commitPostDestinationCompletion (unsigned ttl,
958+ std::uint64_t expected_epoch) noexcept
959+ {
960+ if (ttl == 0 || ttl > host.size ()) return ;
961+ std::scoped_lock lock (ghMutex);
962+ if (data_epoch.load (std::memory_order_relaxed) != expected_epoch) return ;
963+ host[ttl - 1 ].notePostDestinationCompletion ();
964+ ++data_revision;
965+ }
966+
879967void WinMTRNet::commitReply (unsigned ttl, const SOCKADDR_INET & responder,
880968 unsigned round_trip_ms, std::uint64_t cycle, std::uint64_t tick,
881969 std::uint64_t expected_session, std::uint64_t expected_epoch,
0 commit comments