summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBilly Donahue <billy.donahue@mongodb.com>2017-11-08 13:03:37 -0500
committerBilly Donahue <billy.donahue@mongodb.com>2017-11-15 13:02:36 -0500
commitd641ef7968a26a3b84de584faff7437caef748b9 (patch)
treed960d758fcb12f23e5ff8c9fcdb813868a2ccab0
parentf3fa1f280c22e6a93b610deae892ce001b02d106 (diff)
downloadmongo-d641ef7968a26a3b84de584faff7437caef748b9.tar.gz
SERVER-31808 Query vector<SockAddr> from TransportLayer
-rw-r--r--jstests/replsets/localhost3.js11
-rw-r--r--src/mongo/db/repl/repl_set_commands.cpp60
-rw-r--r--src/mongo/shell/servers.js2
-rw-r--r--src/mongo/transport/service_entry_point_test_suite.h4
-rw-r--r--src/mongo/transport/transport_layer.h2
-rw-r--r--src/mongo/transport/transport_layer_asio.cpp13
-rw-r--r--src/mongo/transport/transport_layer_asio.h4
-rw-r--r--src/mongo/transport/transport_layer_legacy.cpp8
-rw-r--r--src/mongo/transport/transport_layer_legacy.h2
-rw-r--r--src/mongo/transport/transport_layer_manager.cpp9
-rw-r--r--src/mongo/transport/transport_layer_manager.h2
-rw-r--r--src/mongo/transport/transport_layer_mock.h2
-rw-r--r--src/mongo/util/net/listen.cpp59
-rw-r--r--src/mongo/util/net/listen.h16
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;