| /* | 
 |  *  Copyright 2018 The WebRTC project authors. All Rights Reserved. | 
 |  * | 
 |  *  Use of this source code is governed by a BSD-style license | 
 |  *  that can be found in the LICENSE file in the root of the source | 
 |  *  tree. An additional intellectual property rights grant can be found | 
 |  *  in the file PATENTS.  All contributing project authors may | 
 |  *  be found in the AUTHORS file in the root of the source tree. | 
 |  */ | 
 |  | 
 | #include "pc/dtls_transport.h" | 
 |  | 
 | #include <memory> | 
 | #include <optional> | 
 | #include <utility> | 
 |  | 
 | #include "api/dtls_transport_interface.h" | 
 | #include "api/ice_transport_interface.h" | 
 | #include "api/make_ref_counted.h" | 
 | #include "api/scoped_refptr.h" | 
 | #include "api/sequence_checker.h" | 
 | #include "p2p/dtls/dtls_transport_internal.h" | 
 | #include "pc/ice_transport.h" | 
 | #include "rtc_base/checks.h" | 
 | #include "rtc_base/logging.h" | 
 | #include "rtc_base/ssl_stream_adapter.h" | 
 | #include "rtc_base/synchronization/mutex.h" | 
 | #include "rtc_base/thread.h" | 
 |  | 
 | namespace webrtc { | 
 |  | 
 | // Implementation of DtlsTransportInterface | 
 | DtlsTransport::DtlsTransport(std::unique_ptr<DtlsTransportInternal> internal) | 
 |     : owner_thread_(Thread::Current()), | 
 |       info_(DtlsTransportState::kNew), | 
 |       internal_dtls_transport_(std::move(internal)), | 
 |       ice_transport_(make_ref_counted<IceTransportWithPointer>( | 
 |           internal_dtls_transport_->ice_transport())) { | 
 |   RTC_DCHECK(internal_dtls_transport_.get()); | 
 |   internal_dtls_transport_->SubscribeDtlsTransportState( | 
 |       [this](DtlsTransportInternal* transport, DtlsTransportState state) { | 
 |         OnInternalDtlsState(transport, state); | 
 |       }); | 
 |   UpdateInformation(); | 
 | } | 
 |  | 
 | DtlsTransport::~DtlsTransport() { | 
 |   // TODO(tommi): Due to a reference being held by the RtpSenderBase | 
 |   // implementation, the last reference to the `DtlsTransport` instance can | 
 |   // be released on the signaling thread. | 
 |   // RTC_DCHECK_RUN_ON(owner_thread_); | 
 |  | 
 |   // We depend on the signaling thread to call Clear() before dropping | 
 |   // its last reference to this object. | 
 |  | 
 |   // If there are non `owner_thread_` references outstanding, and those | 
 |   // references are the last ones released, we depend on Clear() having been | 
 |   // called from the owner_thread before the last reference is deleted. | 
 |   // `Clear()` is currently called from `JsepTransport::~JsepTransport`. | 
 |   RTC_DCHECK(owner_thread_->IsCurrent() || !internal_dtls_transport_); | 
 | } | 
 |  | 
 | DtlsTransportInformation DtlsTransport::Information() { | 
 |   MutexLock lock(&lock_); | 
 |   return info_; | 
 | } | 
 |  | 
 | void DtlsTransport::RegisterObserver(DtlsTransportObserverInterface* observer) { | 
 |   RTC_DCHECK_RUN_ON(owner_thread_); | 
 |   RTC_DCHECK(observer); | 
 |   observer_ = observer; | 
 | } | 
 |  | 
 | void DtlsTransport::UnregisterObserver() { | 
 |   RTC_DCHECK_RUN_ON(owner_thread_); | 
 |   observer_ = nullptr; | 
 | } | 
 |  | 
 | scoped_refptr<IceTransportInterface> DtlsTransport::ice_transport() { | 
 |   return ice_transport_; | 
 | } | 
 |  | 
 | // Internal functions | 
 | void DtlsTransport::Clear() { | 
 |   RTC_DCHECK_RUN_ON(owner_thread_); | 
 |   RTC_DCHECK(internal()); | 
 |   bool must_send_event = | 
 |       (internal()->dtls_state() != DtlsTransportState::kClosed); | 
 |   internal_dtls_transport_.reset(); | 
 |   ice_transport_->Clear(); | 
 |   UpdateInformation(); | 
 |   if (observer_ && must_send_event) { | 
 |     observer_->OnStateChange(Information()); | 
 |   } | 
 | } | 
 |  | 
 | void DtlsTransport::OnInternalDtlsState(DtlsTransportInternal* transport, | 
 |                                         DtlsTransportState state) { | 
 |   RTC_DCHECK_RUN_ON(owner_thread_); | 
 |   RTC_DCHECK(transport == internal()); | 
 |   RTC_DCHECK(state == internal()->dtls_state()); | 
 |   UpdateInformation(); | 
 |   if (observer_) { | 
 |     observer_->OnStateChange(Information()); | 
 |   } | 
 | } | 
 |  | 
 | void DtlsTransport::UpdateInformation() { | 
 |   RTC_DCHECK_RUN_ON(owner_thread_); | 
 |   if (internal_dtls_transport_) { | 
 |     if (internal_dtls_transport_->dtls_state() == | 
 |         DtlsTransportState::kConnected) { | 
 |       bool success = true; | 
 |       SSLRole internal_role; | 
 |       std::optional<DtlsTransportTlsRole> role; | 
 |       int ssl_cipher_suite; | 
 |       int tls_version; | 
 |       int srtp_cipher; | 
 |       success &= internal_dtls_transport_->GetDtlsRole(&internal_role); | 
 |       if (success) { | 
 |         switch (internal_role) { | 
 |           case SSL_CLIENT: | 
 |             role = DtlsTransportTlsRole::kClient; | 
 |             break; | 
 |           case SSL_SERVER: | 
 |             role = DtlsTransportTlsRole::kServer; | 
 |             break; | 
 |         } | 
 |       } | 
 |       success &= internal_dtls_transport_->GetSslVersionBytes(&tls_version); | 
 |       success &= internal_dtls_transport_->GetSslCipherSuite(&ssl_cipher_suite); | 
 |       success &= internal_dtls_transport_->GetSrtpCryptoSuite(&srtp_cipher); | 
 |       if (success) { | 
 |         set_info(DtlsTransportInformation( | 
 |             internal_dtls_transport_->dtls_state(), role, tls_version, | 
 |             ssl_cipher_suite, srtp_cipher, | 
 |             internal_dtls_transport_->GetRemoteSSLCertChain(), | 
 |             internal_dtls_transport_->GetSslGroupId())); | 
 |       } else { | 
 |         RTC_LOG(LS_ERROR) << "DtlsTransport in connected state has incomplete " | 
 |                              "TLS information"; | 
 |         set_info(DtlsTransportInformation( | 
 |             internal_dtls_transport_->dtls_state(), role, std::nullopt, | 
 |             std::nullopt, std::nullopt, | 
 |             internal_dtls_transport_->GetRemoteSSLCertChain(), | 
 |             /* ssl_group_id= */ std::nullopt)); | 
 |       } | 
 |     } else { | 
 |       set_info( | 
 |           DtlsTransportInformation(internal_dtls_transport_->dtls_state())); | 
 |     } | 
 |   } else { | 
 |     set_info(DtlsTransportInformation(DtlsTransportState::kClosed)); | 
 |   } | 
 | } | 
 |  | 
 | }  // namespace webrtc |