feat(listener): ListenerQUIC listens on the address it is given
A new constructor takes a numeric bind address first, as ListenerTCP's does: 127.0.0.1 or ::1 for this machine alone, 0.0.0.0 or :: for every address of one family. Until now every QUIC listener listened on every address of both families (QUIC_ADDRESS_FAMILY_UNSPEC), so a server meant for this machine's own processes, such as a debug server embedded in an app, was reachable from the network. A name such as `localhost` is refused (AI_NUMERICHOST) rather than bound to whichever address the resolver ranks first. The port-only constructor keeps listening on every address. msquic binds the dual-stack wildcard UDP socket for the port whatever address it is given, and filters by the address a connection was sent to in its own listener lookup (QuicBindingGetListener). A connection to another address of the machine is closed with no_application_protocol during its first flight, so the client fails at once (QUIC_STATUS_ALPN_NEG_FAILURE, 4 ms on loopback here) rather than waiting out its handshake timeout, and never reaches connectCallback. Both constructors now share Impl::Start, which leaves nothing open when it throws. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
fdb0ac2524
commit
bffb757ab7
2 changed files with 112 additions and 33 deletions
|
|
@ -27,12 +27,29 @@ namespace Crafter {
|
|||
std::uint32_t totalClientLimit;
|
||||
std::string alpn;
|
||||
|
||||
// Every address of both families at `port`.
|
||||
ListenerQUIC(std::uint16_t port,
|
||||
std::string alpn,
|
||||
QUICServerCredentials creds,
|
||||
std::function<void(ClientQUIC*)> connectCallback,
|
||||
std::uint32_t concurrentClientLimit = std::numeric_limits<std::uint32_t>::max(),
|
||||
std::uint32_t totalClientLimit = std::numeric_limits<std::uint32_t>::max());
|
||||
// One local address. `bindAddress` is a numeric IPv4 or IPv6 address
|
||||
// (127.0.0.1 or ::1 for this machine alone, 0.0.0.0 for every IPv4
|
||||
// address, :: for every IPv6 one) and a name such as `localhost` is
|
||||
// refused with QUICException: the address decides who can reach the
|
||||
// listener, so it is spelled out rather than looked up, as
|
||||
// ListenerTCP takes it. msquic still binds the UDP port on every
|
||||
// address and filters by the address a connection was sent to, at
|
||||
// its own layer: one sent to another address of this machine fails
|
||||
// its handshake at once, refused as having no application protocol.
|
||||
ListenerQUIC(std::string_view bindAddress,
|
||||
std::uint16_t port,
|
||||
std::string alpn,
|
||||
QUICServerCredentials creds,
|
||||
std::function<void(ClientQUIC*)> connectCallback,
|
||||
std::uint32_t concurrentClientLimit = std::numeric_limits<std::uint32_t>::max(),
|
||||
std::uint32_t totalClientLimit = std::numeric_limits<std::uint32_t>::max());
|
||||
|
||||
~ListenerQUIC();
|
||||
ListenerQUIC(const ListenerQUIC&) = delete;
|
||||
|
|
|
|||
Loading…
Reference in a new issue