Convert ConnectTunnel::HostAndPort usage to QuicServerId Will be needed for both CONNECT code and CONNECT-UDP code, so useful to have a neutral standalone type, and QuicServerId often fills that role within similar QUICHE code. Also added some helpers for parsing and emitting host and port strings to avoid having that logic duplicated in my various usages. Also modernized the QuicServerId hashing to use AbslHashValue(), so I can use it in absl::flat_hash_set without explicitly specifying hashing. PiperOrigin-RevId: 469761717
diff --git a/quiche/quic/core/quic_server_id.cc b/quiche/quic/core/quic_server_id.cc index 3618e96..17233ff 100644 --- a/quiche/quic/core/quic_server_id.cc +++ b/quiche/quic/core/quic_server_id.cc
@@ -6,17 +6,67 @@ #include <string> #include <tuple> +#include <utility> + +#include "absl/strings/match.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/string_view.h" +#include "absl/types/optional.h" +#include "url/third_party/mozilla/url_parse.h" +#include "quiche/common/platform/api/quiche_logging.h" namespace quic { +// static +absl::optional<QuicServerId> QuicServerId::ParseFromHostPortString( + absl::string_view host_port_string) { + url::Component username_component; + url::Component password_component; + url::Component host_component; + url::Component port_component; + + url::ParseAuthority(host_port_string.data(), + url::Component(0, host_port_string.size()), + &username_component, &password_component, &host_component, + &port_component); + + // Only support "host:port" and nothing more or less. + if (username_component.is_valid() || password_component.is_valid() || + !host_component.is_nonempty() || !port_component.is_nonempty()) { + QUICHE_DVLOG(1) << "QuicServerId could not be parsed: " << host_port_string; + return absl::nullopt; + } + + std::string hostname(host_port_string.data() + host_component.begin, + host_component.len); + + int parsed_port_number = + url::ParsePort(host_port_string.data(), port_component); + // Negative result is either invalid or unspecified, either of which is + // disallowed for this parse. Port 0 is technically valid but reserved and not + // really usable in practice, so easiest to just disallow it here. + if (parsed_port_number <= 0) { + QUICHE_DVLOG(1) + << "Port could not be parsed while parsing QuicServerId from: " + << host_port_string; + return absl::nullopt; + } + QUICHE_DCHECK_LE(parsed_port_number, std::numeric_limits<uint16_t>::max()); + + return QuicServerId(std::move(hostname), + static_cast<uint16_t>(parsed_port_number)); +} + QuicServerId::QuicServerId() : QuicServerId("", 0, false) {} -QuicServerId::QuicServerId(const std::string& host, uint16_t port) - : QuicServerId(host, port, false) {} +QuicServerId::QuicServerId(std::string host, uint16_t port) + : QuicServerId(std::move(host), port, false) {} -QuicServerId::QuicServerId(const std::string& host, uint16_t port, +QuicServerId::QuicServerId(std::string host, uint16_t port, bool privacy_mode_enabled) - : host_(host), port_(port), privacy_mode_enabled_(privacy_mode_enabled) {} + : host_(std::move(host)), + port_(port), + privacy_mode_enabled_(privacy_mode_enabled) {} QuicServerId::~QuicServerId() {} @@ -34,4 +84,25 @@ return !(*this == other); } +std::string QuicServerId::ToHostPortString() const { + return absl::StrCat(GetHostWithIpv6Brackets(), ":", port_); +} + +absl::string_view QuicServerId::GetHostWithoutIpv6Brackets() const { + if (host_.length() > 2 && host_.front() == '[' && host_.back() == ']') { + return absl::string_view(host_.data() + 1, host_.length() - 2); + } else { + return host_; + } +} + +std::string QuicServerId::GetHostWithIpv6Brackets() const { + if (!absl::StrContains(host_, ':') || host_.length() <= 2 || + (host_.front() == '[' && host_.back() == ']')) { + return host_; + } else { + return absl::StrCat("[", host_, "]"); + } +} + } // namespace quic
diff --git a/quiche/quic/core/quic_server_id.h b/quiche/quic/core/quic_server_id.h index 7f226fd..51d055b 100644 --- a/quiche/quic/core/quic_server_id.h +++ b/quiche/quic/core/quic_server_id.h
@@ -9,6 +9,8 @@ #include <string> #include "absl/hash/hash.h" +#include "absl/strings/string_view.h" +#include "absl/types/optional.h" #include "quiche/quic/platform/api/quic_export.h" namespace quic { @@ -17,10 +19,15 @@ // privacy_mode. class QUIC_EXPORT_PRIVATE QuicServerId { public: + // Attempts to parse a QuicServerId from a "host:port" string. Returns nullopt + // if input could not be parsed. Requires input to contain both host and port + // and no other components of a URL authority. + static absl::optional<QuicServerId> ParseFromHostPortString( + absl::string_view host_port_string); + QuicServerId(); - QuicServerId(const std::string& host, uint16_t port); - QuicServerId(const std::string& host, uint16_t port, - bool privacy_mode_enabled); + QuicServerId(std::string host, uint16_t port); + QuicServerId(std::string host, uint16_t port, bool privacy_mode_enabled); ~QuicServerId(); // Needed to be an element of an ordered container. @@ -35,19 +42,31 @@ bool privacy_mode_enabled() const { return privacy_mode_enabled_; } + // Returns a "host:port" representation. IPv6 literal hosts will always be + // bracketed in result. + std::string ToHostPortString() const; + + // If host is an IPv6 literal surrounded by [], returns the substring without + // []. Otherwise, returns host as is. + absl::string_view GetHostWithoutIpv6Brackets() const; + + // If host is an IPv6 literal without surrounding [], returns host wrapped in + // []. Otherwise, returns host as is. + std::string GetHostWithIpv6Brackets() const; + + template <typename H> + friend H AbslHashValue(H h, const QuicServerId& server_id) { + return H::combine(std::move(h), server_id.host(), server_id.port(), + server_id.privacy_mode_enabled()); + } + private: std::string host_; uint16_t port_; bool privacy_mode_enabled_; }; -class QUIC_EXPORT_PRIVATE QuicServerIdHash { - public: - size_t operator()(const quic::QuicServerId& server_id) const noexcept { - return absl::HashOf(server_id.host(), server_id.port(), - server_id.privacy_mode_enabled()); - } -}; +using QuicServerIdHash = absl::Hash<QuicServerId>; } // namespace quic
diff --git a/quiche/quic/core/quic_server_id_test.cc b/quiche/quic/core/quic_server_id_test.cc index 226a517..1ca7a70 100644 --- a/quiche/quic/core/quic_server_id_test.cc +++ b/quiche/quic/core/quic_server_id_test.cc
@@ -6,12 +6,16 @@ #include <string> +#include "absl/types/optional.h" #include "quiche/quic/platform/api/quic_test.h" namespace quic::test { namespace { +using ::testing::Optional; +using ::testing::Property; + class QuicServerIdTest : public QuicTest {}; TEST_F(QuicServerIdTest, Constructor) { @@ -119,6 +123,103 @@ EXPECT_NE(new_a_10_https_no_private, a_10_https_private); } +TEST_F(QuicServerIdTest, Parse) { + absl::optional<QuicServerId> server_id = + QuicServerId::ParseFromHostPortString("host.test:500"); + + EXPECT_THAT(server_id, Optional(Property(&QuicServerId::host, "host.test"))); + EXPECT_THAT(server_id, Optional(Property(&QuicServerId::port, 500))); + EXPECT_THAT(server_id, + Optional(Property(&QuicServerId::privacy_mode_enabled, false))); +} + +TEST_F(QuicServerIdTest, CannotParseMissingPort) { + absl::optional<QuicServerId> server_id = + QuicServerId::ParseFromHostPortString("host.test"); + + EXPECT_EQ(server_id, absl::nullopt); +} + +TEST_F(QuicServerIdTest, CannotParseEmptyPort) { + absl::optional<QuicServerId> server_id = + QuicServerId::ParseFromHostPortString("host.test:"); + + EXPECT_EQ(server_id, absl::nullopt); +} + +TEST_F(QuicServerIdTest, CannotParseEmptyHost) { + absl::optional<QuicServerId> server_id = + QuicServerId::ParseFromHostPortString(":500"); + + EXPECT_EQ(server_id, absl::nullopt); +} + +TEST_F(QuicServerIdTest, CannotParseUserInfo) { + absl::optional<QuicServerId> server_id = + QuicServerId::ParseFromHostPortString("userinfo@host.test:500"); + + EXPECT_EQ(server_id, absl::nullopt); +} + +TEST_F(QuicServerIdTest, ParseIpv6Literal) { + absl::optional<QuicServerId> server_id = + QuicServerId::ParseFromHostPortString("[::1]:400"); + + EXPECT_THAT(server_id, Optional(Property(&QuicServerId::host, "[::1]"))); + EXPECT_THAT(server_id, Optional(Property(&QuicServerId::port, 400))); + EXPECT_THAT(server_id, + Optional(Property(&QuicServerId::privacy_mode_enabled, false))); +} + +TEST_F(QuicServerIdTest, ParseUnbracketedIpv6Literal) { + absl::optional<QuicServerId> server_id = + QuicServerId::ParseFromHostPortString("::1:400"); + + EXPECT_THAT(server_id, Optional(Property(&QuicServerId::host, "::1"))); + EXPECT_THAT(server_id, Optional(Property(&QuicServerId::port, 400))); + EXPECT_THAT(server_id, + Optional(Property(&QuicServerId::privacy_mode_enabled, false))); +} + +TEST_F(QuicServerIdTest, AddBracketsToIpv6) { + QuicServerId server_id("::1", 100); + + EXPECT_EQ(server_id.GetHostWithIpv6Brackets(), "[::1]"); + EXPECT_EQ(server_id.ToHostPortString(), "[::1]:100"); +} + +TEST_F(QuicServerIdTest, AddBracketsAlreadyIncluded) { + QuicServerId server_id("[::1]", 100); + + EXPECT_EQ(server_id.GetHostWithIpv6Brackets(), "[::1]"); + EXPECT_EQ(server_id.ToHostPortString(), "[::1]:100"); +} + +TEST_F(QuicServerIdTest, AddBracketsNotAddedToNonIpv6) { + QuicServerId server_id("host.test", 100); + + EXPECT_EQ(server_id.GetHostWithIpv6Brackets(), "host.test"); + EXPECT_EQ(server_id.ToHostPortString(), "host.test:100"); +} + +TEST_F(QuicServerIdTest, RemoveBracketsFromIpv6) { + QuicServerId server_id("[::1]", 100); + + EXPECT_EQ(server_id.GetHostWithoutIpv6Brackets(), "::1"); +} + +TEST_F(QuicServerIdTest, RemoveBracketsNotIncluded) { + QuicServerId server_id("::1", 100); + + EXPECT_EQ(server_id.GetHostWithoutIpv6Brackets(), "::1"); +} + +TEST_F(QuicServerIdTest, RemoveBracketsFromNonIpv6) { + QuicServerId server_id("host.test", 100); + + EXPECT_EQ(server_id.GetHostWithoutIpv6Brackets(), "host.test"); +} + } // namespace } // namespace quic::test
diff --git a/quiche/quic/tools/connect_server_backend.cc b/quiche/quic/tools/connect_server_backend.cc index baee9c1..f54e6ab 100644 --- a/quiche/quic/tools/connect_server_backend.cc +++ b/quiche/quic/tools/connect_server_backend.cc
@@ -11,6 +11,7 @@ #include "absl/container/flat_hash_set.h" #include "absl/strings/string_view.h" #include "quiche/quic/core/io/socket_factory.h" +#include "quiche/quic/core/quic_server_id.h" #include "quiche/quic/tools/connect_tunnel.h" #include "quiche/quic/tools/quic_simple_server_backend.h" #include "quiche/common/platform/api/quiche_bug_tracker.h" @@ -34,7 +35,7 @@ ConnectServerBackend::ConnectServerBackend( std::unique_ptr<QuicSimpleServerBackend> non_connect_backend, - absl::flat_hash_set<ConnectTunnel::HostAndPort> acceptable_destinations) + absl::flat_hash_set<QuicServerId> acceptable_destinations) : non_connect_backend_(std::move(non_connect_backend)), acceptable_destinations_(std::move(acceptable_destinations)) { QUICHE_DCHECK(non_connect_backend_);
diff --git a/quiche/quic/tools/connect_server_backend.h b/quiche/quic/tools/connect_server_backend.h index a1cd843..74a21e2 100644 --- a/quiche/quic/tools/connect_server_backend.h +++ b/quiche/quic/tools/connect_server_backend.h
@@ -13,7 +13,7 @@ #include "absl/container/flat_hash_map.h" #include "absl/container/flat_hash_set.h" #include "quiche/quic/core/io/socket_factory.h" -#include "quiche/quic/core/quic_types.h" +#include "quiche/quic/core/quic_server_id.h" #include "quiche/quic/tools/connect_tunnel.h" #include "quiche/quic/tools/quic_simple_server_backend.h" @@ -25,7 +25,7 @@ public: ConnectServerBackend( std::unique_ptr<QuicSimpleServerBackend> non_connect_backend, - absl::flat_hash_set<ConnectTunnel::HostAndPort> acceptable_destinations); + absl::flat_hash_set<QuicServerId> acceptable_destinations); ConnectServerBackend(const ConnectServerBackend&) = delete; ConnectServerBackend& operator=(const ConnectServerBackend&) = delete; @@ -48,8 +48,7 @@ private: std::unique_ptr<QuicSimpleServerBackend> non_connect_backend_; - const absl::flat_hash_set<ConnectTunnel::HostAndPort> - acceptable_destinations_; + const absl::flat_hash_set<QuicServerId> acceptable_destinations_; SocketFactory* socket_factory_; // unowned absl::flat_hash_map<QuicStreamId, std::unique_ptr<ConnectTunnel>> tunnels_;
diff --git a/quiche/quic/tools/connect_tunnel.cc b/quiche/quic/tools/connect_tunnel.cc index e86d628..4a31f12 100644 --- a/quiche/quic/tools/connect_tunnel.cc +++ b/quiche/quic/tools/connect_tunnel.cc
@@ -5,7 +5,6 @@ #include "quiche/quic/tools/connect_tunnel.h" #include <cstdint> -#include <limits> #include <string> #include <utility> #include <vector> @@ -17,9 +16,9 @@ #include "absl/strings/string_view.h" #include "absl/types/optional.h" #include "absl/types/span.h" -#include "url/third_party/mozilla/url_parse.h" #include "quiche/quic/core/io/socket_factory.h" #include "quiche/quic/core/quic_error_codes.h" +#include "quiche/quic/core/quic_server_id.h" #include "quiche/quic/platform/api/quic_socket_address.h" #include "quiche/quic/tools/quic_backend_response.h" #include "quiche/quic/tools/quic_name_lookup.h" @@ -35,57 +34,7 @@ // Arbitrarily chosen. No effort has been made to figure out an optimal size. constexpr size_t kReadSize = 4 * 1024; -absl::optional<ConnectTunnel::HostAndPort> ValidateAndParseAuthorityString( - absl::string_view authority_string) { - url::Component username_component; - url::Component password_component; - url::Component host_component; - url::Component port_component; - - url::ParseAuthority(authority_string.data(), - url::Component(0, authority_string.size()), - &username_component, &password_component, &host_component, - &port_component); - - // A valid CONNECT authority must contain host and port and nothing else, per - // https://www.rfc-editor.org/rfc/rfc9110.html#name-connect. - if (username_component.is_valid() || password_component.is_valid() || - !host_component.is_nonempty() || !port_component.is_nonempty()) { - QUICHE_DVLOG(1) << "CONNECT request authority is malformed: " - << authority_string; - return absl::nullopt; - } - - QUICHE_DCHECK_LT(static_cast<size_t>(host_component.end()), - authority_string.length()); - if (authority_string.length() > 2 && - authority_string.data()[host_component.begin] == '[' && - authority_string.data()[host_component.end() - 1] == ']') { - // Strip "[]" off IPv6 literals. - host_component.begin += 1; - host_component.len -= 2; - } - std::string hostname(authority_string.data() + host_component.begin, - host_component.len); - - int parsed_port_number = - url::ParsePort(authority_string.data(), port_component); - // Negative result is either invalid or unspecified, either of which is - // disallowed for a CONNECT authority. Port 0 is technically valid but - // reserved and not really usable in practice, so easiest to just disallow it - // here. - if (parsed_port_number <= 0) { - QUICHE_DVLOG(1) << "CONNECT request authority port is malformed: " - << authority_string; - return absl::nullopt; - } - QUICHE_DCHECK_LE(parsed_port_number, std::numeric_limits<uint16_t>::max()); - - return ConnectTunnel::HostAndPort(std::move(hostname), - static_cast<uint16_t>(parsed_port_number)); -} - -absl::optional<ConnectTunnel::HostAndPort> ValidateHeadersAndGetAuthority( +absl::optional<QuicServerId> ValidateHeadersAndGetAuthority( const spdy::Http2HeaderBlock& request_headers) { QUICHE_DCHECK(request_headers.contains(":method")); QUICHE_DCHECK(request_headers.find(":method")->second == "CONNECT"); @@ -111,35 +60,39 @@ return absl::nullopt; } - return ValidateAndParseAuthorityString(authority_it->second); + // A valid CONNECT authority must contain host and port and nothing else, per + // https://www.rfc-editor.org/rfc/rfc9110.html#name-connect. This matches the + // host and port parsing rules for QuicServerId. + absl::optional<QuicServerId> server_id = + QuicServerId::ParseFromHostPortString(authority_it->second); + if (!server_id.has_value()) { + QUICHE_DVLOG(1) << "CONNECT request authority is malformed: " + << authority_it->second; + return absl::nullopt; + } + + return server_id; } -bool ValidateAuthority(const ConnectTunnel::HostAndPort& authority, - const absl::flat_hash_set<ConnectTunnel::HostAndPort>& - acceptable_destinations) { +bool ValidateAuthority( + const QuicServerId& authority, + const absl::flat_hash_set<QuicServerId>& acceptable_destinations) { if (acceptable_destinations.contains(authority)) { return true; } QUICHE_DVLOG(1) << "CONNECT request authority: " - << absl::StrCat(authority.host, ":", authority.port) + << authority.ToHostPortString() << " is not an acceptable allow-listed destiation "; return false; } } // namespace -ConnectTunnel::HostAndPort::HostAndPort(std::string host, uint16_t port) - : host(std::move(host)), port(port) {} - -bool ConnectTunnel::HostAndPort::operator==(const HostAndPort& other) const { - return host == other.host && port == other.port; -} - ConnectTunnel::ConnectTunnel( QuicSimpleServerBackend::RequestHandler* client_stream_request_handler, SocketFactory* socket_factory, - absl::flat_hash_set<HostAndPort> acceptable_destinations) + absl::flat_hash_set<QuicServerId> acceptable_destinations) : acceptable_destinations_(std::move(acceptable_destinations)), socket_factory_(socket_factory), client_stream_request_handler_(client_stream_request_handler) { @@ -158,9 +111,9 @@ void ConnectTunnel::OpenTunnel(const spdy::Http2HeaderBlock& request_headers) { QUICHE_DCHECK(!IsConnectedToDestination()); - absl::optional<HostAndPort> authority = + absl::optional<QuicServerId> authority = ValidateHeadersAndGetAuthority(request_headers); - if (!authority) { + if (!authority.has_value()) { TerminateClientStream( "invalid request headers", QuicResetStreamError::FromIetf(QuicHttp3ErrorCode::MESSAGE_ERROR)); @@ -174,8 +127,8 @@ return; } - QuicSocketAddress address = tools::LookupAddress( - AF_UNSPEC, authority->host, absl::StrCat(authority->port)); + QuicSocketAddress address = + tools::LookupAddress(AF_UNSPEC, authority.value()); if (!address.IsInitialized()) { TerminateClientStream("host resolution error"); return; @@ -198,7 +151,7 @@ QUICHE_DVLOG(1) << "CONNECT tunnel opened from stream " << client_stream_request_handler_->stream_id() << " to " - << authority->host << ":" << authority->port; + << authority.value().ToHostPortString(); SendConnectResponse(); BeginAsyncReadFromDestination();
diff --git a/quiche/quic/tools/connect_tunnel.h b/quiche/quic/tools/connect_tunnel.h index d18d63f..357a9d0 100644 --- a/quiche/quic/tools/connect_tunnel.h +++ b/quiche/quic/tools/connect_tunnel.h
@@ -17,6 +17,7 @@ #include "quiche/quic/core/io/socket_factory.h" #include "quiche/quic/core/io/stream_client_socket.h" #include "quiche/quic/core/quic_error_codes.h" +#include "quiche/quic/core/quic_server_id.h" #include "quiche/quic/tools/quic_simple_server_backend.h" #include "quiche/common/platform/api/quiche_mem_slice.h" #include "quiche/spdy/core/http2_header_block.h" @@ -26,26 +27,12 @@ // Manages a single connection tunneled over a CONNECT proxy. class ConnectTunnel : public StreamClientSocket::AsyncVisitor { public: - struct HostAndPort { - HostAndPort(std::string host, uint16_t port); - - bool operator==(const HostAndPort& other) const; - - template <typename H> - friend H AbslHashValue(H h, const HostAndPort& host_and_port) { - return H::combine(std::move(h), host_and_port.host, host_and_port.port); - } - - std::string host; - uint16_t port; - }; - // `client_stream_request_handler` and `socket_factory` must both outlive the // created ConnectTunnel. ConnectTunnel( QuicSimpleServerBackend::RequestHandler* client_stream_request_handler, SocketFactory* socket_factory, - absl::flat_hash_set<HostAndPort> acceptable_destinations); + absl::flat_hash_set<QuicServerId> acceptable_destinations); ~ConnectTunnel(); ConnectTunnel(const ConnectTunnel&) = delete; ConnectTunnel& operator=(const ConnectTunnel&) = delete; @@ -85,7 +72,7 @@ QuicResetStreamError error_code = QuicResetStreamError::FromIetf(QuicHttp3ErrorCode::CONNECT_ERROR)); - const absl::flat_hash_set<HostAndPort> acceptable_destinations_; + const absl::flat_hash_set<QuicServerId> acceptable_destinations_; SocketFactory* const socket_factory_; // Null when client stream closed.
diff --git a/quiche/quic/tools/connect_tunnel_test.cc b/quiche/quic/tools/connect_tunnel_test.cc index a9d4c1d..de569f3 100644 --- a/quiche/quic/tools/connect_tunnel_test.cc +++ b/quiche/quic/tools/connect_tunnel_test.cc
@@ -107,12 +107,13 @@ NiceMock<MockSocketFactory> socket_factory_; StrictMock<MockSocket>* socket_; - ConnectTunnel tunnel_{&request_handler_, - &socket_factory_, - /*acceptable_destinations=*/ - {{std::string(kAcceptableDestination), kAcceptablePort}, - {TestLoopback4().ToString(), kAcceptablePort}, - {TestLoopback6().ToString(), kAcceptablePort}}}; + ConnectTunnel tunnel_{ + &request_handler_, + &socket_factory_, + /*acceptable_destinations=*/ + {{std::string(kAcceptableDestination), kAcceptablePort}, + {TestLoopback4().ToString(), kAcceptablePort}, + {absl::StrCat("[", TestLoopback6().ToString(), "]"), kAcceptablePort}}}; }; TEST_F(ConnectTunnelTest, OpenTunnel) {
diff --git a/quiche/quic/tools/quic_name_lookup.cc b/quiche/quic/tools/quic_name_lookup.cc index 5098e80..63e063e 100644 --- a/quiche/quic/tools/quic_name_lookup.cc +++ b/quiche/quic/tools/quic_name_lookup.cc
@@ -8,6 +8,10 @@ #include <sys/socket.h> #include <sys/types.h> +#include <string> + +#include "absl/strings/str_cat.h" +#include "quiche/quic/core/quic_server_id.h" #include "quiche/quic/platform/api/quic_logging.h" namespace quic::tools { @@ -33,4 +37,11 @@ return QuicSocketAddress(info_list->ai_addr, info_list->ai_addrlen); } +QuicSocketAddress LookupAddress(int address_family_for_lookup, + const QuicServerId& server_id) { + return LookupAddress(address_family_for_lookup, + std::string(server_id.GetHostWithoutIpv6Brackets()), + absl::StrCat(server_id.port())); +} + } // namespace quic::tools
diff --git a/quiche/quic/tools/quic_name_lookup.h b/quiche/quic/tools/quic_name_lookup.h index 99a69b1..d9fd8e8 100644 --- a/quiche/quic/tools/quic_name_lookup.h +++ b/quiche/quic/tools/quic_name_lookup.h
@@ -9,15 +9,27 @@ #include "quiche/quic/platform/api/quic_socket_address.h" -namespace quic::tools { +namespace quic { + +class QuicServerId; + +namespace tools { quic::QuicSocketAddress LookupAddress(int address_family_for_lookup, std::string host, std::string port); +quic::QuicSocketAddress LookupAddress(int address_family_for_lookup, + const QuicServerId& server_id); + inline QuicSocketAddress LookupAddress(std::string host, std::string port) { return LookupAddress(0, host, port); } -} // namespace quic::tools +inline QuicSocketAddress LookupAddress(const QuicServerId& server_id) { + return LookupAddress(0, server_id); +} + +} // namespace tools +} // namespace quic #endif // QUICHE_QUIC_TOOLS_QUIC_NAME_LOOKUP_H_