diff options
author | Jonathan Reams <jbreams@mongodb.com> | 2017-06-20 11:03:42 -0400 |
---|---|---|
committer | Jonathan Reams <jbreams@mongodb.com> | 2017-06-26 16:24:09 -0400 |
commit | e8157bfbed3e86ed24eaffa84038500425c2ee49 (patch) | |
tree | 98090ed73bb3e1671346a534d5104bea83808da0 /src/mongo | |
parent | 13d540f45bc84aaf925197eb3d4803262bc0a51c (diff) | |
download | mongo-e8157bfbed3e86ed24eaffa84038500425c2ee49.tar.gz |
SERVER-29165 Don't create RestrictionEnvironment in TransportLayer
Diffstat (limited to 'src/mongo')
27 files changed, 109 insertions, 50 deletions
diff --git a/src/mongo/client/dbclient.cpp b/src/mongo/client/dbclient.cpp index 4732658795c..efeab45e926 100644 --- a/src/mongo/client/dbclient.cpp +++ b/src/mongo/client/dbclient.cpp @@ -845,7 +845,9 @@ Status DBClientConnection::connectSocketOnly(const HostAndPort& serverAddress) { _failed = true; // We need to construct a SockAddr so we can resolve the address. - SockAddr osAddr{serverAddress.host().c_str(), serverAddress.port()}; + SockAddr osAddr{serverAddress.host().c_str(), + serverAddress.port(), + static_cast<sa_family_t>(IPv6Enabled() ? AF_UNSPEC : AF_INET)}; if (!osAddr.isValid()) { return Status(ErrorCodes::InvalidOptions, diff --git a/src/mongo/client/dbclient_rs_test.cpp b/src/mongo/client/dbclient_rs_test.cpp index 15bc9f24a58..b90b4fe75ee 100644 --- a/src/mongo/client/dbclient_rs_test.cpp +++ b/src/mongo/client/dbclient_rs_test.cpp @@ -31,6 +31,8 @@ * the DBClientReplicaSet talks to, so the tests only covers the client side logic. */ +#include "mongo/platform/basic.h" + #include <map> #include <memory> #include <string> diff --git a/src/mongo/db/auth/authz_session_external_state.cpp b/src/mongo/db/auth/authz_session_external_state.cpp index c0dceb9617b..edc3a589d88 100644 --- a/src/mongo/db/auth/authz_session_external_state.cpp +++ b/src/mongo/db/auth/authz_session_external_state.cpp @@ -26,6 +26,8 @@ * it in the license file. */ +#include "mongo/platform/basic.h" + #include "mongo/db/auth/authz_session_external_state.h" #include "mongo/base/status.h" diff --git a/src/mongo/db/auth/restriction.cpp b/src/mongo/db/auth/restriction.cpp index a158f58ede5..a7d55b8ed9e 100644 --- a/src/mongo/db/auth/restriction.cpp +++ b/src/mongo/db/auth/restriction.cpp @@ -26,6 +26,8 @@ * it in the license file. */ +#include "mongo/platform/basic.h" + #include "mongo/db/auth/restriction.h" namespace mongo { diff --git a/src/mongo/db/auth/restriction_environment.cpp b/src/mongo/db/auth/restriction_environment.cpp index 9c07f61db0c..20ddc8f821c 100644 --- a/src/mongo/db/auth/restriction_environment.cpp +++ b/src/mongo/db/auth/restriction_environment.cpp @@ -26,6 +26,8 @@ * it in the license file. */ +#include "mongo/platform/basic.h" + #include "mongo/db/auth/restriction_environment.h" #include "mongo/transport/session.h" diff --git a/src/mongo/db/cursor_manager.cpp b/src/mongo/db/cursor_manager.cpp index a2e9687f5b1..de1b1f0d56e 100644 --- a/src/mongo/db/cursor_manager.cpp +++ b/src/mongo/db/cursor_manager.cpp @@ -26,6 +26,8 @@ * it in the license file. */ +#include "mongo/platform/basic.h" + #include "mongo/db/cursor_manager.h" #include "mongo/base/data_cursor.h" diff --git a/src/mongo/dbtests/mock/mock_conn_registry.cpp b/src/mongo/dbtests/mock/mock_conn_registry.cpp index 61388e337f7..29fd5e0be9b 100644 --- a/src/mongo/dbtests/mock/mock_conn_registry.cpp +++ b/src/mongo/dbtests/mock/mock_conn_registry.cpp @@ -26,6 +26,8 @@ * then also delete it in the license file. */ +#include "mongo/platform/basic.h" + #include "mongo/dbtests/mock/mock_conn_registry.h" #include "mongo/base/init.h" diff --git a/src/mongo/dbtests/mock/mock_dbclient_connection.cpp b/src/mongo/dbtests/mock/mock_dbclient_connection.cpp index 9e7f4467964..b69409b017a 100644 --- a/src/mongo/dbtests/mock/mock_dbclient_connection.cpp +++ b/src/mongo/dbtests/mock/mock_dbclient_connection.cpp @@ -25,6 +25,8 @@ * then also delete it in the license file. */ +#include "mongo/platform/basic.h" + #include "mongo/dbtests/mock/mock_dbclient_connection.h" #include "mongo/dbtests/mock/mock_dbclient_cursor.h" diff --git a/src/mongo/dbtests/mock/mock_dbclient_cursor.cpp b/src/mongo/dbtests/mock/mock_dbclient_cursor.cpp index 4105b866b02..0138e13822b 100644 --- a/src/mongo/dbtests/mock/mock_dbclient_cursor.cpp +++ b/src/mongo/dbtests/mock/mock_dbclient_cursor.cpp @@ -27,6 +27,8 @@ * then also delete it in the license file. */ +#include "mongo/platform/basic.h" + #include "mongo/dbtests/mock/mock_dbclient_cursor.h" namespace mongo { diff --git a/src/mongo/dbtests/mock/mock_replica_set.cpp b/src/mongo/dbtests/mock/mock_replica_set.cpp index 77035a0f8f0..c2c098b4211 100644 --- a/src/mongo/dbtests/mock/mock_replica_set.cpp +++ b/src/mongo/dbtests/mock/mock_replica_set.cpp @@ -25,6 +25,8 @@ * then also delete it in the license file. */ +#include "mongo/platform/basic.h" + #include "mongo/dbtests/mock/mock_replica_set.h" #include "mongo/db/repl/member_state.h" diff --git a/src/mongo/executor/network_interface_factory.cpp b/src/mongo/executor/network_interface_factory.cpp index 2dc7d3f5845..48b4e7a6546 100644 --- a/src/mongo/executor/network_interface_factory.cpp +++ b/src/mongo/executor/network_interface_factory.cpp @@ -26,6 +26,8 @@ * it in the license file. */ +#include "mongo/platform/basic.h" + #include "mongo/executor/network_interface_factory.h" #include "mongo/base/init.h" diff --git a/src/mongo/s/client/shard_connection_test.cpp b/src/mongo/s/client/shard_connection_test.cpp index 1074148f90e..b2fb37be9c4 100644 --- a/src/mongo/s/client/shard_connection_test.cpp +++ b/src/mongo/s/client/shard_connection_test.cpp @@ -25,6 +25,8 @@ * then also delete it in the license file. */ +#include "mongo/platform/basic.h" + #include <cstdint> #include <vector> diff --git a/src/mongo/s/mongos_options_init.cpp b/src/mongo/s/mongos_options_init.cpp index 678785e4f88..681e7469679 100644 --- a/src/mongo/s/mongos_options_init.cpp +++ b/src/mongo/s/mongos_options_init.cpp @@ -26,6 +26,8 @@ * then also delete it in the license file. */ +#include "mongo/platform/basic.h" + #include "mongo/s/mongos_options.h" #include <iostream> diff --git a/src/mongo/transport/SConscript b/src/mongo/transport/SConscript index c8b8af833d8..8da74dcae3b 100644 --- a/src/mongo/transport/SConscript +++ b/src/mongo/transport/SConscript @@ -85,6 +85,7 @@ env.Library( 'service_state_machine.cpp', ], LIBDEPS=[ + '$BUILD_DIR/mongo/db/auth/authentication_restriction', "$BUILD_DIR/mongo/db/service_context", '$BUILD_DIR/mongo/db/stats/counters', "$BUILD_DIR/mongo/util/processinfo", diff --git a/src/mongo/transport/asio_utils.h b/src/mongo/transport/asio_utils.h index eb706f8488c..c06375da31f 100644 --- a/src/mongo/transport/asio_utils.h +++ b/src/mongo/transport/asio_utils.h @@ -46,7 +46,7 @@ inline SockAddr endpointToSockAddr(const asio::generic::stream_protocol::endpoin // Utility function to turn an ASIO endpoint into a mongo HostAndPort inline HostAndPort endpointToHostAndPort(const asio::generic::stream_protocol::endpoint& endPoint) { - return HostAndPort(endpointToSockAddr(endPoint).toString(true)); + return HostAndPort(endpointToSockAddr(endPoint)); } inline Status errorCodeToStatus(const std::error_code& ec) { diff --git a/src/mongo/transport/service_entry_point_impl.cpp b/src/mongo/transport/service_entry_point_impl.cpp index c802e0a8471..2e3ea90eb34 100644 --- a/src/mongo/transport/service_entry_point_impl.cpp +++ b/src/mongo/transport/service_entry_point_impl.cpp @@ -34,6 +34,7 @@ #include <vector> +#include "mongo/db/auth/restriction_environment.h" #include "mongo/transport/service_entry_point_utils.h" #include "mongo/transport/service_state_machine.h" #include "mongo/transport/session.h" @@ -43,8 +44,17 @@ namespace mongo { void ServiceEntryPointImpl::startSession(transport::SessionHandle session) { + // Setup the restriction environment on the Session, if the Session has local/remote Sockaddrs + const auto& remoteAddr = session->remote().sockAddr(); + const auto& localAddr = session->local().sockAddr(); + invariant(remoteAddr && localAddr); + auto restrictionEnvironment = + stdx::make_unique<RestrictionEnvironment>(*localAddr, *remoteAddr); + RestrictionEnvironment::set(session, std::move(restrictionEnvironment)); + // Pass ownership of the transport::SessionHandle into our worker thread. When this // thread exits, the session will end. + // launchServiceWorkerThread([ this, session = std::move(session) ]() mutable { _nWorkers.addAndFetch(1); const auto guard = MakeGuard([this] { _nWorkers.subtractAndFetch(1); }); diff --git a/src/mongo/transport/transport_layer_legacy.cpp b/src/mongo/transport/transport_layer_legacy.cpp index 962b39425e4..843d30cc7e2 100644 --- a/src/mongo/transport/transport_layer_legacy.cpp +++ b/src/mongo/transport/transport_layer_legacy.cpp @@ -38,7 +38,6 @@ #include "mongo/base/checked_cast.h" #include "mongo/config.h" -#include "mongo/db/auth/restriction_environment.h" #include "mongo/db/service_context.h" #include "mongo/db/stats/counters.h" #include "mongo/stdx/functional.h" @@ -89,8 +88,8 @@ std::shared_ptr<TransportLayerLegacy::LegacySession> TransportLayerLegacy::Legac TransportLayerLegacy::LegacySession::LegacySession(std::unique_ptr<AbstractMessagingPort> amp, TransportLayerLegacy* tl) - : _remote(amp->remote()), - _local(amp->localAddr().toString(true)), + : _remote(amp->remoteAddr()), + _local(amp->localAddr()), _tl(tl), _tags(kEmptyTagMask), _connection(stdx::make_unique<Connection>(std::move(amp))) {} @@ -328,11 +327,8 @@ void TransportLayerLegacy::_handleNewConnection(std::unique_ptr<AbstractMessagin } amp->setLogLevel(logger::LogSeverity::Debug(1)); - auto restrictionEnvironment = - stdx::make_unique<RestrictionEnvironment>(amp->remoteAddr(), amp->localAddr()); - auto session = LegacySession::create(std::move(amp), this); - RestrictionEnvironment::set(session, std::move(restrictionEnvironment)); + auto session = LegacySession::create(std::move(amp), this); stdx::list<std::weak_ptr<LegacySession>> list; auto it = list.emplace(list.begin(), session); diff --git a/src/mongo/transport/transport_layer_legacy_test.cpp b/src/mongo/transport/transport_layer_legacy_test.cpp index f442b231e9a..103ad622d2b 100644 --- a/src/mongo/transport/transport_layer_legacy_test.cpp +++ b/src/mongo/transport/transport_layer_legacy_test.cpp @@ -79,7 +79,7 @@ TEST(TransportLayerLegacy, endSessionsDoesntDoubleClose) { stdx::thread thr{[&] { Socket s; - SockAddr sa{"localhost", 27017}; + SockAddr sa{"localhost", 27017, AF_INET}; s.connect(sa); stdx::unique_lock<stdx::mutex> lk(mutex); diff --git a/src/mongo/util/net/SConscript b/src/mongo/util/net/SConscript index 8d79bbd06d3..792ee8bd9b6 100644 --- a/src/mongo/util/net/SConscript +++ b/src/mongo/util/net/SConscript @@ -8,6 +8,7 @@ env.Library( target='hostandport', source=[ 'hostandport.cpp', + 'sockaddr.cpp', ], LIBDEPS=[ '$BUILD_DIR/mongo/base', @@ -63,7 +64,6 @@ networkEnv.Library( "message_port_startup_param.cpp", "op_msg.cpp", "sock.cpp", - "sockaddr.cpp", 'socket_exception.cpp', "socket_poll.cpp", "ssl_expiration.cpp", diff --git a/src/mongo/util/net/asio_message_port.cpp b/src/mongo/util/net/asio_message_port.cpp index 19413c53435..f12be672592 100644 --- a/src/mongo/util/net/asio_message_port.cpp +++ b/src/mongo/util/net/asio_message_port.cpp @@ -482,7 +482,7 @@ HostAndPort ASIOMessagingPort::remote() const { } SockAddr ASIOMessagingPort::remoteAddr() const { - return SockAddr(_remote.host(), _remote.port()); + return SockAddr(_remote.host(), _remote.port(), AF_UNSPEC); } SockAddr ASIOMessagingPort::localAddr() const { @@ -493,14 +493,14 @@ SockAddr ASIOMessagingPort::localAddr() const { asio::ip::tcp::endpoint tcpEP; tcpEP.resize(ep.size()); memcpy(tcpEP.data(), ep.data(), ep.size()); - return SockAddr(tcpEP.address().to_string(), tcpEP.port()); + return SockAddr(tcpEP.address().to_string(), tcpEP.port(), ep.protocol().family()); } #ifndef _WIN32 case AF_UNIX: { asio::local::stream_protocol::endpoint localEP; localEP.resize(ep.size()); memcpy(localEP.data(), ep.data(), ep.size()); - return SockAddr(localEP.path(), 0); + return SockAddr(localEP.path(), 0, AF_UNIX); } #endif // _WIN32 default: { MONGO_UNREACHABLE; } diff --git a/src/mongo/util/net/hostandport.cpp b/src/mongo/util/net/hostandport.cpp index ad94315e2f7..f4904208830 100644 --- a/src/mongo/util/net/hostandport.cpp +++ b/src/mongo/util/net/hostandport.cpp @@ -59,6 +59,10 @@ HostAndPort::HostAndPort(StringData text) { HostAndPort::HostAndPort(const std::string& h, int p) : _host(h), _port(p) {} +HostAndPort::HostAndPort(SockAddr addr) : _addr(std::move(addr)) { + uassertStatusOK(initialize(_addr->toString(true))); +} + bool HostAndPort::operator<(const HostAndPort& r) const { const int cmp = host().compare(r.host()); if (cmp) diff --git a/src/mongo/util/net/hostandport.h b/src/mongo/util/net/hostandport.h index 74f9fa578a1..540f57f3b46 100644 --- a/src/mongo/util/net/hostandport.h +++ b/src/mongo/util/net/hostandport.h @@ -30,8 +30,11 @@ #include <iosfwd> #include <string> +#include <boost/optional.hpp> + #include "mongo/bson/util/builder.h" #include "mongo/platform/hash_namespace.h" +#include "mongo/util/net/sockaddr.h" namespace mongo { @@ -75,6 +78,14 @@ struct HostAndPort { HostAndPort(const std::string& h, int p); /** + * Constructs a HostAndPort from a SockAddr + * + * Used by the TransportLayer to convert raw socket addresses into HostAndPorts to be + * accessed via tranport::Session + */ + explicit HostAndPort(SockAddr addr); + + /** * (Re-)initializes this HostAndPort by parsing "s". Returns * Status::OK on success. The state of this HostAndPort is unspecified * after initialize() returns a non-OK status, though it is safe to @@ -116,6 +127,14 @@ struct HostAndPort { */ bool empty() const; + /** + * Returns the SockAddr representation of this address, if available + */ + const boost::optional<SockAddr>& sockAddr() const& { + return _addr; + } + void sockAddr() && = delete; + const std::string& host() const { return _host; } @@ -126,6 +145,7 @@ struct HostAndPort { } private: + boost::optional<SockAddr> _addr; std::string _host; int _port; // -1 indicates unspecified }; diff --git a/src/mongo/util/net/listen.cpp b/src/mongo/util/net/listen.cpp index 7be61a420ee..6e446f14ee1 100644 --- a/src/mongo/util/net/listen.cpp +++ b/src/mongo/util/net/listen.cpp @@ -96,13 +96,13 @@ using std::vector; vector<SockAddr> ipToAddrs(const char* ips, int port, bool useUnixSockets) { vector<SockAddr> out; if (*ips == '\0') { - out.push_back(SockAddr("127.0.0.1", port)); // IPv4 localhost + out.push_back(SockAddr("127.0.0.1", port, AF_INET)); // IPv4 localhost if (IPv6Enabled()) - out.push_back(SockAddr("::1", port)); // IPv6 localhost + out.push_back(SockAddr("::1", port, AF_INET6)); // IPv6 localhost #ifndef _WIN32 if (useUnixSockets) - out.push_back(SockAddr(makeUnixSockPath(port), port)); // Unix socket + out.push_back(SockAddr(makeUnixSockPath(port), port, AF_UNIX)); // Unix socket #endif return out; } @@ -118,13 +118,13 @@ vector<SockAddr> ipToAddrs(const char* ips, int port, bool useUnixSockets) { ips = ""; } - SockAddr sa(ip.c_str(), port); + SockAddr sa(ip.c_str(), port, IPv6Enabled() ? AF_UNSPEC : AF_INET); out.push_back(sa); #ifndef _WIN32 if (sa.isValid() && useUnixSockets && (sa.getAddr() == "127.0.0.1" || sa.getAddr() == "0.0.0.0")) // only IPv4 - out.push_back(SockAddr(makeUnixSockPath(port), port)); + out.push_back(SockAddr(makeUnixSockPath(port), port, AF_INET)); #endif } return out; diff --git a/src/mongo/util/net/sock.cpp b/src/mongo/util/net/sock.cpp index 1efc692229b..f0fc3cfde79 100644 --- a/src/mongo/util/net/sock.cpp +++ b/src/mongo/util/net/sock.cpp @@ -194,15 +194,6 @@ void disableNagle(int sock) { #endif -string getAddrInfoStrError(int code) { -#if !defined(_WIN32) - return gai_strerror(code); -#else - /* gai_strerrorA is not threadsafe on windows. don't use it. */ - return errnoWithDescription(code); -#endif -} - // --- SockAddr string makeUnixSockPath(int port) { @@ -213,7 +204,7 @@ string makeUnixSockPath(int port) { // If an ip address is passed in, just return that. If a hostname is passed // in, look up its ip and return that. Returns "" on failure. string hostbyname(const char* hostname) { - SockAddr sockAddr(hostname, 0); + SockAddr sockAddr(hostname, 0, IPv6Enabled() ? AF_UNSPEC : AF_INET); if (!sockAddr.isValid() || sockAddr.getAddr() == "0.0.0.0") return ""; else diff --git a/src/mongo/util/net/sock.h b/src/mongo/util/net/sock.h index 0ba5b20b9a3..18fba961c6d 100644 --- a/src/mongo/util/net/sock.h +++ b/src/mongo/util/net/sock.h @@ -68,13 +68,8 @@ struct SSLPeerInfo; extern const int portSendFlags; extern const int portRecvFlags; -const int SOCK_FAMILY_UNKNOWN_ERROR = 13078; - void disableNagle(int sock); -// Generate a string representation for getaddrinfo return codes -std::string getAddrInfoStrError(int code); - #if !defined(_WIN32) inline void closesocket(int s) { diff --git a/src/mongo/util/net/sockaddr.cpp b/src/mongo/util/net/sockaddr.cpp index f9111744b7e..167b5664c32 100644 --- a/src/mongo/util/net/sockaddr.cpp +++ b/src/mongo/util/net/sockaddr.cpp @@ -47,10 +47,22 @@ #endif #include "mongo/bson/util/builder.h" +#include "mongo/util/itoa.h" #include "mongo/util/log.h" -#include "mongo/util/net/sock.h" namespace mongo { +namespace { +constexpr int SOCK_FAMILY_UNKNOWN_ERROR = 13078; +} // namespace + +std::string getAddrInfoStrError(int code) { +#if !defined(_WIN32) + return gai_strerror(code); +#else + /* gai_strerrorA is not threadsafe on windows. don't use it. */ + return errnoWithDescription(code); +#endif +} SockAddr::SockAddr() { addressSize = sizeof(sa); @@ -68,21 +80,21 @@ SockAddr::SockAddr(int sourcePort) { _isValid = true; } -SockAddr::SockAddr(const char* _iporhost, int port) : _hostOrIp(_iporhost) { - std::string target = _iporhost; +SockAddr::SockAddr(StringData target, int port, sa_family_t familyHint) + : _hostOrIp(target.toString()) { if (target == "localhost") { target = "127.0.0.1"; } - if (mongoutils::str::contains(target, '/')) { + if (mongoutils::str::contains(_hostOrIp, '/')) { #ifdef _WIN32 uassert(13080, "no unix socket support on windows", false); #endif uassert(13079, "path to unix socket too long", - target.size() < sizeof(as<sockaddr_un>().sun_path)); + _hostOrIp.size() < sizeof(as<sockaddr_un>().sun_path)); as<sockaddr_un>().sun_family = AF_UNIX; - strcpy(as<sockaddr_un>().sun_path, target.c_str()); + strcpy(as<sockaddr_un>().sun_path, _hostOrIp.c_str()); addressSize = sizeof(sockaddr_un); _isValid = true; return; @@ -95,11 +107,10 @@ SockAddr::SockAddr(const char* _iporhost, int port) : _hostOrIp(_iporhost) { // hints.ai_flags = AI_ADDRCONFIG; // This is often recommended but don't do it. // SERVER-1579 hints.ai_flags |= AI_NUMERICHOST; // first pass tries w/o DNS lookup - hints.ai_family = (IPv6Enabled() ? AF_UNSPEC : AF_INET); + hints.ai_family = familyHint; - StringBuilder ss; - ss << port; - int ret = getaddrinfo(target.c_str(), ss.str().c_str(), &hints, &addrs); + ItoA portStr(port); + int ret = getaddrinfo(_hostOrIp.c_str(), StringData(portStr).rawData(), &hints, &addrs); // old C compilers on IPv6-capable hosts return EAI_NODATA error #ifdef EAI_NODATA @@ -110,14 +121,14 @@ SockAddr::SockAddr(const char* _iporhost, int port) : _hostOrIp(_iporhost) { if ((ret == EAI_NONAME || nodata)) { // iporhost isn't an IP address, allow DNS lookup hints.ai_flags &= ~AI_NUMERICHOST; - ret = getaddrinfo(target.c_str(), ss.str().c_str(), &hints, &addrs); + ret = getaddrinfo(_hostOrIp.c_str(), StringData(portStr).rawData(), &hints, &addrs); } if (ret) { // we were unsuccessful if (target != "0.0.0.0") { // don't log if this as it is a // CRT construction and log() may not work yet. - log() << "getaddrinfo(\"" << target << "\") failed: " << getAddrInfoStrError(ret); + log() << "getaddrinfo(\"" << _hostOrIp << "\") failed: " << getAddrInfoStrError(ret); _isValid = false; return; } diff --git a/src/mongo/util/net/sockaddr.h b/src/mongo/util/net/sockaddr.h index 0f32c48846d..1475d98be1c 100644 --- a/src/mongo/util/net/sockaddr.h +++ b/src/mongo/util/net/sockaddr.h @@ -43,6 +43,8 @@ #endif // not _WIN32 +#include "mongo/base/string_data.h" + namespace mongo { #if defined(_WIN32) @@ -58,16 +60,19 @@ struct sockaddr_un { #endif // _WIN32 +// Generate a string representation for getaddrinfo return codes +std::string getAddrInfoStrError(int code); + /** * Wrapper around os representation of network address. */ struct SockAddr { SockAddr(); + explicit SockAddr(int sourcePort); /* listener side */ - SockAddr( - const char* ip, - int port); /* EndPoint (remote) side, or if you want to specify which interface locally */ - SockAddr(const std::string& ip, int port) : SockAddr(ip.c_str(), port) {} + + explicit SockAddr(StringData ip, int port, sa_family_t familyHint); + explicit SockAddr(struct sockaddr_storage& other, socklen_t size); template <typename T> |