diff options
author | Billy Donahue <billy.donahue@mongodb.com> | 2017-11-08 13:03:37 -0500 |
---|---|---|
committer | Billy Donahue <billy.donahue@mongodb.com> | 2017-11-15 13:02:36 -0500 |
commit | d641ef7968a26a3b84de584faff7437caef748b9 (patch) | |
tree | d960d758fcb12f23e5ff8c9fcdb813868a2ccab0 | |
parent | f3fa1f280c22e6a93b610deae892ce001b02d106 (diff) | |
download | mongo-d641ef7968a26a3b84de584faff7437caef748b9.tar.gz |
SERVER-31808 Query vector<SockAddr> from TransportLayer
-rw-r--r-- | jstests/replsets/localhost3.js | 11 | ||||
-rw-r--r-- | src/mongo/db/repl/repl_set_commands.cpp | 60 | ||||
-rw-r--r-- | src/mongo/shell/servers.js | 2 | ||||
-rw-r--r-- | src/mongo/transport/service_entry_point_test_suite.h | 4 | ||||
-rw-r--r-- | src/mongo/transport/transport_layer.h | 2 | ||||
-rw-r--r-- | src/mongo/transport/transport_layer_asio.cpp | 13 | ||||
-rw-r--r-- | src/mongo/transport/transport_layer_asio.h | 4 | ||||
-rw-r--r-- | src/mongo/transport/transport_layer_legacy.cpp | 8 | ||||
-rw-r--r-- | src/mongo/transport/transport_layer_legacy.h | 2 | ||||
-rw-r--r-- | src/mongo/transport/transport_layer_manager.cpp | 9 | ||||
-rw-r--r-- | src/mongo/transport/transport_layer_manager.h | 2 | ||||
-rw-r--r-- | src/mongo/transport/transport_layer_mock.h | 2 | ||||
-rw-r--r-- | src/mongo/util/net/listen.cpp | 59 | ||||
-rw-r--r-- | src/mongo/util/net/listen.h | 16 |
14 files changed, 117 insertions, 77 deletions
diff --git a/jstests/replsets/localhost3.js b/jstests/replsets/localhost3.js new file mode 100644 index 00000000000..66fbcf26151 --- /dev/null +++ b/jstests/replsets/localhost3.js @@ -0,0 +1,11 @@ +// Test ReplSet default initiate with localhost-only binding + +(function() { + 'use strict'; + const rt = + new ReplSetTest({name: "foo", nodes: [MongoRunner.mongoOptions({bind_ip: undefined})]}); + const primary = rt.startSet({})[0]; + const db = primary.getDB('admin'); + const resp = assert.commandWorked(db.adminCommand({replSetInitiate: undefined})); + rt.stopSet(); +})(); diff --git a/src/mongo/db/repl/repl_set_commands.cpp b/src/mongo/db/repl/repl_set_commands.cpp index 76873a1dd9b..aca660cf80c 100644 --- a/src/mongo/db/repl/repl_set_commands.cpp +++ b/src/mongo/db/repl/repl_set_commands.cpp @@ -249,46 +249,6 @@ private: } cmdReplSetGetConfig; namespace { -HostAndPort someHostAndPortForMe() { - const auto& bind_ip = serverGlobalParams.bind_ip; - const auto& bind_port = serverGlobalParams.port; - const auto& af = IPv6Enabled() ? AF_UNSPEC : AF_INET; - bool localhost_only = true; - - std::vector<std::string> addrs; - boost::split(addrs, bind_ip, boost::is_any_of(","), boost::token_compress_on); - for (const auto& addr : addrs) { - // Get all addresses associated with each named bind host. - // If we find any that are valid external identifiers, - // then go ahead and use the first one. - const auto& socks = SockAddr::createAll(addr, bind_port, af); - for (const auto& sock : socks) { - if (!sock.isLocalHost()) { - if (!sock.isDefaultRoute()) { - // Return the hostname as passed rather than the resolved address. - return HostAndPort(addr, bind_port); - } - localhost_only = false; - } - } - } - - if (localhost_only) { - // We're only binding localhost-type interfaces. - // Use one of those by name if available, - // otherwise fall back on "localhost". - return HostAndPort(addrs.size() ? addrs[0] : "localhost", bind_port); - } - - // Based on the above logic, this is only reached for --bind_ip '0.0.0.0'. - // We are listening externally, but we don't have a definite hostname. - // Ask the OS. - std::string h = getHostName(); - verify(!h.empty()); - verify(h != "localhost"); - return HostAndPort(h, serverGlobalParams.port); -} - void parseReplSetSeedList(ReplicationCoordinatorExternalState* externalState, const std::string& replSetString, std::string* setname, @@ -381,9 +341,12 @@ public: b.append("_id", name); b.append("version", 1); BSONObjBuilder members; - HostAndPort me = someHostAndPortForMe(); - members.append("0", BSON("_id" << 0 << "host" << me.toString())); - result.append("me", me.toString()); + StatusWith<HostAndPort> me = _someHostAndPortForMe(opCtx); + if (!me.isOK()) { + return appendCommandStatus(result, me.getStatus()); + } + members.append("0", BSON("_id" << 0 << "host" << me.getValue().toString())); + result.append("me", me.getValue().toString()); for (unsigned i = 0; i < seeds.size(); i++) { members.append(BSONObjBuilder::numStr(i + 1), BSON("_id" << i + 1 << "host" << seeds[i].toString())); @@ -406,6 +369,17 @@ public: } private: + static StatusWith<HostAndPort> _someHostAndPortForMe(OperationContext* opCtx) { + auto service = opCtx->getServiceContext(); + auto transportLayer = service->getTransportLayer(); + invariant(transportLayer != nullptr); + std::vector<HostAndPort> acceptPorts = transportLayer->getListeningPorts(); + if (acceptPorts.empty()) { + return Status(ErrorCodes::InternalError, "not listening on any ports"); + } + return acceptPorts.front(); + } + ActionSet getAuthActionSet() const override { return ActionSet{ActionType::replSetConfigure}; } diff --git a/src/mongo/shell/servers.js b/src/mongo/shell/servers.js index 19f00f5e2db..beb64a68e03 100644 --- a/src/mongo/shell/servers.js +++ b/src/mongo/shell/servers.js @@ -473,7 +473,7 @@ var MongoRunner, _startMongod, startMongoProgram, runMongoProgram, startMongoPro opts.networkMessageCompressors = jsTestOptions().networkMessageCompressors; } - if (!opts.bind_ip) { + if (!opts.hasOwnProperty('bind_ip')) { opts.bind_ip = "0.0.0.0"; } diff --git a/src/mongo/transport/service_entry_point_test_suite.h b/src/mongo/transport/service_entry_point_test_suite.h index 96461584b83..c2670139a6a 100644 --- a/src/mongo/transport/service_entry_point_test_suite.h +++ b/src/mongo/transport/service_entry_point_test_suite.h @@ -115,6 +115,10 @@ public: Status start() override; void shutdown() override; + std::vector<HostAndPort> getListeningPorts() const override { + return {}; + } + transport::MockTicket* getMockTicket(const transport::Ticket& ticket); // Mocked method hooks diff --git a/src/mongo/transport/transport_layer.h b/src/mongo/transport/transport_layer.h index 383e3bd0cd5..cc305cd0e19 100644 --- a/src/mongo/transport/transport_layer.h +++ b/src/mongo/transport/transport_layer.h @@ -158,6 +158,8 @@ public: */ virtual Status setup() = 0; + virtual std::vector<HostAndPort> getListeningPorts() const = 0; + protected: TransportLayer() = default; diff --git a/src/mongo/transport/transport_layer_asio.cpp b/src/mongo/transport/transport_layer_asio.cpp index b1dd15f57d7..4da118247d7 100644 --- a/src/mongo/transport/transport_layer_asio.cpp +++ b/src/mongo/transport/transport_layer_asio.cpp @@ -281,6 +281,19 @@ void TransportLayerASIO::shutdown() { } } +std::vector<HostAndPort> TransportLayerASIO::getListeningPorts() const { + std::vector<HostAndPort> r; + stdx::lock_guard<stdx::mutex> lk(_mutex); + if (!_running.load()) { + return r; + } + for (auto& acceptor : _acceptors) { + HostAndPort hp = endpointToHostAndPort(acceptor.local_endpoint()); + r.push_back(std::move(hp)); + } + return r; +} + const std::shared_ptr<asio::io_context>& TransportLayerASIO::getIOContext() { return _workerIOContext; } diff --git a/src/mongo/transport/transport_layer_asio.h b/src/mongo/transport/transport_layer_asio.h index 11cc43e489f..bb5433b878f 100644 --- a/src/mongo/transport/transport_layer_asio.h +++ b/src/mongo/transport/transport_layer_asio.h @@ -110,6 +110,8 @@ public: void shutdown() final; + std::vector<HostAndPort> getListeningPorts() const final; + const std::shared_ptr<asio::io_context>& getIOContext(); private: @@ -124,7 +126,7 @@ private: void _acceptConnection(GenericAcceptor& acceptor); - stdx::mutex _mutex; + mutable stdx::mutex _mutex; // There are two IO contexts that are used by TransportLayerASIO. The _workerIOContext // contains all the accepted sockets and all normal networking activity. The diff --git a/src/mongo/transport/transport_layer_legacy.cpp b/src/mongo/transport/transport_layer_legacy.cpp index 0deea151158..45ed7ab1fe1 100644 --- a/src/mongo/transport/transport_layer_legacy.cpp +++ b/src/mongo/transport/transport_layer_legacy.cpp @@ -212,6 +212,14 @@ void TransportLayerLegacy::shutdown() { } } +std::vector<HostAndPort> TransportLayerLegacy::getListeningPorts() const { + std::vector<HostAndPort> r; + for (const SockAddr& addr : _listener->getListenerAddrs()) { + r.push_back(HostAndPort(addr)); + } + return r; +} + void TransportLayerLegacy::_destroy(LegacySession& session) { if (!session.conn()->closed) { _closeConnection(session.conn()); diff --git a/src/mongo/transport/transport_layer_legacy.h b/src/mongo/transport/transport_layer_legacy.h index 47a97b6050d..24a2b7b7dce 100644 --- a/src/mongo/transport/transport_layer_legacy.h +++ b/src/mongo/transport/transport_layer_legacy.h @@ -87,6 +87,8 @@ public: void shutdown() override; + std::vector<HostAndPort> getListeningPorts() const final; + private: class LegacySession; using LegacySessionHandle = std::shared_ptr<LegacySession>; diff --git a/src/mongo/transport/transport_layer_manager.cpp b/src/mongo/transport/transport_layer_manager.cpp index 82e23e1a049..42d35d9c3d7 100644 --- a/src/mongo/transport/transport_layer_manager.cpp +++ b/src/mongo/transport/transport_layer_manager.cpp @@ -102,6 +102,15 @@ void TransportLayerManager::shutdown() { _foreach([](TransportLayer* tl) { tl->shutdown(); }); } +std::vector<HostAndPort> TransportLayerManager::getListeningPorts() const { + std::vector<HostAndPort> r; + _foreach([&r](TransportLayer* tl) { + auto hp = tl->getListeningPorts(); + r.insert(r.end(), hp.begin(), hp.end()); + }); + return r; +} + // TODO Same comment as start() Status TransportLayerManager::setup() { for (auto&& tl : _tls) { diff --git a/src/mongo/transport/transport_layer_manager.h b/src/mongo/transport/transport_layer_manager.h index 8349fc56f32..0d8d71f220f 100644 --- a/src/mongo/transport/transport_layer_manager.h +++ b/src/mongo/transport/transport_layer_manager.h @@ -75,6 +75,8 @@ public: void shutdown() override; Status setup() override; + std::vector<HostAndPort> getListeningPorts() const override; + // TODO This method is not called anymore, but may be useful to add new TransportLayers // to the manager after it's been created. Status addAndStartTransportLayer(std::unique_ptr<TransportLayer> tl); diff --git a/src/mongo/transport/transport_layer_mock.h b/src/mongo/transport/transport_layer_mock.h index fd8670818ad..c4d938a71e4 100644 --- a/src/mongo/transport/transport_layer_mock.h +++ b/src/mongo/transport/transport_layer_mock.h @@ -71,6 +71,8 @@ public: void shutdown() override; bool inShutdown() const; + std::vector<HostAndPort> getListeningPorts() const override { return {}; } + private: struct Connection { bool ended; diff --git a/src/mongo/util/net/listen.cpp b/src/mongo/util/net/listen.cpp index c53e5a2a9b9..2e5cc394f65 100644 --- a/src/mongo/util/net/listen.cpp +++ b/src/mongo/util/net/listen.cpp @@ -168,16 +168,15 @@ bool Listener::setupSockets() { checkTicketNumbers(); } -#if !defined(_WIN32) - _mine = ipToAddrs(_ip.c_str(), _port, (!serverGlobalParams.noUnixSocket && useUnixSockets())); + const bool withUnix = +#if defined(_WIN32) + false; #else - _mine = ipToAddrs(_ip.c_str(), _port, false); + !serverGlobalParams.noUnixSocket && useUnixSockets(); #endif - for (std::vector<SockAddr>::const_iterator it = _mine.begin(), end = _mine.end(); it != end; - ++it) { - const SockAddr& me = *it; + for (const SockAddr& me : ipToAddrs(_ip.c_str(), _port, withUnix)) { if (!me.isValid()) { error() << "listen(): socket is invalid."; return _setupSocketsSuccessful; @@ -234,7 +233,7 @@ bool Listener::setupSockets() { } #endif - _socks.push_back(sock); + _socks.push_back(SockRecord{me, sock}); socketGuard.Dismiss(); } @@ -250,16 +249,16 @@ void Listener::initAndListen() { } SOCKET maxfd = 0; // needed for select() - for (unsigned i = 0; i < _socks.size(); i++) { - if (::listen(_socks[i], serverGlobalParams.listenBacklog) != 0) { + for (const auto& rec : _socks) { + if (::listen(rec.sock, serverGlobalParams.listenBacklog) != 0) { error() << "listen(): listen() failed " << errnoWithDescription(); return; } - ListeningSockets::get()->add(_socks[i]); + ListeningSockets::get()->add(rec.sock); - if (_socks[i] > maxfd) { - maxfd = _socks[i]; + if (rec.sock > maxfd) { + maxfd = rec.sock; } } @@ -289,8 +288,8 @@ void Listener::initAndListen() { fd_set fds[1]; FD_ZERO(fds); - for (vector<SOCKET>::iterator it = _socks.begin(), end = _socks.end(); it != end; ++it) { - FD_SET(*it, fds); + for (const auto& rec : _socks) { + FD_SET(rec.sock, fds); } maxSelectTime.tv_sec = 0; @@ -315,11 +314,11 @@ void Listener::initAndListen() { return; } - for (vector<SOCKET>::iterator it = _socks.begin(), end = _socks.end(); it != end; ++it) { - if (!(FD_ISSET(*it, fds))) + for (const auto& rec : _socks) { + if (!(FD_ISSET(rec.sock, fds))) continue; SockAddr from; - int s = accept(*it, from.raw(), &from.addressSize); + int s = accept(rec.sock, from.raw(), &from.addressSize); if (s < 0) { int x = errno; // so no global issues if (x == EBADF) { @@ -429,13 +428,13 @@ void Listener::initAndListen() { return; } - for (unsigned i = 0; i < _socks.size(); i++) { - if (::listen(_socks[i], serverGlobalParams.listenBacklog) != 0) { + for (const auto& rec : _socks) { + if (::listen(rec.sock, serverGlobalParams.listenBacklog) != 0) { error() << "listen(): listen() failed " << errnoWithDescription(); return; } - ListeningSockets::get()->add(_socks[i]); + ListeningSockets::get()->add(rec.sock); } #ifdef MONGO_CONFIG_SSL @@ -454,7 +453,6 @@ void Listener::initAndListen() { std::vector<std::unique_ptr<EventHolder>> eventHolders; std::unique_ptr<WSAEVENT[]> events(new WSAEVENT[_socks.size()]); - // Populate events array with an event for each socket we are watching for (size_t count = 0; count < _socks.size(); ++count) { auto ev = stdx::make_unique<EventHolder>(); @@ -467,7 +465,7 @@ void Listener::initAndListen() { while (!globalInShutdownDeprecated() && !_finished.load()) { // Turn on listening for accept-ready sockets for (size_t count = 0; count < _socks.size(); ++count) { - int status = WSAEventSelect(_socks[count], events[count], FD_ACCEPT | FD_CLOSE); + int status = WSAEventSelect(_socks[count].sock, events[count], FD_ACCEPT | FD_CLOSE); if (status == SOCKET_ERROR) { const int mongo_errno = WSAGetLastError(); @@ -501,9 +499,10 @@ void Listener::initAndListen() { // Determine which socket is ready DWORD eventIndex = result - WSA_WAIT_EVENT_0; + SOCKET eventSock = _socks[eventIndex].sock; WSANETWORKEVENTS networkEvents; // Extract event details, and clear event for next pass - int status = WSAEnumNetworkEvents(_socks[eventIndex], events[eventIndex], &networkEvents); + int status = WSAEnumNetworkEvents(eventSock, events[eventIndex], &networkEvents); if (status == SOCKET_ERROR) { const int mongo_errno = WSAGetLastError(); error() << "Windows WSAEnumNetworkEvents returned " @@ -527,17 +526,17 @@ void Listener::initAndListen() { continue; } - status = WSAEventSelect(_socks[eventIndex], NULL, 0); + status = WSAEventSelect(eventSock, NULL, 0); if (status == SOCKET_ERROR) { const int mongo_errno = WSAGetLastError(); error() << "Windows WSAEventSelect returned " << errnoWithDescription(mongo_errno); continue; } - disableNonblockingMode(_socks[eventIndex]); + disableNonblockingMode(eventSock); SockAddr from; - int s = accept(_socks[eventIndex], from.raw(), &from.addressSize); + int s = accept(eventSock, from.raw(), &from.addressSize); if (s < 0) { int x = errno; // so no global issues if (x == EBADF) { @@ -652,6 +651,14 @@ void Listener::shutdown() { _finished.store(true); } +std::vector<SockAddr> Listener::getListenerAddrs() const { + std::vector<SockAddr> r; + for (const auto& rec : _socks) { + r.push_back(rec.mine); + } + return r; +} + TicketHolder Listener::globalTicketHolder(DEFAULT_MAX_CONN); AtomicInt64 Listener::globalConnectionNumber; diff --git a/src/mongo/util/net/listen.h b/src/mongo/util/net/listen.h index eb473bae009..6cb97a1acb6 100644 --- a/src/mongo/util/net/listen.h +++ b/src/mongo/util/net/listen.h @@ -66,8 +66,6 @@ public: /* spawn a thread, etc., then return */ virtual void accepted(std::unique_ptr<AbstractMessagingPort> mp) = 0; - const int _port; - /** * Allocate sockets for the listener and set _setupSocketsSuccessful to true * iff the process was successful. @@ -83,17 +81,23 @@ public: void shutdown(); + std::vector<SockAddr> getListenerAddrs() const; + private: - std::vector<SockAddr> _mine; - std::vector<SOCKET> _socks; + struct SockRecord { + SockAddr mine; + SOCKET sock; + }; + + std::vector<SockRecord> _socks; + const int _port; std::string _name; std::string _ip; bool _setupSocketsSuccessful; bool _logConnect; mutable stdx::mutex _readyMutex; // Protects _ready mutable stdx::condition_variable _readyCondition; // Used to wait for changes to _ready - // Boolean that indicates whether this Listener is ready to accept incoming network requests - bool _ready; + bool _ready; // Ready to accept incoming network requests? AtomicBool _finished{false}; ServiceContext* _ctx; |