1 /*
2 * Copyright 2018 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "pc/dtls_transport.h"
12
13 #include <utility>
14
15 #include "absl/types/optional.h"
16 #include "api/dtls_transport_interface.h"
17 #include "api/make_ref_counted.h"
18 #include "api/sequence_checker.h"
19 #include "pc/ice_transport.h"
20 #include "rtc_base/checks.h"
21 #include "rtc_base/logging.h"
22 #include "rtc_base/ssl_stream_adapter.h"
23
24 namespace webrtc {
25
26 // Implementation of DtlsTransportInterface
DtlsTransport(std::unique_ptr<cricket::DtlsTransportInternal> internal)27 DtlsTransport::DtlsTransport(
28 std::unique_ptr<cricket::DtlsTransportInternal> internal)
29 : owner_thread_(rtc::Thread::Current()),
30 info_(DtlsTransportState::kNew),
31 internal_dtls_transport_(std::move(internal)),
32 ice_transport_(rtc::make_ref_counted<IceTransportWithPointer>(
33 internal_dtls_transport_->ice_transport())) {
34 RTC_DCHECK(internal_dtls_transport_.get());
35 internal_dtls_transport_->SubscribeDtlsTransportState(
36 [this](cricket::DtlsTransportInternal* transport,
37 DtlsTransportState state) {
38 OnInternalDtlsState(transport, state);
39 });
40 UpdateInformation();
41 }
42
~DtlsTransport()43 DtlsTransport::~DtlsTransport() {
44 // We depend on the signaling thread to call Clear() before dropping
45 // its last reference to this object.
46 RTC_DCHECK(owner_thread_->IsCurrent() || !internal_dtls_transport_);
47 }
48
Information()49 DtlsTransportInformation DtlsTransport::Information() {
50 MutexLock lock(&lock_);
51 return info_;
52 }
53
RegisterObserver(DtlsTransportObserverInterface * observer)54 void DtlsTransport::RegisterObserver(DtlsTransportObserverInterface* observer) {
55 RTC_DCHECK_RUN_ON(owner_thread_);
56 RTC_DCHECK(observer);
57 observer_ = observer;
58 }
59
UnregisterObserver()60 void DtlsTransport::UnregisterObserver() {
61 RTC_DCHECK_RUN_ON(owner_thread_);
62 observer_ = nullptr;
63 }
64
ice_transport()65 rtc::scoped_refptr<IceTransportInterface> DtlsTransport::ice_transport() {
66 return ice_transport_;
67 }
68
69 // Internal functions
Clear()70 void DtlsTransport::Clear() {
71 RTC_DCHECK_RUN_ON(owner_thread_);
72 RTC_DCHECK(internal());
73 bool must_send_event =
74 (internal()->dtls_state() != DtlsTransportState::kClosed);
75 // The destructor of cricket::DtlsTransportInternal calls back
76 // into DtlsTransport, so we can't hold the lock while releasing.
77 std::unique_ptr<cricket::DtlsTransportInternal> transport_to_release;
78 {
79 MutexLock lock(&lock_);
80 transport_to_release = std::move(internal_dtls_transport_);
81 ice_transport_->Clear();
82 }
83 UpdateInformation();
84 if (observer_ && must_send_event) {
85 observer_->OnStateChange(Information());
86 }
87 }
88
OnInternalDtlsState(cricket::DtlsTransportInternal * transport,DtlsTransportState state)89 void DtlsTransport::OnInternalDtlsState(
90 cricket::DtlsTransportInternal* transport,
91 DtlsTransportState state) {
92 RTC_DCHECK_RUN_ON(owner_thread_);
93 RTC_DCHECK(transport == internal());
94 RTC_DCHECK(state == internal()->dtls_state());
95 UpdateInformation();
96 if (observer_) {
97 observer_->OnStateChange(Information());
98 }
99 }
100
UpdateInformation()101 void DtlsTransport::UpdateInformation() {
102 RTC_DCHECK_RUN_ON(owner_thread_);
103 MutexLock lock(&lock_);
104 if (internal_dtls_transport_) {
105 if (internal_dtls_transport_->dtls_state() ==
106 DtlsTransportState::kConnected) {
107 bool success = true;
108 rtc::SSLRole internal_role;
109 absl::optional<DtlsTransportTlsRole> role;
110 int ssl_cipher_suite;
111 int tls_version;
112 int srtp_cipher;
113 success &= internal_dtls_transport_->GetDtlsRole(&internal_role);
114 if (success) {
115 switch (internal_role) {
116 case rtc::SSL_CLIENT:
117 role = DtlsTransportTlsRole::kClient;
118 break;
119 case rtc::SSL_SERVER:
120 role = DtlsTransportTlsRole::kServer;
121 break;
122 }
123 }
124 success &= internal_dtls_transport_->GetSslVersionBytes(&tls_version);
125 success &= internal_dtls_transport_->GetSslCipherSuite(&ssl_cipher_suite);
126 success &= internal_dtls_transport_->GetSrtpCryptoSuite(&srtp_cipher);
127 if (success) {
128 info_ = DtlsTransportInformation(
129 internal_dtls_transport_->dtls_state(), role, tls_version,
130 ssl_cipher_suite, srtp_cipher,
131 internal_dtls_transport_->GetRemoteSSLCertChain());
132 } else {
133 RTC_LOG(LS_ERROR) << "DtlsTransport in connected state has incomplete "
134 "TLS information";
135 info_ = DtlsTransportInformation(
136 internal_dtls_transport_->dtls_state(), role, absl::nullopt,
137 absl::nullopt, absl::nullopt,
138 internal_dtls_transport_->GetRemoteSSLCertChain());
139 }
140 } else {
141 info_ = DtlsTransportInformation(internal_dtls_transport_->dtls_state());
142 }
143 } else {
144 info_ = DtlsTransportInformation(DtlsTransportState::kClosed);
145 }
146 }
147
148 } // namespace webrtc
149