diff options
author | Amirsaman Memaripour <amirsaman.memaripour@mongodb.com> | 2022-01-26 21:40:16 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2022-01-26 22:06:47 +0000 |
commit | 3f92a7d72d4fe92a12aeb0f35bb6110fbce8ceb9 (patch) | |
tree | ac345c73f280061843439b4a767d0d0ee6d4ee69 /src/mongo/transport | |
parent | ba6850cae1a4ccf7d24ff1b5db0290e9c8919931 (diff) | |
download | mongo-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.cpp | 4 | ||||
-rw-r--r-- | src/mongo/transport/transport_layer_asio.cpp | 28 |
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 |