deadbeef | f534659 | 2017-01-25 05:51:21 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2017 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 | |
Mirko Bonadei | 92ea95e | 2017-09-15 04:47:31 | [diff] [blame] | 11 | #ifndef P2P_BASE_FAKEDTLSTRANSPORT_H_ |
| 12 | #define P2P_BASE_FAKEDTLSTRANSPORT_H_ |
deadbeef | f534659 | 2017-01-25 05:51:21 | [diff] [blame] | 13 | |
| 14 | #include <memory> |
| 15 | #include <string> |
| 16 | #include <vector> |
| 17 | |
Mirko Bonadei | 92ea95e | 2017-09-15 04:47:31 | [diff] [blame] | 18 | #include "p2p/base/dtlstransportinternal.h" |
| 19 | #include "p2p/base/fakeicetransport.h" |
| 20 | #include "rtc_base/fakesslidentity.h" |
deadbeef | f534659 | 2017-01-25 05:51:21 | [diff] [blame] | 21 | |
| 22 | namespace cricket { |
| 23 | |
| 24 | // Fake DTLS transport which is implemented by wrapping a fake ICE transport. |
| 25 | // Doesn't interact directly with fake ICE transport for anything other than |
| 26 | // sending packets. |
| 27 | class FakeDtlsTransport : public DtlsTransportInternal { |
| 28 | public: |
| 29 | explicit FakeDtlsTransport(FakeIceTransport* ice_transport) |
| 30 | : ice_transport_(ice_transport), |
| 31 | transport_name_(ice_transport->transport_name()), |
| 32 | component_(ice_transport->component()), |
| 33 | dtls_fingerprint_("", nullptr, 0) { |
Zhi Huang | 942bc2e | 2017-11-13 21:26:07 | [diff] [blame] | 34 | RTC_DCHECK(ice_transport_); |
deadbeef | f534659 | 2017-01-25 05:51:21 | [diff] [blame] | 35 | ice_transport_->SignalReadPacket.connect( |
| 36 | this, &FakeDtlsTransport::OnIceTransportReadPacket); |
Zhi Huang | 942bc2e | 2017-11-13 21:26:07 | [diff] [blame] | 37 | ice_transport_->SignalNetworkRouteChanged.connect( |
| 38 | this, &FakeDtlsTransport::OnNetworkRouteChanged); |
deadbeef | f534659 | 2017-01-25 05:51:21 | [diff] [blame] | 39 | } |
| 40 | |
| 41 | // If this constructor is called, a new fake ICE transport will be created, |
| 42 | // and this FakeDtlsTransport will take the ownership. |
| 43 | explicit FakeDtlsTransport(const std::string& name, int component) |
| 44 | : owned_ice_transport_(new FakeIceTransport(name, component)), |
| 45 | transport_name_(owned_ice_transport_->transport_name()), |
| 46 | component_(owned_ice_transport_->component()), |
| 47 | dtls_fingerprint_("", nullptr, 0) { |
| 48 | ice_transport_ = owned_ice_transport_.get(); |
| 49 | ice_transport_->SignalReadPacket.connect( |
| 50 | this, &FakeDtlsTransport::OnIceTransportReadPacket); |
Zhi Huang | 942bc2e | 2017-11-13 21:26:07 | [diff] [blame] | 51 | ice_transport_->SignalNetworkRouteChanged.connect( |
| 52 | this, &FakeDtlsTransport::OnNetworkRouteChanged); |
deadbeef | f534659 | 2017-01-25 05:51:21 | [diff] [blame] | 53 | } |
| 54 | |
| 55 | ~FakeDtlsTransport() override { |
| 56 | if (dest_ && dest_->dest_ == this) { |
| 57 | dest_->dest_ = nullptr; |
| 58 | } |
| 59 | } |
| 60 | |
| 61 | // Get inner fake ICE transport. |
| 62 | FakeIceTransport* fake_ice_transport() { return ice_transport_; } |
| 63 | |
| 64 | // If async, will send packets by "Post"-ing to message queue instead of |
| 65 | // synchronously "Send"-ing. |
| 66 | void SetAsync(bool async) { ice_transport_->SetAsync(async); } |
| 67 | void SetAsyncDelay(int delay_ms) { ice_transport_->SetAsyncDelay(delay_ms); } |
| 68 | |
| 69 | // SetWritable, SetReceiving and SetDestination are the main methods that can |
| 70 | // be used for testing, to simulate connectivity or lack thereof. |
| 71 | void SetWritable(bool writable) { |
| 72 | ice_transport_->SetWritable(writable); |
| 73 | set_writable(writable); |
| 74 | } |
| 75 | void SetReceiving(bool receiving) { |
| 76 | ice_transport_->SetReceiving(receiving); |
| 77 | set_receiving(receiving); |
| 78 | } |
| 79 | |
| 80 | // Simulates the two DTLS transports connecting to each other. |
| 81 | // If |asymmetric| is true this method only affects this FakeDtlsTransport. |
| 82 | // If false, it affects |dest| as well. |
| 83 | void SetDestination(FakeDtlsTransport* dest, bool asymmetric = false) { |
| 84 | if (dest == dest_) { |
| 85 | return; |
| 86 | } |
| 87 | RTC_DCHECK(!dest || !dest_) |
| 88 | << "Changing fake destination from one to another is not supported."; |
| 89 | if (dest && !dest_) { |
| 90 | // This simulates the DTLS handshake. |
| 91 | dest_ = dest; |
| 92 | if (local_cert_ && dest_->local_cert_) { |
| 93 | do_dtls_ = true; |
deadbeef | f534659 | 2017-01-25 05:51:21 | [diff] [blame] | 94 | } |
| 95 | SetWritable(true); |
| 96 | if (!asymmetric) { |
| 97 | dest->SetDestination(this, true); |
| 98 | } |
jbauch | 5869f50 | 2017-06-29 19:31:36 | [diff] [blame] | 99 | dtls_state_ = DTLS_TRANSPORT_CONNECTED; |
deadbeef | f534659 | 2017-01-25 05:51:21 | [diff] [blame] | 100 | ice_transport_->SetDestination( |
| 101 | static_cast<FakeIceTransport*>(dest->ice_transport()), asymmetric); |
| 102 | } else { |
| 103 | // Simulates loss of connectivity, by asymmetrically forgetting dest_. |
| 104 | dest_ = nullptr; |
| 105 | SetWritable(false); |
| 106 | ice_transport_->SetDestination(nullptr, asymmetric); |
| 107 | } |
| 108 | } |
| 109 | |
| 110 | // Fake DtlsTransportInternal implementation. |
| 111 | DtlsTransportState dtls_state() const override { return dtls_state_; } |
| 112 | const std::string& transport_name() const override { return transport_name_; } |
| 113 | int component() const override { return component_; } |
| 114 | const rtc::SSLFingerprint& dtls_fingerprint() const { |
| 115 | return dtls_fingerprint_; |
| 116 | } |
| 117 | bool SetRemoteFingerprint(const std::string& alg, |
| 118 | const uint8_t* digest, |
| 119 | size_t digest_len) override { |
| 120 | dtls_fingerprint_ = rtc::SSLFingerprint(alg, digest, digest_len); |
| 121 | return true; |
| 122 | } |
| 123 | bool SetSslRole(rtc::SSLRole role) override { |
| 124 | ssl_role_ = role; |
| 125 | return true; |
| 126 | } |
| 127 | bool GetSslRole(rtc::SSLRole* role) const override { |
| 128 | *role = ssl_role_; |
| 129 | return true; |
| 130 | } |
jbauch | 5869f50 | 2017-06-29 19:31:36 | [diff] [blame] | 131 | const rtc::CryptoOptions& crypto_options() const override { |
| 132 | return crypto_options_; |
| 133 | } |
| 134 | void SetCryptoOptions(const rtc::CryptoOptions& crypto_options) { |
| 135 | crypto_options_ = crypto_options; |
| 136 | } |
deadbeef | f534659 | 2017-01-25 05:51:21 | [diff] [blame] | 137 | bool SetLocalCertificate( |
| 138 | const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) override { |
| 139 | local_cert_ = certificate; |
| 140 | return true; |
| 141 | } |
| 142 | void SetRemoteSSLCertificate(rtc::FakeSSLCertificate* cert) { |
| 143 | remote_cert_ = cert; |
| 144 | } |
| 145 | bool IsDtlsActive() const override { return do_dtls_; } |
deadbeef | f534659 | 2017-01-25 05:51:21 | [diff] [blame] | 146 | bool GetSrtpCryptoSuite(int* crypto_suite) override { |
deadbeef | 7914b8c | 2017-04-21 10:23:33 | [diff] [blame] | 147 | if (!do_dtls_) { |
| 148 | return false; |
deadbeef | f534659 | 2017-01-25 05:51:21 | [diff] [blame] | 149 | } |
jbauch | 5869f50 | 2017-06-29 19:31:36 | [diff] [blame] | 150 | *crypto_suite = crypto_suite_; |
deadbeef | 7914b8c | 2017-04-21 10:23:33 | [diff] [blame] | 151 | return true; |
deadbeef | f534659 | 2017-01-25 05:51:21 | [diff] [blame] | 152 | } |
jbauch | 5869f50 | 2017-06-29 19:31:36 | [diff] [blame] | 153 | void SetSrtpCryptoSuite(int crypto_suite) { |
| 154 | crypto_suite_ = crypto_suite; |
| 155 | } |
deadbeef | f534659 | 2017-01-25 05:51:21 | [diff] [blame] | 156 | bool GetSslCipherSuite(int* cipher_suite) override { return false; } |
| 157 | rtc::scoped_refptr<rtc::RTCCertificate> GetLocalCertificate() const override { |
| 158 | return local_cert_; |
| 159 | } |
| 160 | std::unique_ptr<rtc::SSLCertificate> GetRemoteSSLCertificate() |
| 161 | const override { |
| 162 | return remote_cert_ ? std::unique_ptr<rtc::SSLCertificate>( |
| 163 | remote_cert_->GetReference()) |
| 164 | : nullptr; |
| 165 | } |
| 166 | bool ExportKeyingMaterial(const std::string& label, |
| 167 | const uint8_t* context, |
| 168 | size_t context_len, |
| 169 | bool use_context, |
| 170 | uint8_t* result, |
| 171 | size_t result_len) override { |
deadbeef | 7914b8c | 2017-04-21 10:23:33 | [diff] [blame] | 172 | if (!do_dtls_) { |
| 173 | return false; |
deadbeef | f534659 | 2017-01-25 05:51:21 | [diff] [blame] | 174 | } |
deadbeef | 7914b8c | 2017-04-21 10:23:33 | [diff] [blame] | 175 | memset(result, 0xff, result_len); |
| 176 | return true; |
deadbeef | f534659 | 2017-01-25 05:51:21 | [diff] [blame] | 177 | } |
| 178 | void set_ssl_max_protocol_version(rtc::SSLProtocolVersion version) { |
| 179 | ssl_max_version_ = version; |
| 180 | } |
| 181 | rtc::SSLProtocolVersion ssl_max_protocol_version() const { |
| 182 | return ssl_max_version_; |
| 183 | } |
deadbeef | f534659 | 2017-01-25 05:51:21 | [diff] [blame] | 184 | |
| 185 | IceTransportInternal* ice_transport() override { return ice_transport_; } |
| 186 | |
deadbeef | 5bd5ca3 | 2017-02-10 19:31:50 | [diff] [blame] | 187 | // PacketTransportInternal implementation, which passes through to fake ICE |
deadbeef | f534659 | 2017-01-25 05:51:21 | [diff] [blame] | 188 | // transport for sending actual packets. |
| 189 | bool writable() const override { return writable_; } |
| 190 | bool receiving() const override { return receiving_; } |
| 191 | int SendPacket(const char* data, |
| 192 | size_t len, |
| 193 | const rtc::PacketOptions& options, |
| 194 | int flags) override { |
| 195 | // We expect only SRTP packets to be sent through this interface. |
| 196 | if (flags != PF_SRTP_BYPASS && flags != 0) { |
| 197 | return -1; |
| 198 | } |
| 199 | return ice_transport_->SendPacket(data, len, options, flags); |
| 200 | } |
| 201 | int SetOption(rtc::Socket::Option opt, int value) override { |
| 202 | return ice_transport_->SetOption(opt, value); |
| 203 | } |
| 204 | bool GetOption(rtc::Socket::Option opt, int* value) override { |
| 205 | return ice_transport_->GetOption(opt, value); |
| 206 | } |
| 207 | int GetError() override { return ice_transport_->GetError(); } |
| 208 | |
Zhi Huang | 942bc2e | 2017-11-13 21:26:07 | [diff] [blame] | 209 | rtc::Optional<rtc::NetworkRoute> network_route() const override { |
| 210 | return ice_transport_->network_route(); |
| 211 | } |
| 212 | |
deadbeef | f534659 | 2017-01-25 05:51:21 | [diff] [blame] | 213 | private: |
deadbeef | 5bd5ca3 | 2017-02-10 19:31:50 | [diff] [blame] | 214 | void OnIceTransportReadPacket(PacketTransportInternal* ice_, |
deadbeef | f534659 | 2017-01-25 05:51:21 | [diff] [blame] | 215 | const char* data, |
| 216 | size_t len, |
| 217 | const rtc::PacketTime& time, |
| 218 | int flags) { |
| 219 | SignalReadPacket(this, data, len, time, flags); |
| 220 | } |
| 221 | |
deadbeef | f534659 | 2017-01-25 05:51:21 | [diff] [blame] | 222 | void set_receiving(bool receiving) { |
| 223 | if (receiving_ == receiving) { |
| 224 | return; |
| 225 | } |
| 226 | receiving_ = receiving; |
| 227 | SignalReceivingState(this); |
| 228 | } |
| 229 | |
| 230 | void set_writable(bool writable) { |
| 231 | if (writable_ == writable) { |
| 232 | return; |
| 233 | } |
| 234 | writable_ = writable; |
| 235 | if (writable_) { |
| 236 | SignalReadyToSend(this); |
| 237 | } |
| 238 | SignalWritableState(this); |
| 239 | } |
| 240 | |
Zhi Huang | 942bc2e | 2017-11-13 21:26:07 | [diff] [blame] | 241 | void OnNetworkRouteChanged(rtc::Optional<rtc::NetworkRoute> network_route) { |
| 242 | SignalNetworkRouteChanged(network_route); |
| 243 | } |
| 244 | |
deadbeef | f534659 | 2017-01-25 05:51:21 | [diff] [blame] | 245 | FakeIceTransport* ice_transport_; |
| 246 | std::unique_ptr<FakeIceTransport> owned_ice_transport_; |
| 247 | std::string transport_name_; |
| 248 | int component_; |
| 249 | FakeDtlsTransport* dest_ = nullptr; |
| 250 | rtc::scoped_refptr<rtc::RTCCertificate> local_cert_; |
| 251 | rtc::FakeSSLCertificate* remote_cert_ = nullptr; |
| 252 | bool do_dtls_ = false; |
deadbeef | f534659 | 2017-01-25 05:51:21 | [diff] [blame] | 253 | rtc::SSLProtocolVersion ssl_max_version_ = rtc::SSL_PROTOCOL_DTLS_12; |
| 254 | rtc::SSLFingerprint dtls_fingerprint_; |
| 255 | rtc::SSLRole ssl_role_ = rtc::SSL_CLIENT; |
jbauch | 5869f50 | 2017-06-29 19:31:36 | [diff] [blame] | 256 | int crypto_suite_ = rtc::SRTP_AES128_CM_SHA1_80; |
| 257 | rtc::CryptoOptions crypto_options_; |
deadbeef | f534659 | 2017-01-25 05:51:21 | [diff] [blame] | 258 | |
| 259 | DtlsTransportState dtls_state_ = DTLS_TRANSPORT_NEW; |
| 260 | |
| 261 | bool receiving_ = false; |
| 262 | bool writable_ = false; |
| 263 | }; |
| 264 | |
| 265 | } // namespace cricket |
| 266 | |
Mirko Bonadei | 92ea95e | 2017-09-15 04:47:31 | [diff] [blame] | 267 | #endif // P2P_BASE_FAKEDTLSTRANSPORT_H_ |