diff options
author | Jonathan Reams <jbreams@mongodb.com> | 2017-06-26 16:41:35 -0400 |
---|---|---|
committer | Jonathan Reams <jbreams@mongodb.com> | 2017-06-26 16:41:35 -0400 |
commit | f96a7014dc38fc6d28e3e997d13a818c271768e8 (patch) | |
tree | 3357ece5a4d6ba574d8c50f861f099232301925d | |
parent | e8157bfbed3e86ed24eaffa84038500425c2ee49 (diff) | |
download | mongo-f96a7014dc38fc6d28e3e997d13a818c271768e8.tar.gz |
Revert "SERVER-29165 Don't create RestrictionEnvironment in TransportLayer"
This reverts commit e8157bfbed3e86ed24eaffa84038500425c2ee49.
27 files changed, 50 insertions, 109 deletions
diff --git a/src/mongo/client/dbclient.cpp b/src/mongo/client/dbclient.cpp index efeab45e926..4732658795c 100644 --- a/src/mongo/client/dbclient.cpp +++ b/src/mongo/client/dbclient.cpp @@ -845,9 +845,7 @@ 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(), - static_cast<sa_family_t>(IPv6Enabled() ? AF_UNSPEC : AF_INET)}; + SockAddr osAddr{serverAddress.host().c_str(), serverAddress.port()}; 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 b90b4fe75ee..15bc9f24a58 100644 --- a/src/mongo/client/dbclient_rs_test.cpp +++ b/src/mongo/client/dbclient_rs_test.cpp @@ -31,8 +31,6 @@ * 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 edc3a589d88..c0dceb9617b 100644 --- a/src/mongo/db/auth/authz_session_external_state.cpp +++ b/src/mongo/db/auth/authz_session_external_state.cpp @@ -26,8 +26,6 @@ * 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 a7d55b8ed9e..a158f58ede5 100644 --- a/src/mongo/db/auth/restriction.cpp +++ b/src/mongo/db/auth/restriction.cpp @@ -26,8 +26,6 @@ * 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 20ddc8f821c..9c07f61db0c 100644 --- a/src/mongo/db/auth/restriction_environment.cpp +++ b/src/mongo/db/auth/restriction_environment.cpp @@ -26,8 +26,6 @@ * 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 de1b1f0d56e..a2e9687f5b1 100644 --- a/src/mongo/db/cursor_manager.cpp +++ b/src/mongo/db/cursor_manager.cpp @@ -26,8 +26,6 @@ * 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 29fd5e0be9b..61388e337f7 100644 --- a/src/mongo/dbtests/mock/mock_conn_registry.cpp +++ b/src/mongo/dbtests/mock/mock_conn_registry.cpp @@ -26,8 +26,6 @@ * 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 b69409b017a..9e7f4467964 100644 --- a/src/mongo/dbtests/mock/mock_dbclient_connection.cpp +++ b/src/mongo/dbtests/mock/mock_dbclient_connection.cpp @@ -25,8 +25,6 @@ * 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 0138e13822b..4105b866b02 100644 --- a/src/mongo/dbtests/mock/mock_dbclient_cursor.cpp +++ b/src/mongo/dbtests/mock/mock_dbclient_cursor.cpp @@ -27,8 +27,6 @@ * 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 c2c098b4211..77035a0f8f0 100644 --- a/src/mongo/dbtests/mock/mock_replica_set.cpp +++ b/src/mongo/dbtests/mock/mock_replica_set.cpp @@ -25,8 +25,6 @@ * 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 48b4e7a6546..2dc7d3f5845 100644 --- a/src/mongo/executor/network_interface_factory.cpp +++ b/src/mongo/executor/network_interface_factory.cpp @@ -26,8 +26,6 @@ * 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 b2fb37be9c4..1074148f90e 100644 --- a/src/mongo/s/client/shard_connection_test.cpp +++ b/src/mongo/s/client/shard_connection_test.cpp @@ -25,8 +25,6 @@ * 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 681e7469679..678785e4f88 100644 --- a/src/mongo/s/mongos_options_init.cpp +++ b/src/mongo/s/mongos_options_init.cpp @@ -26,8 +26,6 @@ * 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 8da74dcae3b..c8b8af833d8 100644 --- a/src/mongo/transport/SConscript +++ b/src/mongo/transport/SConscript @@ -85,7 +85,6 @@ 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 c06375da31f..eb706f8488c 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)); + return HostAndPort(endpointToSockAddr(endPoint).toString(true)); } 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 2e3ea90eb34..c802e0a8471 100644 --- a/src/mongo/transport/service_entry_point_impl.cpp +++ b/src/mongo/transport/service_entry_point_impl.cpp @@ -34,7 +34,6 @@ #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" @@ -44,17 +43,8 @@ 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 843d30cc7e2..962b39425e4 100644 --- a/src/mongo/transport/transport_layer_legacy.cpp +++ b/src/mongo/transport/transport_layer_legacy.cpp @@ -38,6 +38,7 @@ #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" @@ -88,8 +89,8 @@ std::shared_ptr<TransportLayerLegacy::LegacySession> TransportLayerLegacy::Legac TransportLayerLegacy::LegacySession::LegacySession(std::unique_ptr<AbstractMessagingPort> amp, TransportLayerLegacy* tl) - : _remote(amp->remoteAddr()), - _local(amp->localAddr()), + : _remote(amp->remote()), + _local(amp->localAddr().toString(true)), _tl(tl), _tags(kEmptyTagMask), _connection(stdx::make_unique<Connection>(std::move(amp))) {} @@ -327,8 +328,11 @@ 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)); + 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 103ad622d2b..f442b231e9a 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, AF_INET}; + SockAddr sa{"localhost", 27017}; 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 792ee8bd9b6..8d79bbd06d3 100644 --- a/src/mongo/util/net/SConscript +++ b/src/mongo/util/net/SConscript @@ -8,7 +8,6 @@ env.Library( target='hostandport', source=[ 'hostandport.cpp', - 'sockaddr.cpp', ], LIBDEPS=[ '$BUILD_DIR/mongo/base', @@ -64,6 +63,7 @@ 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 f12be672592..19413c53435 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(), AF_UNSPEC); + return SockAddr(_remote.host(), _remote.port()); } 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(), ep.protocol().family()); + return SockAddr(tcpEP.address().to_string(), tcpEP.port()); } #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, AF_UNIX); + return SockAddr(localEP.path(), 0); } #endif // _WIN32 default: { MONGO_UNREACHABLE; } diff --git a/src/mongo/util/net/hostandport.cpp b/src/mongo/util/net/hostandport.cpp index f4904208830..ad94315e2f7 100644 --- a/src/mongo/util/net/hostandport.cpp +++ b/src/mongo/util/net/hostandport.cpp @@ -59,10 +59,6 @@ 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 540f57f3b46..74f9fa578a1 100644 --- a/src/mongo/util/net/hostandport.h +++ b/src/mongo/util/net/hostandport.h @@ -30,11 +30,8 @@ #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 { @@ -78,14 +75,6 @@ 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 @@ -127,14 +116,6 @@ 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; } @@ -145,7 +126,6 @@ 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 6e446f14ee1..7be61a420ee 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, AF_INET)); // IPv4 localhost + out.push_back(SockAddr("127.0.0.1", port)); // IPv4 localhost if (IPv6Enabled()) - out.push_back(SockAddr("::1", port, AF_INET6)); // IPv6 localhost + out.push_back(SockAddr("::1", port)); // IPv6 localhost #ifndef _WIN32 if (useUnixSockets) - out.push_back(SockAddr(makeUnixSockPath(port), port, AF_UNIX)); // Unix socket + out.push_back(SockAddr(makeUnixSockPath(port), port)); // 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, IPv6Enabled() ? AF_UNSPEC : AF_INET); + SockAddr sa(ip.c_str(), port); 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, AF_INET)); + out.push_back(SockAddr(makeUnixSockPath(port), port)); #endif } return out; diff --git a/src/mongo/util/net/sock.cpp b/src/mongo/util/net/sock.cpp index f0fc3cfde79..1efc692229b 100644 --- a/src/mongo/util/net/sock.cpp +++ b/src/mongo/util/net/sock.cpp @@ -194,6 +194,15 @@ 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) { @@ -204,7 +213,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, IPv6Enabled() ? AF_UNSPEC : AF_INET); + SockAddr sockAddr(hostname, 0); 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 18fba961c6d..0ba5b20b9a3 100644 --- a/src/mongo/util/net/sock.h +++ b/src/mongo/util/net/sock.h @@ -68,8 +68,13 @@ 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 167b5664c32..f9111744b7e 100644 --- a/src/mongo/util/net/sockaddr.cpp +++ b/src/mongo/util/net/sockaddr.cpp @@ -47,22 +47,10 @@ #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); @@ -80,21 +68,21 @@ SockAddr::SockAddr(int sourcePort) { _isValid = true; } -SockAddr::SockAddr(StringData target, int port, sa_family_t familyHint) - : _hostOrIp(target.toString()) { +SockAddr::SockAddr(const char* _iporhost, int port) : _hostOrIp(_iporhost) { + std::string target = _iporhost; if (target == "localhost") { target = "127.0.0.1"; } - if (mongoutils::str::contains(_hostOrIp, '/')) { + if (mongoutils::str::contains(target, '/')) { #ifdef _WIN32 uassert(13080, "no unix socket support on windows", false); #endif uassert(13079, "path to unix socket too long", - _hostOrIp.size() < sizeof(as<sockaddr_un>().sun_path)); + target.size() < sizeof(as<sockaddr_un>().sun_path)); as<sockaddr_un>().sun_family = AF_UNIX; - strcpy(as<sockaddr_un>().sun_path, _hostOrIp.c_str()); + strcpy(as<sockaddr_un>().sun_path, target.c_str()); addressSize = sizeof(sockaddr_un); _isValid = true; return; @@ -107,10 +95,11 @@ SockAddr::SockAddr(StringData target, int port, sa_family_t familyHint) // 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 = familyHint; + hints.ai_family = (IPv6Enabled() ? AF_UNSPEC : AF_INET); - ItoA portStr(port); - int ret = getaddrinfo(_hostOrIp.c_str(), StringData(portStr).rawData(), &hints, &addrs); + StringBuilder ss; + ss << port; + int ret = getaddrinfo(target.c_str(), ss.str().c_str(), &hints, &addrs); // old C compilers on IPv6-capable hosts return EAI_NODATA error #ifdef EAI_NODATA @@ -121,14 +110,14 @@ SockAddr::SockAddr(StringData target, int port, sa_family_t familyHint) if ((ret == EAI_NONAME || nodata)) { // iporhost isn't an IP address, allow DNS lookup hints.ai_flags &= ~AI_NUMERICHOST; - ret = getaddrinfo(_hostOrIp.c_str(), StringData(portStr).rawData(), &hints, &addrs); + ret = getaddrinfo(target.c_str(), ss.str().c_str(), &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(\"" << _hostOrIp << "\") failed: " << getAddrInfoStrError(ret); + log() << "getaddrinfo(\"" << target << "\") failed: " << getAddrInfoStrError(ret); _isValid = false; return; } diff --git a/src/mongo/util/net/sockaddr.h b/src/mongo/util/net/sockaddr.h index 1475d98be1c..0f32c48846d 100644 --- a/src/mongo/util/net/sockaddr.h +++ b/src/mongo/util/net/sockaddr.h @@ -43,8 +43,6 @@ #endif // not _WIN32 -#include "mongo/base/string_data.h" - namespace mongo { #if defined(_WIN32) @@ -60,19 +58,16 @@ 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 */ - - explicit SockAddr(StringData ip, int port, sa_family_t familyHint); - + 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(struct sockaddr_storage& other, socklen_t size); template <typename T> |