diff --git a/src/security/tls_session.cpp b/src/security/tls_session.cpp index c3e563aecfdf568b419c1585cd9c1713700aa269..112206059fa72064610f6b4daff93b21e70b35b8 100644 --- a/src/security/tls_session.cpp +++ b/src/security/tls_session.cpp @@ -188,6 +188,10 @@ public: SocketType& transport_; + // State protectors + std::mutex stateMutex_; + std::condition_variable stateCondition_; + // State machine TlsSessionState handleStateSetup(TlsSessionState state); TlsSessionState handleStateCookie(TlsSessionState state); @@ -197,6 +201,7 @@ public: TlsSessionState handleStateShutdown(TlsSessionState state); std::map<TlsSessionState, StateHandler> fsmHandlers_ {}; std::atomic<TlsSessionState> state_ {TlsSessionState::SETUP}; + std::atomic<TlsSessionState> newState_ {TlsSessionState::NONE}; std::atomic<int> maxPayload_ {-1}; // IO GnuTLS <-> ICE @@ -251,9 +256,6 @@ public: bool setup(); void process(); void cleanup(); - // State protectors - std::mutex stateMutex_; - std::condition_variable stateCondition_; ScheduledExecutor scheduler_; @@ -302,6 +304,9 @@ TlsSession::TlsSessionImpl::TlsSessionImpl(SocketType& transport, TlsSession::TlsSessionImpl::~TlsSessionImpl() { + state_ = TlsSessionState::SHUTDOWN; + stateCondition_.notify_all(); + rxCv_.notify_all(); thread_.join(); if (not transport_.isReliable()) transport_.setOnRecv(nullptr); @@ -1130,11 +1135,20 @@ TlsSession::TlsSessionImpl::handleStateEstablished(TlsSessionState state) // Nothing to do in reliable mode, so just wait for state change if (transport_.isReliable()) { auto disconnected = [this]() -> bool { - return state_.load() != TlsSessionState::ESTABLISHED; + return state_.load() != TlsSessionState::ESTABLISHED + or newState_.load() != TlsSessionState::NONE; }; std::unique_lock<std::mutex> lk(stateMutex_); stateCondition_.wait(lk, disconnected); - return state; + auto oldState = state_.load(); + if (oldState == TlsSessionState::ESTABLISHED) { + auto newState = newState_.load(); + if (newState != TlsSessionState::NONE) { + newState_ = TlsSessionState::NONE; + return newState; + } + } + return oldState; } // block until rx packet or state change @@ -1227,9 +1241,7 @@ TlsSession::TlsSession(SocketType& transport, const TlsParams& params, {} TlsSession::~TlsSession() -{ - if (pimpl_) shutdown(); -} +{} bool TlsSession::isInitiator() const @@ -1316,22 +1328,27 @@ TlsSession::read(ValueType* data, std::size_t size, std::error_code& ec) return ret; } + std::lock_guard<std::mutex> lk(pimpl_->stateMutex_); if (ret == 0) { if (pimpl_) { - JAMI_ERR("[TLS] eof"); - shutdown(); + JAMI_DBG("[TLS] eof"); + pimpl_->newState_ = TlsSessionState::SHUTDOWN; + pimpl_->stateCondition_.notify_all(); + pimpl_->rxCv_.notify_one(); // unblock waiting FSM } error = std::errc::broken_pipe; break; } else if (ret == GNUTLS_E_REHANDSHAKE) { JAMI_DBG("[TLS] re-handshake"); - pimpl_->state_ = TlsSessionState::HANDSHAKE; + pimpl_->newState_ = TlsSessionState::HANDSHAKE; pimpl_->rxCv_.notify_one(); // unblock waiting FSM pimpl_->stateCondition_.notify_all(); } else if (gnutls_error_is_fatal(ret)) { if (pimpl_ && pimpl_->state_ != TlsSessionState::SHUTDOWN) { JAMI_ERR("[TLS] fatal error in recv: %s", gnutls_strerror(ret)); - shutdown(); + pimpl_->newState_ = TlsSessionState::SHUTDOWN; + pimpl_->stateCondition_.notify_all(); + pimpl_->rxCv_.notify_one(); // unblock waiting FSM } error = std::errc::io_error; break; diff --git a/src/security/tls_session.h b/src/security/tls_session.h index 4b779e9ddeff370a2e04c276304ee872a695119e..80e241e9539bd0fcda2fa58d188f5f46914bc0ba 100644 --- a/src/security/tls_session.h +++ b/src/security/tls_session.h @@ -46,6 +46,7 @@ class DhParams; enum class TlsSessionState { + NONE, SETUP, COOKIE, // only used with non-initiator and non-reliable transport HANDSHAKE,