You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
311 lines
10 KiB
311 lines
10 KiB
/*
|
|
* 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 "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(std::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;
|
|
SignalDtlsState(this, dtls_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);
|
|
}
|
|
// If the |dtls_role_| is unset, set it to SSL_CLIENT by default.
|
|
if (!dtls_role_) {
|
|
dtls_role_ = std::move(rtc::SSL_CLIENT);
|
|
}
|
|
SetDtlsState(DTLS_TRANSPORT_CONNECTED);
|
|
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 GetSslVersionBytes(int* version) const override {
|
|
if (!do_dtls_) {
|
|
return false;
|
|
}
|
|
*version = 0x0102;
|
|
return true;
|
|
}
|
|
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 std::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_
|