summaryrefslogtreecommitdiff
path: root/src/mongo/transport
diff options
context:
space:
mode:
authorAmirsaman Memaripour <amirsaman.memaripour@mongodb.com>2022-01-26 21:40:16 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2022-01-26 22:06:47 +0000
commit3f92a7d72d4fe92a12aeb0f35bb6110fbce8ceb9 (patch)
treeac345c73f280061843439b4a767d0d0ee6d4ee69 /src/mongo/transport
parentba6850cae1a4ccf7d24ff1b5db0290e9c8919931 (diff)
downloadmongo-3f92a7d72d4fe92a12aeb0f35bb6110fbce8ceb9.tar.gz
SERVER-62665 Ensure `TimerService` can safely end the session
Diffstat (limited to 'src/mongo/transport')
-rw-r--r--src/mongo/transport/session_asio.cpp4
-rw-r--r--src/mongo/transport/transport_layer_asio.cpp28
2 files changed, 22 insertions, 10 deletions
diff --git a/src/mongo/transport/session_asio.cpp b/src/mongo/transport/session_asio.cpp
index 3c957556f15..069ebdc52e1 100644
--- a/src/mongo/transport/session_asio.cpp
+++ b/src/mongo/transport/session_asio.cpp
@@ -287,8 +287,8 @@ const std::shared_ptr<SSLManagerInterface> TransportLayerASIO::ASIOSession::getS
return _sslContext->manager;
}
-// The unique_lock here is held by TransportLayerASIO to synchronize with the asyncConnect
-// timeout callback. It will be unlocked before the SSL actually handshake begins.
+// The unique_lock here is held by TransportLayerASIO to synchronize with the timeout callback for
+// both connect and asyncConnect. It will be unlocked before the SSL handshake actually begins.
Future<void> TransportLayerASIO::ASIOSession::handshakeSSLForEgressWithLock(
stdx::unique_lock<Latch> lk, const HostAndPort& target, const ReactorHandle& reactor) {
if (!_sslContext->egress) {
diff --git a/src/mongo/transport/transport_layer_asio.cpp b/src/mongo/transport/transport_layer_asio.cpp
index 8403774718c..83fc6e7de26 100644
--- a/src/mongo/transport/transport_layer_asio.cpp
+++ b/src/mongo/transport/transport_layer_asio.cpp
@@ -599,31 +599,43 @@ StatusWith<SessionHandle> TransportLayerASIO::connect(
// The handshake is complete once either of the following passes the finish line:
// - The thread running the handshake returns from `handshakeSSLForEgress`.
// - The thread running `TimerService` cancels the handshake due to a timeout.
- auto finishLine = std::make_shared<StrongWeakFinishLine>(2);
+ struct HandshakeState {
+ StrongWeakFinishLine finishLine{2};
+ Mutex mutex = MONGO_MAKE_LATCH("HandshakeState::mutex");
+ };
+ auto hs = std::make_shared<HandshakeState>();
// Schedules a task to cancel the synchronous handshake if it does not complete before the
// specified timeout.
auto timer = _timerService->makeTimer();
+
#ifndef _WIN32
// TODO SERVER-62035: enable the following on Windows.
if (timeout > Milliseconds(0)) {
- timer->waitUntil(_timerService->now() + timeout)
- .getAsync([finishLine, session](Status status) {
- if (status.isOK() && finishLine->arriveStrongly())
- session->end();
- });
+ timer->waitUntil(_timerService->now() + timeout).getAsync([hs, session](Status status) {
+ if (status.isOK() && hs->finishLine.arriveStrongly()) {
+ // Holding the `mutex` ensures the socket object inside the session is not moved
+ // by `handshakeSSLForEgressWithLock` while the timer is ending the session.
+ auto lk = stdx::lock_guard(hs->mutex);
+ session->end();
+ }
+ });
}
#endif
Date_t timeBefore = Date_t::now();
- auto sslStatus = session->handshakeSSLForEgress(peer).getNoThrow();
+ stdx::unique_lock<Latch> lk(hs->mutex);
+ // The mutex is released before performing the blocking SSL handshake, so the timer can
+ // acquire the mutex and end the session even when the blocking handshake is in progress.
+ auto sslStatus =
+ session->handshakeSSLForEgressWithLock(std::move(lk), peer, nullptr).getNoThrow();
Date_t timeAfter = Date_t::now();
if (timeAfter - timeBefore > kSlowOperationThreshold) {
networkCounter.incrementNumSlowSSLOperations();
}
- if (finishLine->arriveStrongly()) {
+ if (hs->finishLine.arriveStrongly()) {
timer->cancel();
} else if (!sslStatus.isOK()) {
// We only take this path if the handshake times out. Overwrite the socket exception