29#ifndef OPENVPN_CLIENT_SERVERPROBER_H
30#define OPENVPN_CLIENT_SERVERPROBER_H
51class ServerProber :
public std::enable_shared_from_this<ServerProber>
82 const Time::Duration &probe_window_arg)
87 stats(std::move(stats_arg)),
89 timer(io_context_arg),
108 std::vector<Target> targets;
116 for (
const auto &t : targets)
120 timer.async_wait([self = shared_from_this()](
const openvpn_io::error_code &error)
132 openvpn_io::error_code ec;
158 openvpn_io::error_code ec;
161 return std::move(slot);
191 if (!item || !item->transport_protocol.is_udp())
196 for (
size_t j = 0; item->get_endpoint(ep, j); ++j)
197 targets.push_back({i, ep});
199 catch (
const std::exception &)
209 const bool v4 = target.address().is_v4();
211 const openvpn_io::ip::udp proto = v4 ? openvpn_io::ip::udp::v4() : openvpn_io::ip::udp::v6();
215 auto s = std::make_unique<UDPSocket>(
io_context);
216 openvpn_io::error_code ec;
220 OPENVPN_LOG(
"ServerProber: socket open failed: " << ec.message());
226 OPENVPN_LOG(
"ServerProber: socket_protect failed (continuing)");
254 openvpn_io::error_code ec;
258 OPENVPN_LOG(
"ServerProber: send to " << t.
ep <<
" failed: " << ec.message());
268 if (
halt || !slot || !slot->is_open())
270 auto rc = std::make_shared<RecvCtx>();
272 slot->async_receive_from(
rc->buf.mutable_buffer(),
rc->sender, [self = shared_from_this(), v4,
rc](
const openvpn_io::error_code &error,
const size_t bytes_recvd)
mutable
276 if (!error && bytes_recvd)
278 rc->buf.set_size(bytes_recvd);
285 self->handle_reply(
rc->sender,
rc->buf);
287 catch (
const std::exception &e)
290 OPENVPN_LOG(
"ServerProber: exception processing reply from "
291 <<
rc->sender <<
": " << e.what());
295 if (!self->halt && error != openvpn_io::error::operation_aborted)
296 self->queue_recv(v4); });
302 auto it =
pending.find(sender);
305 const Time::Duration rtt =
Time::now() - it->second.sent;
322 .port = it->first.port(),
std::size_t expires_after(const Time::Duration &d)
virtual bool socket_protect(openvpn_io::detail::socket_type socket, IP::Addr endpoint)=0
void reset(const size_t min_capacity, const BufferFlags flags=BufAllocFlags::NO_FLAGS)
Resets the buffer with the specified minimum capacity and flags.
openvpn_io::const_buffer const_buffer() const
Return an openvpn_io::const_buffer object used by asio write methods.
static Addr from_asio(const openvpn_io::ip::address &addr)
Wrap an out-of-band SERVER_PROBE / unwrap the matching PROBE_REPLY.
UnwrapStatus unwrap(BufferAllocated &recv, BufferAllocated &work, ProtoSessionID &src_psid, PacketIDControl &pid)
Unwrap a received PROBE_REPLY in place.
const ProtoSessionID & self_psid() const
the client session id carried in the probe (echoed back in the reply)
void wrap(BufferAllocated &buf, BufferAllocated &work)
Wrap an already-encoded SERVER_PROBE payload in place.
Item::Ptr get_item(const size_t index) const
void queue_recv(const bool v4)
void handle_reply(const UDPEndpoint &sender, BufferAllocated &buf)
Unwrap a PROBE_REPLY and record a Result, ignoring anything unsolicited.
NotifyCallback * notify_callback
std::unique_ptr< UDPSocket > release_socket(const IP::Addr::Version v)
Hand off the probe socket for an address family so it can be adopted as the connection socket (source...
std::unique_ptr< UDPSocket > sock_v6
std::unique_ptr< UDPSocket > sock_v4
~ServerProber()
Cancels any in-flight probe; see stop().
Time::Duration probe_window
void gather_targets(std::vector< Target > &targets)
Collect every resolved UDP endpoint from the remote list.
ProtoContext::ProbeWrap probe_wrap
void send_probe(const Target &t)
Wrap and send one SERVER_PROBE, recording the endpoint as pending.
openvpn_io::ip::udp::endpoint UDPEndpoint
void stop()
Cancel probing without invoking the callback. Sockets stay open (transferable).
UDPSocket * socket_for(const UDPEndpoint &target)
Lazily open (and socket_protect) the per-family socket, arming its receive.
void start(NotifyCallback *cb)
Begin probing. cb->server_probe_done() fires exactly once, when the probe window elapses (or immediat...
RemoteList::Ptr remote_list
ServerProber(openvpn_io::io_context &io_context_arg, RemoteList::Ptr remote_list_arg, ProtoContext::ProtoConfig::Ptr proto_config_arg, SocketProtect *socket_protect_arg, SessionStats::Ptr stats_arg, const Time::Duration &probe_window_arg)
openvpn_io::ip::udp::socket UDPSocket
openvpn_io::io_context & io_context
ProtoContext::ProtoConfig::Ptr proto_config
SocketProtect * socket_protect
std::map< UDPEndpoint, Pending > pending
std::vector< Result > results
base_type seconds_since_epoch() const
#define OPENVPN_LOG(args)
void work(openvpn_io::io_context &io_context, ThreadCommon &tc, MyRunContext &runctx, const unsigned int unit)
constexpr BufferFlags NO_FLAGS(0U)
no flags set
bool server_probe_write(Buffer &buf, const ProbeParameter ¶m)
Write a complete SERVER_PROBE (message header + probe_parameter TLV). Client.
std::optional< ProbeReply > client_reply_read(Buffer &buf)
virtual void server_probe_done(std::vector< Result > results)=0
called once when the probe window closes, with every reply collected
virtual ~NotifyCallback()=default
One responding server, with its measured latency and advertised parameters.
Time::Duration rtt
measured probe round-trip time
size_t remote_index
index of the remote in the RemoteList
unsigned short port
the port that answered
oob::ProbeReply reply
priority / weight / connect_lifetime / flags
IP::Addr addr
the address that answered
probe parameter TLV (sent by the client in a SERVER_PROBE).
std::uint64_t timestamp
client clock as a UNIX timestamp
probe reply TLV (sent by the server in a PROBE_REPLY).