Index: webrtc/p2p/base/fakedtlstransport.h |
diff --git a/webrtc/p2p/base/fakedtlstransport.h b/webrtc/p2p/base/fakedtlstransport.h |
new file mode 100644 |
index 0000000000000000000000000000000000000000..1fe66ec1b28d2119016d06765327fa6a57ef0d7d |
--- /dev/null |
+++ b/webrtc/p2p/base/fakedtlstransport.h |
@@ -0,0 +1,270 @@ |
+/* |
+ * Copyright 2017 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. |
+ */ |
+ |
+#ifndef WEBRTC_P2P_BASE_FAKEDTLSTRANSPORT_H_ |
+#define WEBRTC_P2P_BASE_FAKEDTLSTRANSPORT_H_ |
+ |
+#include <memory> |
+#include <string> |
+#include <vector> |
+ |
+#include "webrtc/base/fakesslidentity.h" |
+#include "webrtc/p2p/base/dtlstransportinternal.h" |
+#include "webrtc/p2p/base/fakeicetransport.h" |
+ |
+namespace cricket { |
+ |
+// Fake DTLS transport which is implemented by wrapping a fake ICE transport. |
+// Doesn't interact directly with fake ICE transport for anything other than |
+// sending packets. |
+class FakeDtlsTransport : public DtlsTransportInternal { |
+ public: |
+ explicit FakeDtlsTransport(FakeIceTransport* ice_transport) |
+ : ice_transport_(ice_transport), |
+ transport_name_(ice_transport->transport_name()), |
+ component_(ice_transport->component()), |
+ dtls_fingerprint_("", nullptr, 0) { |
+ ice_transport_->SignalReadPacket.connect( |
+ this, &FakeDtlsTransport::OnIceTransportReadPacket); |
+ } |
+ |
+ // If this constructor is called, a new fake ICE transport will be created, |
+ // and this FakeDtlsTransport will take the ownership. |
+ explicit FakeDtlsTransport(const std::string& name, int component) |
+ : owned_ice_transport_(new FakeIceTransport(name, component)), |
+ transport_name_(owned_ice_transport_->transport_name()), |
+ component_(owned_ice_transport_->component()), |
+ dtls_fingerprint_("", nullptr, 0) { |
+ ice_transport_ = owned_ice_transport_.get(); |
+ ice_transport_->SignalReadPacket.connect( |
+ this, &FakeDtlsTransport::OnIceTransportReadPacket); |
+ } |
+ |
+ ~FakeDtlsTransport() override { |
+ if (dest_ && dest_->dest_ == this) { |
+ dest_->dest_ = nullptr; |
+ } |
+ } |
+ |
+ // Get inner fake ICE transport. |
+ FakeIceTransport* fake_ice_transport() { return ice_transport_; } |
+ |
+ // If async, will send packets by "Post"-ing to message queue instead of |
+ // synchronously "Send"-ing. |
+ void SetAsync(bool async) { ice_transport_->SetAsync(async); } |
+ void SetAsyncDelay(int delay_ms) { ice_transport_->SetAsyncDelay(delay_ms); } |
+ |
+ // SetWritable, SetReceiving and SetDestination are the main methods that can |
+ // be used for testing, to simulate connectivity or lack thereof. |
+ void SetWritable(bool writable) { |
+ ice_transport_->SetWritable(writable); |
+ set_writable(writable); |
+ } |
+ void SetReceiving(bool receiving) { |
+ ice_transport_->SetReceiving(receiving); |
+ set_receiving(receiving); |
+ } |
+ |
+ // Simulates the two DTLS transports connecting to each other. |
+ // If |asymmetric| is true this method only affects this FakeDtlsTransport. |
+ // If false, it affects |dest| as well. |
+ void SetDestination(FakeDtlsTransport* dest, bool asymmetric = false) { |
+ if (dest == dest_) { |
+ return; |
+ } |
+ RTC_DCHECK(!dest || !dest_) |
+ << "Changing fake destination from one to another is not supported."; |
+ if (dest && !dest_) { |
+ // This simulates the DTLS handshake. |
+ dest_ = dest; |
+ if (local_cert_ && dest_->local_cert_) { |
+ do_dtls_ = true; |
+ NegotiateSrtpCiphers(); |
+ } |
+ SetWritable(true); |
+ if (!asymmetric) { |
+ dest->SetDestination(this, true); |
+ } |
+ ice_transport_->SetDestination( |
+ static_cast<FakeIceTransport*>(dest->ice_transport()), asymmetric); |
+ } else { |
+ // Simulates loss of connectivity, by asymmetrically forgetting dest_. |
+ dest_ = nullptr; |
+ SetWritable(false); |
+ ice_transport_->SetDestination(nullptr, asymmetric); |
+ } |
+ } |
+ |
+ // Fake DtlsTransportInternal implementation. |
+ DtlsTransportState dtls_state() const override { return dtls_state_; } |
+ const std::string& transport_name() const override { return transport_name_; } |
+ int component() const override { return component_; } |
+ const rtc::SSLFingerprint& dtls_fingerprint() const { |
+ return dtls_fingerprint_; |
+ } |
+ bool SetRemoteFingerprint(const std::string& alg, |
+ const uint8_t* digest, |
+ size_t digest_len) override { |
+ dtls_fingerprint_ = rtc::SSLFingerprint(alg, digest, digest_len); |
+ return true; |
+ } |
+ bool SetSslRole(rtc::SSLRole role) override { |
+ ssl_role_ = role; |
+ return true; |
+ } |
+ bool GetSslRole(rtc::SSLRole* role) const override { |
+ *role = ssl_role_; |
+ return true; |
+ } |
+ bool SetLocalCertificate( |
+ const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) override { |
+ local_cert_ = certificate; |
+ return true; |
+ } |
+ void SetRemoteSSLCertificate(rtc::FakeSSLCertificate* cert) { |
+ remote_cert_ = cert; |
+ } |
+ bool IsDtlsActive() const override { return do_dtls_; } |
+ bool SetSrtpCryptoSuites(const std::vector<int>& ciphers) override { |
+ srtp_ciphers_ = ciphers; |
+ return true; |
+ } |
+ bool GetSrtpCryptoSuite(int* crypto_suite) override { |
+ if (chosen_crypto_suite_ != rtc::SRTP_INVALID_CRYPTO_SUITE) { |
+ *crypto_suite = chosen_crypto_suite_; |
+ return true; |
+ } |
+ return false; |
+ } |
+ bool GetSslCipherSuite(int* cipher_suite) override { return false; } |
+ rtc::scoped_refptr<rtc::RTCCertificate> GetLocalCertificate() const override { |
+ return local_cert_; |
+ } |
+ std::unique_ptr<rtc::SSLCertificate> GetRemoteSSLCertificate() |
+ const override { |
+ return remote_cert_ ? std::unique_ptr<rtc::SSLCertificate>( |
+ remote_cert_->GetReference()) |
+ : nullptr; |
+ } |
+ bool ExportKeyingMaterial(const std::string& label, |
+ const uint8_t* context, |
+ size_t context_len, |
+ bool use_context, |
+ uint8_t* result, |
+ size_t result_len) override { |
+ if (chosen_crypto_suite_ != rtc::SRTP_INVALID_CRYPTO_SUITE) { |
+ memset(result, 0xff, result_len); |
+ return true; |
+ } |
+ |
+ return false; |
+ } |
+ void set_ssl_max_protocol_version(rtc::SSLProtocolVersion version) { |
+ ssl_max_version_ = version; |
+ } |
+ rtc::SSLProtocolVersion ssl_max_protocol_version() const { |
+ return ssl_max_version_; |
+ } |
+ bool SetSrtpCiphers(const std::vector<std::string>& ciphers) override { |
+ std::vector<int> crypto_suites; |
+ for (const auto cipher : ciphers) { |
+ crypto_suites.push_back(rtc::SrtpCryptoSuiteFromName(cipher)); |
+ } |
+ return SetSrtpCryptoSuites(crypto_suites); |
+ } |
+ |
+ IceTransportInternal* ice_transport() override { return ice_transport_; } |
+ |
+ // PacketTransportInterface implementation, which passes through to fake ICE |
+ // transport for sending actual packets. |
+ bool writable() const override { return writable_; } |
+ bool receiving() const override { return receiving_; } |
+ int SendPacket(const char* data, |
+ size_t len, |
+ const rtc::PacketOptions& options, |
+ int flags) override { |
+ // We expect only SRTP packets to be sent through this interface. |
+ if (flags != PF_SRTP_BYPASS && flags != 0) { |
+ return -1; |
+ } |
+ return ice_transport_->SendPacket(data, len, options, flags); |
+ } |
+ int SetOption(rtc::Socket::Option opt, int value) override { |
+ return ice_transport_->SetOption(opt, value); |
+ } |
+ bool GetOption(rtc::Socket::Option opt, int* value) override { |
+ return ice_transport_->GetOption(opt, value); |
+ } |
+ int GetError() override { return ice_transport_->GetError(); } |
+ |
+ private: |
+ void OnIceTransportReadPacket(PacketTransportInterface* ice_, |
+ const char* data, |
+ size_t len, |
+ const rtc::PacketTime& time, |
+ int flags) { |
+ SignalReadPacket(this, data, len, time, flags); |
+ } |
+ |
+ void NegotiateSrtpCiphers() { |
+ for (std::vector<int>::const_iterator it1 = srtp_ciphers_.begin(); |
+ it1 != srtp_ciphers_.end(); ++it1) { |
+ for (std::vector<int>::const_iterator it2 = dest_->srtp_ciphers_.begin(); |
+ it2 != dest_->srtp_ciphers_.end(); ++it2) { |
+ if (*it1 == *it2) { |
+ chosen_crypto_suite_ = *it1; |
+ return; |
+ } |
+ } |
+ } |
+ } |
+ |
+ void set_receiving(bool receiving) { |
+ if (receiving_ == receiving) { |
+ return; |
+ } |
+ receiving_ = receiving; |
+ SignalReceivingState(this); |
+ } |
+ |
+ void set_writable(bool writable) { |
+ if (writable_ == writable) { |
+ return; |
+ } |
+ writable_ = writable; |
+ if (writable_) { |
+ SignalReadyToSend(this); |
+ } |
+ SignalWritableState(this); |
+ } |
+ |
+ FakeIceTransport* ice_transport_; |
+ std::unique_ptr<FakeIceTransport> owned_ice_transport_; |
+ std::string transport_name_; |
+ int component_; |
+ FakeDtlsTransport* dest_ = nullptr; |
+ rtc::scoped_refptr<rtc::RTCCertificate> local_cert_; |
+ rtc::FakeSSLCertificate* remote_cert_ = nullptr; |
+ bool do_dtls_ = false; |
+ std::vector<int> srtp_ciphers_; |
+ int chosen_crypto_suite_ = rtc::SRTP_INVALID_CRYPTO_SUITE; |
+ rtc::SSLProtocolVersion ssl_max_version_ = rtc::SSL_PROTOCOL_DTLS_12; |
+ rtc::SSLFingerprint dtls_fingerprint_; |
+ rtc::SSLRole ssl_role_ = rtc::SSL_CLIENT; |
+ |
+ DtlsTransportState dtls_state_ = DTLS_TRANSPORT_NEW; |
+ |
+ bool receiving_ = false; |
+ bool writable_ = false; |
+}; |
+ |
+} // namespace cricket |
+ |
+#endif // WEBRTC_P2P_BASE_FAKEDTLSTRANSPORT_H_ |