summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Reams <jbreams@mongodb.com>2016-11-29 20:01:18 -0500
committerJonathan Reams <jbreams@mongodb.com>2016-12-08 10:44:05 -0500
commitd55eb9d186f3039695a4d710116e79ad04536409 (patch)
treed7eeb820a9365d9266f926969177c05a9413e300
parente91795212e7f274db6eb66efd5bbad8f144cdf32 (diff)
downloadmongo-d55eb9d186f3039695a4d710116e79ad04536409.tar.gz
SERVER-27210 Allow shell to connect to replicasets with ssl=true in URI
-rw-r--r--jstests/ssl/repl_ssl_noca.js51
-rw-r--r--src/mongo/client/connpool.cpp21
-rw-r--r--src/mongo/client/connpool.h3
-rw-r--r--src/mongo/client/dbclient_rs.cpp19
-rw-r--r--src/mongo/client/mongo_uri.h12
-rw-r--r--src/mongo/client/mongo_uri_connect.cpp11
-rw-r--r--src/mongo/client/mongo_uri_test.cpp22
-rw-r--r--src/mongo/client/replica_set_monitor.cpp22
-rw-r--r--src/mongo/client/replica_set_monitor.h5
-rw-r--r--src/mongo/client/replica_set_monitor_internal.h3
-rw-r--r--src/mongo/client/replica_set_monitor_manager.cpp35
-rw-r--r--src/mongo/client/replica_set_monitor_manager.h4
-rw-r--r--src/mongo/client/replica_set_monitor_test.cpp18
-rw-r--r--src/mongo/client/scoped_db_conn_test.cpp49
-rw-r--r--src/mongo/util/net/ssl_manager.cpp2
15 files changed, 259 insertions, 18 deletions
diff --git a/jstests/ssl/repl_ssl_noca.js b/jstests/ssl/repl_ssl_noca.js
new file mode 100644
index 00000000000..b006136f679
--- /dev/null
+++ b/jstests/ssl/repl_ssl_noca.js
@@ -0,0 +1,51 @@
+(function() {
+ 'use strict';
+ if (_isWindows()) {
+ runProgram(
+ "certutil.exe", "-addstore", "-user", "-f", "CA", "jstests\\libs\\trusted-ca.pem");
+ }
+
+ var replTest = new ReplSetTest({
+ name: "ssltest",
+ nodes: 1,
+ nodeOptions: {
+ sslMode: "requireSSL",
+ sslPEMKeyFile: "jstests/libs/trusted-server.pem",
+ },
+ host: "localhost",
+ useHostName: false,
+ });
+
+ replTest.startSet({
+ env: {
+ SSL_CERT_FILE: 'jstests/libs/trusted-ca.pem',
+ },
+ });
+ replTest.initiate();
+
+ var nodeList = replTest.nodeList().join();
+
+ var checkShellOkay = function(url) {
+ // Should not be able to authenticate with x509.
+ // Authenticate call will return 1 on success, 0 on error.
+ var argv = ['./mongo', url, '--eval', ('db.runCommand({replSetGetStatus: 1})')];
+ if (!_isWindows()) {
+ // On Linux we override the default path to the system CA store to point to our
+ // "trusted" CA. On Windows, this CA will have been added to the user's trusted CA list
+ argv.unshift("env", "SSL_CERT_FILE=jstests/libs/trusted-ca.pem");
+ }
+ return runMongoProgram(...argv);
+ };
+
+ var noMentionSSLURL = `mongodb://${nodeList}/admin?replicaSet=${replTest.name}`;
+ jsTestLog(`Replica set url (doesn't mention SSL): ${noMentionSSLURL}`);
+ assert.neq(checkShellOkay(noMentionSSLURL), 0, "shell correctly failed to connect without SSL");
+
+ var useSSLURL = `mongodb://${nodeList}/admin?replicaSet=${replTest.name}&ssl=true`;
+ jsTestLog(`Replica set url (uses SSL): ${useSSLURL}`);
+ assert.eq(checkShellOkay(useSSLURL), 0, "successfully connected with SSL");
+
+ var disableSSLURL = `mongodb://${nodeList}/admin?replicaSet=${replTest.name}&ssl=false`;
+ jsTestLog(`Replica set url (doesnt use SSL): ${disableSSLURL}`);
+ assert.neq(checkShellOkay(disableSSLURL), 0, "shell correctly failed to connect without SSL");
+})();
diff --git a/src/mongo/client/connpool.cpp b/src/mongo/client/connpool.cpp
index 8ac32a3386b..7a960dc8d42 100644
--- a/src/mongo/client/connpool.cpp
+++ b/src/mongo/client/connpool.cpp
@@ -258,6 +258,20 @@ DBClientBase* DBConnectionPool::get(const string& host, double socketTimeout) {
return _finishCreate(host, socketTimeout, c);
}
+DBClientBase* DBConnectionPool::get(const MongoURI& uri, double socketTimeout) {
+ std::unique_ptr<DBClientBase> c(_get(uri.toString(), socketTimeout));
+ if (c) {
+ onHandedOut(c.get());
+ return c.release();
+ }
+
+ string errmsg;
+ c = std::unique_ptr<DBClientBase>(uri.connect(StringData(), errmsg, socketTimeout));
+ uassert(40356, _name + ": connect failed " + uri.toString() + " : " + errmsg, c);
+
+ return _finishCreate(uri.toString(), socketTimeout, c.release());
+}
+
int DBConnectionPool::getNumAvailableConns(const string& host, double socketTimeout) const {
stdx::lock_guard<stdx::mutex> L(_mutex);
auto it = _pools.find(PoolKey(host, socketTimeout));
@@ -467,6 +481,13 @@ ScopedDbConnection::ScopedDbConnection(const ConnectionString& host, double sock
_setSocketTimeout();
}
+ScopedDbConnection::ScopedDbConnection(const MongoURI& uri, double socketTimeout)
+ : _host(uri.toString()),
+ _conn(globalConnPool.get(uri, socketTimeout)),
+ _socketTimeout(socketTimeout) {
+ _setSocketTimeout();
+}
+
void ScopedDbConnection::done() {
if (!_conn) {
return;
diff --git a/src/mongo/client/connpool.h b/src/mongo/client/connpool.h
index 683270d0021..342bc0e2ae6 100644
--- a/src/mongo/client/connpool.h
+++ b/src/mongo/client/connpool.h
@@ -33,6 +33,7 @@
#include <stack>
#include "mongo/client/dbclientinterface.h"
+#include "mongo/client/mongo_uri.h"
#include "mongo/platform/atomic_word.h"
#include "mongo/util/background.h"
#include "mongo/util/concurrency/mutex.h"
@@ -227,6 +228,7 @@ public:
DBClientBase* get(const std::string& host, double socketTimeout = 0);
DBClientBase* get(const ConnectionString& host, double socketTimeout = 0);
+ DBClientBase* get(const MongoURI& uri, double socketTimeout = 0);
/**
* Gets the number of connections available in the pool.
@@ -344,6 +346,7 @@ public:
*/
explicit ScopedDbConnection(const std::string& host, double socketTimeout = 0);
explicit ScopedDbConnection(const ConnectionString& host, double socketTimeout = 0);
+ explicit ScopedDbConnection(const MongoURI& host, double socketTimeout = 0);
ScopedDbConnection() : _host(""), _conn(0), _socketTimeout(0) {}
diff --git a/src/mongo/client/dbclient_rs.cpp b/src/mongo/client/dbclient_rs.cpp
index 113a110e09a..219069bb9dc 100644
--- a/src/mongo/client/dbclient_rs.cpp
+++ b/src/mongo/client/dbclient_rs.cpp
@@ -147,8 +147,12 @@ DBClientReplicaSet::DBClientReplicaSet(const string& name,
_applicationName(applicationName.toString()),
_so_timeout(so_timeout),
_uri(std::move(uri)) {
- _rsm =
- ReplicaSetMonitor::createIfNeeded(name, set<HostAndPort>(servers.begin(), servers.end()));
+ if (uri.isValid()) {
+ _rsm = ReplicaSetMonitor::createIfNeeded(_uri);
+ } else {
+ _rsm = ReplicaSetMonitor::createIfNeeded(name,
+ set<HostAndPort>(servers.begin(), servers.end()));
+ }
}
DBClientReplicaSet::~DBClientReplicaSet() {
@@ -305,17 +309,24 @@ DBClientConnection* DBClientReplicaSet::checkMaster() {
_masterHost = h;
- ConnectionString connStr(_masterHost);
+ MongoURI masterUri;
+ if (!_uri.isValid())
+ masterUri = MongoURI(ConnectionString(_masterHost));
+ else
+ masterUri = _uri.cloneURIForServer(_masterHost);
string errmsg;
DBClientConnection* newConn = NULL;
+ boost::optional<double> socketTimeout;
+ if (_so_timeout > 0.0)
+ socketTimeout = _so_timeout;
try {
// Needs to perform a dynamic_cast because we need to set the replSet
// callback. We should eventually not need this after we remove the
// callback.
newConn = dynamic_cast<DBClientConnection*>(
- connStr.connect(_applicationName, errmsg, _so_timeout));
+ masterUri.connect(_applicationName, errmsg, socketTimeout));
} catch (const AssertionException& ex) {
errmsg = ex.toString();
}
diff --git a/src/mongo/client/mongo_uri.h b/src/mongo/client/mongo_uri.h
index 8a0574540c8..7b6364761d5 100644
--- a/src/mongo/client/mongo_uri.h
+++ b/src/mongo/client/mongo_uri.h
@@ -72,7 +72,9 @@ public:
static StatusWith<MongoURI> parse(const std::string& url);
- DBClientBase* connect(StringData applicationName, std::string& errmsg) const;
+ DBClientBase* connect(StringData applicationName,
+ std::string& errmsg,
+ boost::optional<double> socketTimeoutSecs = boost::none) const;
const std::string& getUser() const {
return _user;
@@ -106,6 +108,14 @@ public:
return _connectString.getServers();
}
+ // If you are trying to clone a URI (including its options/auth information) for a single
+ // server (say a member of a replica-set), you can pass in its HostAndPort information to
+ // get a new URI with the same info, except type() will be MASTER and getServers() will
+ // be the single host you pass in.
+ MongoURI cloneURIForServer(const HostAndPort& hostAndPort) const {
+ return MongoURI(ConnectionString(hostAndPort), _user, _password, _database, _options);
+ }
+
ConnectionString::ConnectionType type() const {
return _connectString.type();
}
diff --git a/src/mongo/client/mongo_uri_connect.cpp b/src/mongo/client/mongo_uri_connect.cpp
index ac2b8db65c6..ee68a2c1614 100644
--- a/src/mongo/client/mongo_uri_connect.cpp
+++ b/src/mongo/client/mongo_uri_connect.cpp
@@ -164,11 +164,11 @@ BSONObj MongoURI::_makeAuthObjFromOptions(int maxWireVersion) const {
return bob.obj();
}
-DBClientBase* MongoURI::connect(StringData applicationName, std::string& errmsg) const {
- double socketTimeoutSecs = 0.0;
-
+DBClientBase* MongoURI::connect(StringData applicationName,
+ std::string& errmsg,
+ boost::optional<double> socketTimeoutSecs) const {
OptionsMap::const_iterator it = _options.find("socketTimeoutMS");
- if (it != _options.end()) {
+ if (it != _options.end() && !socketTimeoutSecs) {
try {
socketTimeoutSecs = std::stod(it->second) / 1000;
} catch (const std::exception& e) {
@@ -177,7 +177,8 @@ DBClientBase* MongoURI::connect(StringData applicationName, std::string& errmsg)
}
}
- auto ret = _connectString.connect(applicationName, errmsg, socketTimeoutSecs, this);
+ auto ret =
+ _connectString.connect(applicationName, errmsg, socketTimeoutSecs.value_or(0.0), this);
if (!ret) {
return ret;
}
diff --git a/src/mongo/client/mongo_uri_test.cpp b/src/mongo/client/mongo_uri_test.cpp
index 05d288818d8..6a5f6c9882a 100644
--- a/src/mongo/client/mongo_uri_test.cpp
+++ b/src/mongo/client/mongo_uri_test.cpp
@@ -335,4 +335,26 @@ TEST(MongoURI, ValidButBadURIsFailToConnect) {
ASSERT_EQ(dbclient, static_cast<decltype(dbclient)>(nullptr));
}
+TEST(MongoURI, CloneURIForServer) {
+ auto sw_uri = MongoURI::parse(
+ "mongodb://localhost:27017,localhost:27018,localhost:27019/admin?replicaSet=rs1&ssl=true");
+ ASSERT_OK(sw_uri.getStatus());
+
+ auto uri = sw_uri.getValue();
+ ASSERT_EQ(uri.type(), kSet);
+ ASSERT_EQ(uri.getSetName(), "rs1");
+ ASSERT_EQ(uri.getServers().size(), static_cast<std::size_t>(3));
+
+ auto& uriOptions = uri.getOptions();
+ ASSERT_EQ(uriOptions.at("ssl"), "true");
+
+ auto clonedURI = uri.cloneURIForServer(mongo::HostAndPort{"localhost:27020"});
+
+ ASSERT_EQ(clonedURI.type(), kMaster);
+ ASSERT_TRUE(clonedURI.getSetName().empty());
+ ASSERT_EQ(clonedURI.getServers().size(), static_cast<std::size_t>(1));
+ auto& clonedURIOptions = clonedURI.getOptions();
+ ASSERT_EQ(clonedURIOptions.at("ssl"), "true");
+}
+
} // namespace
diff --git a/src/mongo/client/replica_set_monitor.cpp b/src/mongo/client/replica_set_monitor.cpp
index c64c4280424..9c1a503a5e1 100644
--- a/src/mongo/client/replica_set_monitor.cpp
+++ b/src/mongo/client/replica_set_monitor.cpp
@@ -180,6 +180,9 @@ ReplicaSetMonitor::ReplicaSetMonitor(StringData name, const std::set<HostAndPort
: _state(std::make_shared<SetState>(name, seeds)),
_executor(globalRSMonitorManager.getExecutor()) {}
+ReplicaSetMonitor::ReplicaSetMonitor(const MongoURI& uri)
+ : _state(std::make_shared<SetState>(uri)), _executor(globalRSMonitorManager.getExecutor()) {}
+
void ReplicaSetMonitor::init() {
stdx::lock_guard<stdx::mutex> lk(_mutex);
invariant(_executor);
@@ -385,6 +388,10 @@ shared_ptr<ReplicaSetMonitor> ReplicaSetMonitor::createIfNeeded(const string& na
ConnectionString::forReplicaSet(name, vector<HostAndPort>(servers.begin(), servers.end())));
}
+shared_ptr<ReplicaSetMonitor> ReplicaSetMonitor::createIfNeeded(const MongoURI& uri) {
+ return globalRSMonitorManager.getOrCreateMonitor(uri);
+}
+
shared_ptr<ReplicaSetMonitor> ReplicaSetMonitor::get(const std::string& name) {
return globalRSMonitorManager.getMonitor(name);
}
@@ -819,11 +826,18 @@ HostAndPort Refresher::_refreshUntilMatches(const ReadPreferenceSetting* criteri
StatusWith<BSONObj> isMasterReplyStatus{ErrorCodes::InternalError,
"Uninitialized variable"};
int64_t pingMicros = 0;
+ MongoURI targetURI;
+
+ if (_set->setUri.isValid()) {
+ targetURI = _set->setUri.cloneURIForServer(ns.host);
+ } else {
+ targetURI = MongoURI(ConnectionString(ns.host));
+ }
// Do not do network calls while holding a mutex
lk.unlock();
try {
- ScopedDbConnection conn(ConnectionString(ns.host), socketTimeoutSecs);
+ ScopedDbConnection conn(targetURI, socketTimeoutSecs);
bool ignoredOutParam = false;
Timer timer;
BSONObj reply;
@@ -1000,6 +1014,12 @@ SetState::SetState(StringData name, const std::set<HostAndPort>& seedNodes)
DEV checkInvariants();
}
+SetState::SetState(const MongoURI& uri)
+ : SetState(uri.getSetName(),
+ std::set<HostAndPort>(uri.getServers().begin(), uri.getServers().end())) {
+ setUri = uri;
+}
+
HostAndPort SetState::getMatchingHost(const ReadPreferenceSetting& criteria) const {
switch (criteria.pref) {
// "Prefered" read preferences are defined in terms of other preferences
diff --git a/src/mongo/client/replica_set_monitor.h b/src/mongo/client/replica_set_monitor.h
index 7b8f602cbce..93394f2386d 100644
--- a/src/mongo/client/replica_set_monitor.h
+++ b/src/mongo/client/replica_set_monitor.h
@@ -35,6 +35,7 @@
#include "mongo/base/disallow_copying.h"
#include "mongo/base/string_data.h"
+#include "mongo/client/mongo_uri.h"
#include "mongo/executor/task_executor.h"
#include "mongo/platform/atomic_word.h"
#include "mongo/stdx/functional.h"
@@ -68,6 +69,8 @@ public:
*/
ReplicaSetMonitor(StringData name, const std::set<HostAndPort>& seeds);
+ ReplicaSetMonitor(const MongoURI& uri);
+
/**
* Schedules the initial refresh task into task executor.
*/
@@ -175,6 +178,8 @@ public:
static std::shared_ptr<ReplicaSetMonitor> createIfNeeded(const std::string& name,
const std::set<HostAndPort>& servers);
+ static std::shared_ptr<ReplicaSetMonitor> createIfNeeded(const MongoURI& uri);
+
/**
* gets a cached Monitor per name. If the monitor is not found and createFromSeed is false,
* it will return none. If createFromSeed is true, it will try to look up the last known
diff --git a/src/mongo/client/replica_set_monitor_internal.h b/src/mongo/client/replica_set_monitor_internal.h
index 237401b1f41..f14080a16a7 100644
--- a/src/mongo/client/replica_set_monitor_internal.h
+++ b/src/mongo/client/replica_set_monitor_internal.h
@@ -142,6 +142,8 @@ public:
*/
SetState(StringData name, const std::set<HostAndPort>& seedNodes);
+ SetState(const MongoURI& uri);
+
bool isUsable() const;
/**
@@ -203,6 +205,7 @@ public:
int64_t latencyThresholdMicros;
mutable PseudoRandom rand; // only used for host selection to balance load
mutable int roundRobin; // used when useDeterministicHostSelection is true
+ MongoURI setUri; // URI that may have constructed this
};
struct ReplicaSetMonitor::ScanState {
diff --git a/src/mongo/client/replica_set_monitor_manager.cpp b/src/mongo/client/replica_set_monitor_manager.cpp
index 6a463dbf29e..773619086a4 100644
--- a/src/mongo/client/replica_set_monitor_manager.cpp
+++ b/src/mongo/client/replica_set_monitor_manager.cpp
@@ -34,6 +34,7 @@
#include "mongo/bson/bsonobjbuilder.h"
#include "mongo/client/connection_string.h"
+#include "mongo/client/mongo_uri.h"
#include "mongo/client/replica_set_monitor.h"
#include "mongo/executor/network_interface_factory.h"
#include "mongo/executor/network_interface_thread_pool.h"
@@ -74,11 +75,7 @@ shared_ptr<ReplicaSetMonitor> ReplicaSetMonitorManager::getMonitor(StringData se
}
}
-shared_ptr<ReplicaSetMonitor> ReplicaSetMonitorManager::getOrCreateMonitor(
- const ConnectionString& connStr) {
- invariant(connStr.type() == ConnectionString::SET);
-
- stdx::lock_guard<stdx::mutex> lk(_mutex);
+void ReplicaSetMonitorManager::_setupTaskExecutorInLock(const std::string& name) {
// do not restart taskExecutor if is in shutdown
if (!_taskExecutor && !_isShutdown) {
// construct task executor
@@ -88,10 +85,17 @@ shared_ptr<ReplicaSetMonitor> ReplicaSetMonitorManager::getOrCreateMonitor(
stdx::make_unique<NetworkInterfaceThreadPool>(netPtr), std::move(net));
LOG(1) << "Starting up task executor for monitoring replica sets in response to request to "
"monitor set: "
- << connStr.toString();
+ << redact(name);
_taskExecutor->startup();
}
+}
+shared_ptr<ReplicaSetMonitor> ReplicaSetMonitorManager::getOrCreateMonitor(
+ const ConnectionString& connStr) {
+ invariant(connStr.type() == ConnectionString::SET);
+
+ stdx::lock_guard<stdx::mutex> lk(_mutex);
+ _setupTaskExecutorInLock(connStr.toString());
auto setName = connStr.getSetName();
auto monitor = _monitors[setName].lock();
if (monitor) {
@@ -108,6 +112,25 @@ shared_ptr<ReplicaSetMonitor> ReplicaSetMonitorManager::getOrCreateMonitor(
return newMonitor;
}
+shared_ptr<ReplicaSetMonitor> ReplicaSetMonitorManager::getOrCreateMonitor(const MongoURI& uri) {
+ invariant(uri.type() == ConnectionString::SET);
+
+ stdx::lock_guard<stdx::mutex> lk(_mutex);
+ _setupTaskExecutorInLock(uri.toString());
+ const auto& setName = uri.getSetName();
+ auto monitor = _monitors[setName].lock();
+ if (monitor) {
+ return monitor;
+ }
+
+ log() << "Starting new replica set monitor for " << uri.toString();
+
+ auto newMonitor = std::make_shared<ReplicaSetMonitor>(uri);
+ _monitors[setName] = newMonitor;
+ newMonitor->init();
+ return newMonitor;
+}
+
vector<string> ReplicaSetMonitorManager::getAllSetNames() {
vector<string> allNames;
diff --git a/src/mongo/client/replica_set_monitor_manager.h b/src/mongo/client/replica_set_monitor_manager.h
index fd47856796e..2730167668f 100644
--- a/src/mongo/client/replica_set_monitor_manager.h
+++ b/src/mongo/client/replica_set_monitor_manager.h
@@ -41,6 +41,7 @@ namespace mongo {
class BSONObjBuilder;
class ConnectionString;
class ReplicaSetMonitor;
+class MongoURI;
/**
* Manages the lifetime of a set of replica set monitors.
@@ -58,6 +59,7 @@ public:
*/
std::shared_ptr<ReplicaSetMonitor> getMonitor(StringData setName);
std::shared_ptr<ReplicaSetMonitor> getOrCreateMonitor(const ConnectionString& connStr);
+ std::shared_ptr<ReplicaSetMonitor> getOrCreateMonitor(const MongoURI& uri);
/**
* Retrieves the names of all sets tracked by this manager.
@@ -101,6 +103,8 @@ private:
// Executor for monitoring replica sets.
std::unique_ptr<executor::TaskExecutor> _taskExecutor;
+ void _setupTaskExecutorInLock(const std::string& name);
+
// set to true when shutdown has been called.
bool _isShutdown{false};
};
diff --git a/src/mongo/client/replica_set_monitor_test.cpp b/src/mongo/client/replica_set_monitor_test.cpp
index 8720176b183..403e03a985a 100644
--- a/src/mongo/client/replica_set_monitor_test.cpp
+++ b/src/mongo/client/replica_set_monitor_test.cpp
@@ -77,6 +77,24 @@ TEST(ReplicaSetMonitor, InitialState) {
}
}
+TEST(ReplicaSetMonitor, InitialStateMongoURI) {
+ auto uri = MongoURI::parse("mongodb://a,b,c/?replicaSet=name");
+ ASSERT_OK(uri.getStatus());
+ SetStatePtr state = std::make_shared<SetState>(uri.getValue());
+ ASSERT_EQUALS(state->name, "name");
+ ASSERT(state->seedNodes == basicSeedsSet);
+ ASSERT(state->lastSeenMaster.empty());
+ ASSERT_EQUALS(state->nodes.size(), basicSeeds.size());
+ for (size_t i = 0; i < basicSeeds.size(); i++) {
+ Node* node = state->findNode(basicSeeds[i]);
+ ASSERT(node);
+ ASSERT_EQUALS(node->host.toString(), basicSeeds[i].toString());
+ ASSERT(!node->isUp);
+ ASSERT(!node->isMaster);
+ ASSERT(node->tags.isEmpty());
+ }
+}
+
TEST(ReplicaSetMonitor, IsMasterBadParse) {
BSONObj ismaster = BSON("hosts" << BSON_ARRAY("mongo.example:badport"));
IsMasterReply imr(HostAndPort("mongo.example:27017"), -1, ismaster);
diff --git a/src/mongo/client/scoped_db_conn_test.cpp b/src/mongo/client/scoped_db_conn_test.cpp
index cebfe48cd16..694fa8ee531 100644
--- a/src/mongo/client/scoped_db_conn_test.cpp
+++ b/src/mongo/client/scoped_db_conn_test.cpp
@@ -91,6 +91,10 @@ public:
_threads.emplace_back(&DummyServiceEntryPoint::run, this, std::move(session));
}
+ void setReplyDelay(Milliseconds delay) {
+ _replyDelay = delay;
+ }
+
private:
void run(transport::SessionHandle session) {
Message inMessage;
@@ -117,6 +121,10 @@ private:
response.header().setResponseToMsgId(inMessage.header().getId());
+ if (_replyDelay.count() > 0) {
+ log() << "Delaying response for " << _replyDelay;
+ sleepFor(_replyDelay);
+ }
if (!session->sinkMessage(response).wait().isOK()) {
return;
}
@@ -128,6 +136,7 @@ private:
virtual void commandRequestHook(const rpc::RequestInterface* request) const {}
std::vector<stdx::thread> _threads;
+ Milliseconds _replyDelay{0};
};
// TODO: Take this out and make it as a reusable class in a header file. The only
@@ -261,6 +270,10 @@ protected:
ASSERT_NOT_EQUALS(a, b);
}
+ void setReplyDelay(Milliseconds delay) {
+ _dummyServiceEntryPoint->setReplyDelay(delay);
+ }
+
/**
* Tries to grab a series of connections from the pool, perform checks on
* them, then put them back into the globalConnPool. After that, it checks these
@@ -374,6 +387,42 @@ TEST_F(DummyServerFixture, BasicScopedDbConnection) {
conn3.done();
}
+TEST_F(DummyServerFixture, ScopedDbConnectionWithTimeout) {
+ auto delay = Milliseconds{8000};
+ auto uri_sw = MongoURI::parse("mongodb://" + TARGET_HOST + "/?socketTimeoutMS=4000");
+ ASSERT_OK(uri_sw.getStatus());
+ auto uri = uri_sw.getValue();
+ Date_t start, end;
+ const auto uriTimeout = Seconds{4};
+ const auto overrideTimeout = Seconds{1};
+
+ ScopedDbConnection conn1(TARGET_HOST);
+
+ setReplyDelay(delay);
+
+ log() << "Testing ConnectionString timeouts";
+ start = Date_t::now();
+ ASSERT_THROWS(ScopedDbConnection conn2(TARGET_HOST, overrideTimeout.count()), SocketException);
+ end = Date_t::now();
+ ASSERT_GTE(end - start, overrideTimeout);
+ ASSERT_LT(end - start, uriTimeout);
+
+ log() << "Testing MongoURI with explicit timeout";
+ start = Date_t::now();
+ ASSERT_THROWS(ScopedDbConnection conn4(uri, overrideTimeout.count()), UserException);
+ end = Date_t::now();
+ ASSERT_GTE(end - start, overrideTimeout);
+ ASSERT_LT(end - start, uriTimeout);
+
+ log() << "Testing MongoURI doesn't timeout";
+ start = Date_t::now();
+ ScopedDbConnection conn5(uri);
+ end = Date_t::now();
+ ASSERT_GREATER_THAN(end - start, uriTimeout);
+
+ setReplyDelay(Milliseconds{0});
+}
+
TEST_F(DummyServerFixture, InvalidateBadConnInPool) {
ScopedDbConnection conn1(TARGET_HOST);
ScopedDbConnection conn2(TARGET_HOST);
diff --git a/src/mongo/util/net/ssl_manager.cpp b/src/mongo/util/net/ssl_manager.cpp
index 504e3d55ab5..14df948c858 100644
--- a/src/mongo/util/net/ssl_manager.cpp
+++ b/src/mongo/util/net/ssl_manager.cpp
@@ -385,7 +385,7 @@ MONGO_INITIALIZER(SetupOpenSSL)(InitializerContext*) {
MONGO_INITIALIZER_WITH_PREREQUISITES(SSLManager, ("SetupOpenSSL"))(InitializerContext*) {
stdx::lock_guard<SimpleMutex> lck(sslManagerMtx);
- if (sslGlobalParams.sslMode.load() != SSLParams::SSLMode_disabled) {
+ if (!isSSLServer || (sslGlobalParams.sslMode.load() != SSLParams::SSLMode_disabled)) {
theSSLManager = new SSLManager(sslGlobalParams, isSSLServer);
}
return Status::OK();