forked from leeter/WinMTR-refresh
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathWinMTRNet-ClassDef.ixx
More file actions
238 lines (222 loc) · 8.22 KB
/
Copy pathWinMTRNet-ClassDef.ixx
File metadata and controls
238 lines (222 loc) · 8.22 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
/*
WinMTR
Copyright (C) 2010-2019 Appnor MSP S.A. - http://www.appnor.com
Copyright (C) 2019-2023 Leetsoftwerx
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; version 2
of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
module;
#pragma warning (disable : 4005)
#include "targetver.h"
#define WIN32_LEAN_AND_MEAN
#define VC_EXTRALEAN
#define NOMCX
#define NOIME
#define NOGDI
#define NONLS
#define NOAPISET
#define NOSERVICE
#define NOMINMAX
#include <winsock2.h>
#include <ws2ipdef.h>
export module WinMTR.Net:ClassDef;
import <optional>;
import <atomic>;
import <array>;
import <condition_variable>;
import <deque>;
import <mutex>;
import <memory>;
import <stop_token>;
import <thread>;
import <vector>;
import <string>;
import <string_view>;
import <cstdint>;
import <unordered_map>;
import <unordered_set>;
import WinMTRSNetHost;
import WinMTROptionsProvider;
import WinMTRUtils;
import winmtr.helper;
export struct WinMTRTraceSnapshot final {
std::uint64_t session_id = 0;
std::uint64_t data_epoch = 0;
std::uint64_t revision = 0;
std::uint64_t started_at_unix_ms = 0;
std::uint64_t ended_at_unix_ms = 0;
std::uint64_t duration_ms = 0;
std::wstring target;
SOCKADDR_INET target_address = {};
ADDRESS_FAMILY address_family = AF_UNSPEC;
unsigned start_ttl = WinMTRUtils::DEFAULT_START_TTL;
unsigned display_max_ttl = 0;
unsigned first_actual_ttl = 0;
std::uint64_t first_actual_sent = 0;
bool tracing = false;
std::vector<s_nethost> hops;
};
export enum class WinMTRTraceResult {
no_reply,
reply,
destination
};
//*****************************************************************************
// CLASS: WinMTRNet
//
//
//*****************************************************************************
export class WinMTRNet final : public std::enable_shared_from_this<WinMTRNet> {
WinMTRNet(const WinMTRNet&) = delete;
WinMTRNet& operator=(const WinMTRNet&) = delete;
public:
WinMTRNet(const IWinMTROptionsProvider* wp)
:host(),
last_remote_addr(),
options(wp),
wsaHelper(MAKEWORD(2, 2)),
tracing() {
for (unsigned index = 0; index < host.size(); ++index) {
host[index].hop = index + 1;
}
if (!wsaHelper) [[unlikely]] {
//AfxMessageBox(IDP_SOCKETS_INIT_FAILED);
return;
}
startMetadataWorkers();
}
~WinMTRNet() noexcept;
// Synchronous trace scheduler. The dialog owns the background std::jthread
// and calls this method from that worker, so no Windows Runtime is required.
[[nodiscard]] WinMTRTraceResult DoTrace(std::stop_token stop_token, SOCKADDR_INET address,
std::wstring target = {}, bool stop_after_unreached_first_round = false);
[[nodiscard]] std::optional<SOCKADDR_INET> SelectCandidate(std::stop_token stop_token,
const std::vector<SOCKADDR_INET>& candidates) const;
void ResetHops() noexcept;
[[nodiscard]]
int GetMax() const;
[[nodiscard]]
std::vector<s_nethost> getCurrentState() const;
[[nodiscard]]
WinMTRTraceSnapshot getTraceSnapshot() const;
s_nethost getStateAt(int at) const
{
std::scoped_lock lock(ghMutex);
if (at < 0 || static_cast<std::size_t>(at) >= host.size()) {
return {};
}
return host[at];
}
[[nodiscard]]
bool isTracing() const noexcept { return tracing.load(std::memory_order_acquire); }
[[nodiscard]]
std::uint64_t getSessionId() const noexcept { return session_id.load(std::memory_order_acquire); }
[[nodiscard]]
std::uint64_t getDataEpoch() const noexcept { return data_epoch.load(std::memory_order_acquire); }
// Safe integration point for asynchronous country/ASN/ISP resolvers.
// Results from an older session/reset are rejected.
bool updateResponderMetadata(std::uint64_t expected_session,
std::uint64_t expected_epoch,
const SOCKADDR_INET& address,
std::wstring name,
std::wstring country,
std::wstring asn,
std::wstring isp);
static constexpr auto MAX_HOPS = WinMTRUtils::MAX_MAX_HOPS;
private:
std::array<s_nethost, WinMTRNet::MAX_HOPS> host;
SOCKADDR_INET last_remote_addr;
std::wstring target_name;
mutable std::mutex ghMutex;
const IWinMTROptionsProvider* options;
winmtr::helper::WSAHelper wsaHelper;
std::atomic_bool tracing = false;
std::atomic_uint64_t session_id = 0;
std::atomic_uint64_t data_epoch = 0;
std::uint64_t reply_sequence = 0;
std::uint64_t completed_cycles = 0;
std::uint64_t data_revision = 0;
std::uint64_t session_started_at_unix_ms = 0;
std::uint64_t session_ended_at_unix_ms = 0;
std::uint64_t session_started_tick = 0;
std::uint64_t session_ended_tick = 0;
unsigned session_start_ttl = WinMTRUtils::DEFAULT_START_TTL;
unsigned display_max_ttl = 0;
// A staggered sweep can receive the target at several TTLs before the
// shortest one completes. Snapshots expose only the lowest known target TTL.
unsigned session_destination_ttl = 0;
WinMTRTraceOptions session_options;
struct responder_metadata final {
std::wstring name;
std::wstring country;
std::wstring asn;
std::wstring isp;
std::wstring source;
std::wstring failure_reason;
bool hostname_queried = false;
bool network_queried = false;
std::uint64_t cached_at_tick = 0;
std::uint64_t hostname_cached_at_tick = 0;
std::uint64_t network_cached_at_tick = 0;
};
struct metadata_job final {
SOCKADDR_INET address = {};
std::wstring address_key;
std::wstring lookup_token;
std::uint64_t expected_session = 0;
std::uint64_t expected_epoch = 0;
bool resolve_hostname = false;
bool lookup_asn_isp = false;
std::stop_token cancellation;
};
std::unordered_map<std::wstring, responder_metadata> responder_lookup_cache;
std::unordered_set<std::wstring> reverse_dns_inflight;
std::stop_source metadata_session_stop;
std::mutex metadata_queue_mutex;
std::condition_variable_any metadata_queue_changed;
std::deque<metadata_job> metadata_jobs;
std::vector<std::jthread> metadata_workers;
void beginSession(const SOCKADDR_INET& address, std::wstring target,
const WinMTRTraceOptions& trace_options);
void finishSession(std::uint64_t expected_session) noexcept;
void setDisplayMaximum(unsigned ttl, std::uint64_t expected_epoch) noexcept;
void setCompletedCycles(std::uint64_t cycles, std::uint64_t expected_epoch) noexcept;
[[nodiscard]] bool replyIsCached(unsigned ttl, std::uint64_t now_tick,
unsigned cache_seconds, std::uint64_t expected_epoch,
bool& is_destination) const noexcept;
void commitTimeout(unsigned ttl, std::uint64_t expected_epoch) noexcept;
void commitIssued(unsigned ttl, std::uint64_t expected_epoch,
std::uint64_t scheduler_lateness_ms) noexcept;
void commitLocalError(unsigned ttl, std::uint64_t expected_epoch,
bool was_issued, std::uint32_t error_code) noexcept;
void commitCancelled(unsigned ttl, std::uint64_t expected_epoch) noexcept;
void commitSchedulerSkipped(unsigned ttl, std::uint64_t expected_epoch) noexcept;
void commitCacheSkipped(unsigned ttl, std::uint64_t expected_epoch) noexcept;
void commitLateCompletion(unsigned ttl, std::uint64_t expected_epoch) noexcept;
void commitPostDestinationCompletion(unsigned ttl,
std::uint64_t expected_epoch) noexcept;
void commitReply(unsigned ttl, const SOCKADDR_INET& responder, unsigned round_trip_ms,
std::uint64_t cycle, std::uint64_t tick, std::uint64_t expected_session,
std::uint64_t expected_epoch, WinMTRProbeOutcome outcome,
std::uint32_t status_code, bool is_destination, bool resolve_hostname,
bool lookup_asn_isp);
void scheduleReverseLookup(const SOCKADDR_INET& address,
std::uint64_t expected_session, std::uint64_t expected_epoch,
bool resolve_hostname, bool lookup_asn_isp);
void startMetadataWorkers();
void metadataWorkerLoop(std::stop_token stop_token) noexcept;
void executeMetadataJob(metadata_job job) noexcept;
[[nodiscard]] static bool hostnameCacheFresh(const responder_metadata& metadata,
std::uint64_t now) noexcept;
[[nodiscard]] static bool networkCacheFresh(const responder_metadata& metadata,
std::uint64_t now) noexcept;
};