| /* | 
 |  *  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 P2P_BASE_FAKE_DTLS_TRANSPORT_H_ | 
 | #define P2P_BASE_FAKE_DTLS_TRANSPORT_H_ | 
 |  | 
 | #include <memory> | 
 | #include <string> | 
 | #include <utility> | 
 | #include <vector> | 
 |  | 
 | #include "absl/memory/memory.h" | 
 | #include "api/crypto/crypto_options.h" | 
 | #include "p2p/base/dtls_transport_internal.h" | 
 | #include "p2p/base/fake_ice_transport.h" | 
 | #include "rtc_base/fake_ssl_identity.h" | 
 | #include "rtc_base/rtc_certificate.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) { | 
 |     RTC_DCHECK(ice_transport_); | 
 |     ice_transport_->SignalReadPacket.connect( | 
 |         this, &FakeDtlsTransport::OnIceTransportReadPacket); | 
 |     ice_transport_->SignalNetworkRouteChanged.connect( | 
 |         this, &FakeDtlsTransport::OnNetworkRouteChanged); | 
 |   } | 
 |  | 
 |   explicit FakeDtlsTransport(std::unique_ptr<FakeIceTransport> ice) | 
 |       : owned_ice_transport_(std::move(ice)), | 
 |         transport_name_(owned_ice_transport_->transport_name()), | 
 |         component_(owned_ice_transport_->component()), | 
 |         dtls_fingerprint_("", rtc::ArrayView<const uint8_t>()) { | 
 |     ice_transport_ = owned_ice_transport_.get(); | 
 |     ice_transport_->SignalReadPacket.connect( | 
 |         this, &FakeDtlsTransport::OnIceTransportReadPacket); | 
 |     ice_transport_->SignalNetworkRouteChanged.connect( | 
 |         this, &FakeDtlsTransport::OnNetworkRouteChanged); | 
 |   } | 
 |  | 
 |   // 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) | 
 |       : FakeDtlsTransport( | 
 |             absl::make_unique<FakeIceTransport>(name, component)) {} | 
 |  | 
 |   ~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); | 
 |   } | 
 |   void SetDtlsState(DtlsTransportState state) { dtls_state_ = state; } | 
 |  | 
 |   // 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; | 
 |         RTC_LOG(LS_INFO) << "FakeDtlsTransport is doing DTLS"; | 
 |       } else { | 
 |         do_dtls_ = false; | 
 |         RTC_LOG(LS_INFO) << "FakeDtlsTransport is not doing DTLS"; | 
 |       } | 
 |       SetWritable(true); | 
 |       if (!asymmetric) { | 
 |         dest->SetDestination(this, true); | 
 |       } | 
 |       dtls_state_ = DTLS_TRANSPORT_CONNECTED; | 
 |       // If the |dtls_role_| is unset, set it to SSL_CLIENT by default. | 
 |       if (!dtls_role_) { | 
 |         dtls_role_ = std::move(rtc::SSL_CLIENT); | 
 |       } | 
 |       SignalDtlsState(this, dtls_state_); | 
 |       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, rtc::MakeArrayView(digest, digest_len)); | 
 |     return true; | 
 |   } | 
 |   bool SetSslMaxProtocolVersion(rtc::SSLProtocolVersion version) override { | 
 |     return true; | 
 |   } | 
 |   bool SetDtlsRole(rtc::SSLRole role) override { | 
 |     dtls_role_ = std::move(role); | 
 |     return true; | 
 |   } | 
 |   bool GetDtlsRole(rtc::SSLRole* role) const override { | 
 |     if (!dtls_role_) { | 
 |       return false; | 
 |     } | 
 |     *role = *dtls_role_; | 
 |     return true; | 
 |   } | 
 |   const webrtc::CryptoOptions& crypto_options() const override { | 
 |     return crypto_options_; | 
 |   } | 
 |   void SetCryptoOptions(const webrtc::CryptoOptions& crypto_options) { | 
 |     crypto_options_ = crypto_options; | 
 |   } | 
 |   bool SetLocalCertificate( | 
 |       const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) override { | 
 |     do_dtls_ = true; | 
 |     local_cert_ = certificate; | 
 |     return true; | 
 |   } | 
 |   void SetRemoteSSLCertificate(rtc::FakeSSLCertificate* cert) { | 
 |     remote_cert_ = cert; | 
 |   } | 
 |   bool IsDtlsActive() const override { return do_dtls_; } | 
 |   bool GetSrtpCryptoSuite(int* crypto_suite) override { | 
 |     if (!do_dtls_) { | 
 |       return false; | 
 |     } | 
 |     *crypto_suite = crypto_suite_; | 
 |     return true; | 
 |   } | 
 |   void SetSrtpCryptoSuite(int crypto_suite) { crypto_suite_ = crypto_suite; } | 
 |  | 
 |   bool GetSslCipherSuite(int* cipher_suite) override { | 
 |     if (ssl_cipher_suite_) { | 
 |       *cipher_suite = *ssl_cipher_suite_; | 
 |       return true; | 
 |     } | 
 |     return false; | 
 |   } | 
 |   void SetSslCipherSuite(absl::optional<int> cipher_suite) { | 
 |     ssl_cipher_suite_ = cipher_suite; | 
 |   } | 
 |   rtc::scoped_refptr<rtc::RTCCertificate> GetLocalCertificate() const override { | 
 |     return local_cert_; | 
 |   } | 
 |   std::unique_ptr<rtc::SSLCertChain> GetRemoteSSLCertChain() const override { | 
 |     if (!remote_cert_) { | 
 |       return nullptr; | 
 |     } | 
 |     return absl::make_unique<rtc::SSLCertChain>(remote_cert_->Clone()); | 
 |   } | 
 |   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 (!do_dtls_) { | 
 |       return false; | 
 |     } | 
 |     memset(result, 0xff, result_len); | 
 |     return true; | 
 |   } | 
 |   void set_ssl_max_protocol_version(rtc::SSLProtocolVersion version) { | 
 |     ssl_max_version_ = version; | 
 |   } | 
 |   rtc::SSLProtocolVersion ssl_max_protocol_version() const { | 
 |     return ssl_max_version_; | 
 |   } | 
 |  | 
 |   IceTransportInternal* ice_transport() override { return ice_transport_; } | 
 |  | 
 |   // PacketTransportInternal 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(); } | 
 |  | 
 |   absl::optional<rtc::NetworkRoute> network_route() const override { | 
 |     return ice_transport_->network_route(); | 
 |   } | 
 |  | 
 |  private: | 
 |   void OnIceTransportReadPacket(PacketTransportInternal* ice_, | 
 |                                 const char* data, | 
 |                                 size_t len, | 
 |                                 const int64_t& packet_time_us, | 
 |                                 int flags) { | 
 |     SignalReadPacket(this, data, len, packet_time_us, flags); | 
 |   } | 
 |  | 
 |   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); | 
 |   } | 
 |  | 
 |   void OnNetworkRouteChanged(absl::optional<rtc::NetworkRoute> network_route) { | 
 |     SignalNetworkRouteChanged(network_route); | 
 |   } | 
 |  | 
 |   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; | 
 |   rtc::SSLProtocolVersion ssl_max_version_ = rtc::SSL_PROTOCOL_DTLS_12; | 
 |   rtc::SSLFingerprint dtls_fingerprint_; | 
 |   absl::optional<rtc::SSLRole> dtls_role_; | 
 |   int crypto_suite_ = rtc::SRTP_AES128_CM_SHA1_80; | 
 |   absl::optional<int> ssl_cipher_suite_; | 
 |   webrtc::CryptoOptions crypto_options_; | 
 |  | 
 |   DtlsTransportState dtls_state_ = DTLS_TRANSPORT_NEW; | 
 |  | 
 |   bool receiving_ = false; | 
 |   bool writable_ = false; | 
 | }; | 
 |  | 
 | }  // namespace cricket | 
 |  | 
 | #endif  // P2P_BASE_FAKE_DTLS_TRANSPORT_H_ |