diff options
Diffstat (limited to 'third_party/libwebrtc/p2p/base/fake_ice_transport.h')
-rw-r--r-- | third_party/libwebrtc/p2p/base/fake_ice_transport.h | 446 |
1 files changed, 446 insertions, 0 deletions
diff --git a/third_party/libwebrtc/p2p/base/fake_ice_transport.h b/third_party/libwebrtc/p2p/base/fake_ice_transport.h new file mode 100644 index 0000000000..ae7bf8947e --- /dev/null +++ b/third_party/libwebrtc/p2p/base/fake_ice_transport.h @@ -0,0 +1,446 @@ +/* + * 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_ICE_TRANSPORT_H_ +#define P2P_BASE_FAKE_ICE_TRANSPORT_H_ + +#include <map> +#include <memory> +#include <string> +#include <utility> + +#include "absl/algorithm/container.h" +#include "absl/strings/string_view.h" +#include "absl/types/optional.h" +#include "api/ice_transport_interface.h" +#include "api/task_queue/pending_task_safety_flag.h" +#include "api/units/time_delta.h" +#include "p2p/base/ice_transport_internal.h" +#include "rtc_base/copy_on_write_buffer.h" +#include "rtc_base/task_queue_for_test.h" + +namespace cricket { +using ::webrtc::SafeTask; +using ::webrtc::TimeDelta; + +// All methods must be called on the network thread (which is either the thread +// calling the constructor, or the separate thread explicitly passed to the +// constructor). +class FakeIceTransport : public IceTransportInternal { + public: + explicit FakeIceTransport(absl::string_view name, + int component, + rtc::Thread* network_thread = nullptr) + : name_(name), + component_(component), + network_thread_(network_thread ? network_thread + : rtc::Thread::Current()) { + RTC_DCHECK(network_thread_); + } + // Must be called either on the network thread, or after the network thread + // has been shut down. + ~FakeIceTransport() override { + if (dest_ && dest_->dest_ == this) { + dest_->dest_ = nullptr; + } + } + + // If async, will send packets by "Post"-ing to message queue instead of + // synchronously "Send"-ing. + void SetAsync(bool async) { + RTC_DCHECK_RUN_ON(network_thread_); + async_ = async; + } + void SetAsyncDelay(int delay_ms) { + RTC_DCHECK_RUN_ON(network_thread_); + async_delay_ms_ = 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) { + RTC_DCHECK_RUN_ON(network_thread_); + set_writable(writable); + } + void SetReceiving(bool receiving) { + RTC_DCHECK_RUN_ON(network_thread_); + set_receiving(receiving); + } + + // Simulates the two transports connecting to each other. + // If `asymmetric` is true this method only affects this FakeIceTransport. + // If false, it affects `dest` as well. + void SetDestination(FakeIceTransport* dest, bool asymmetric = false) { + RTC_DCHECK_RUN_ON(network_thread_); + if (dest == dest_) { + return; + } + RTC_DCHECK(!dest || !dest_) + << "Changing fake destination from one to another is not supported."; + if (dest) { + // This simulates the delivery of candidates. + dest_ = dest; + set_writable(true); + if (!asymmetric) { + dest->SetDestination(this, true); + } + } else { + // Simulates loss of connectivity, by asymmetrically forgetting dest_. + dest_ = nullptr; + set_writable(false); + } + } + + void SetTransportState(webrtc::IceTransportState state, + IceTransportState legacy_state) { + RTC_DCHECK_RUN_ON(network_thread_); + transport_state_ = state; + legacy_transport_state_ = legacy_state; + SignalIceTransportStateChanged(this); + } + + void SetConnectionCount(size_t connection_count) { + RTC_DCHECK_RUN_ON(network_thread_); + size_t old_connection_count = connection_count_; + connection_count_ = connection_count; + if (connection_count) { + had_connection_ = true; + } + // In this fake transport channel, `connection_count_` determines the + // transport state. + if (connection_count_ < old_connection_count) { + SignalStateChanged(this); + } + } + + void SetCandidatesGatheringComplete() { + RTC_DCHECK_RUN_ON(network_thread_); + if (gathering_state_ != kIceGatheringComplete) { + gathering_state_ = kIceGatheringComplete; + SignalGatheringState(this); + } + } + + // Convenience functions for accessing ICE config and other things. + int receiving_timeout() const { + RTC_DCHECK_RUN_ON(network_thread_); + return ice_config_.receiving_timeout_or_default(); + } + bool gather_continually() const { + RTC_DCHECK_RUN_ON(network_thread_); + return ice_config_.gather_continually(); + } + const Candidates& remote_candidates() const { + RTC_DCHECK_RUN_ON(network_thread_); + return remote_candidates_; + } + + // Fake IceTransportInternal implementation. + const std::string& transport_name() const override { return name_; } + int component() const override { return component_; } + uint64_t IceTiebreaker() const { + RTC_DCHECK_RUN_ON(network_thread_); + return tiebreaker_; + } + IceMode remote_ice_mode() const { + RTC_DCHECK_RUN_ON(network_thread_); + return remote_ice_mode_; + } + const std::string& ice_ufrag() const { return ice_parameters_.ufrag; } + const std::string& ice_pwd() const { return ice_parameters_.pwd; } + const std::string& remote_ice_ufrag() const { + return remote_ice_parameters_.ufrag; + } + const std::string& remote_ice_pwd() const { + return remote_ice_parameters_.pwd; + } + const IceParameters& ice_parameters() const { return ice_parameters_; } + const IceParameters& remote_ice_parameters() const { + return remote_ice_parameters_; + } + + IceTransportState GetState() const override { + RTC_DCHECK_RUN_ON(network_thread_); + if (legacy_transport_state_) { + return *legacy_transport_state_; + } + + if (connection_count_ == 0) { + return had_connection_ ? IceTransportState::STATE_FAILED + : IceTransportState::STATE_INIT; + } + + if (connection_count_ == 1) { + return IceTransportState::STATE_COMPLETED; + } + + return IceTransportState::STATE_CONNECTING; + } + + webrtc::IceTransportState GetIceTransportState() const override { + RTC_DCHECK_RUN_ON(network_thread_); + if (transport_state_) { + return *transport_state_; + } + + if (connection_count_ == 0) { + return had_connection_ ? webrtc::IceTransportState::kFailed + : webrtc::IceTransportState::kNew; + } + + if (connection_count_ == 1) { + return webrtc::IceTransportState::kCompleted; + } + + return webrtc::IceTransportState::kConnected; + } + + void SetIceRole(IceRole role) override { + RTC_DCHECK_RUN_ON(network_thread_); + role_ = role; + } + IceRole GetIceRole() const override { + RTC_DCHECK_RUN_ON(network_thread_); + return role_; + } + void SetIceTiebreaker(uint64_t tiebreaker) override { + RTC_DCHECK_RUN_ON(network_thread_); + tiebreaker_ = tiebreaker; + } + void SetIceParameters(const IceParameters& ice_params) override { + RTC_DCHECK_RUN_ON(network_thread_); + ice_parameters_ = ice_params; + } + void SetRemoteIceParameters(const IceParameters& params) override { + RTC_DCHECK_RUN_ON(network_thread_); + remote_ice_parameters_ = params; + } + + void SetRemoteIceMode(IceMode mode) override { + RTC_DCHECK_RUN_ON(network_thread_); + remote_ice_mode_ = mode; + } + + void MaybeStartGathering() override { + RTC_DCHECK_RUN_ON(network_thread_); + if (gathering_state_ == kIceGatheringNew) { + gathering_state_ = kIceGatheringGathering; + SignalGatheringState(this); + } + } + + IceGatheringState gathering_state() const override { + RTC_DCHECK_RUN_ON(network_thread_); + return gathering_state_; + } + + void SetIceConfig(const IceConfig& config) override { + RTC_DCHECK_RUN_ON(network_thread_); + ice_config_ = config; + } + + void AddRemoteCandidate(const Candidate& candidate) override { + RTC_DCHECK_RUN_ON(network_thread_); + remote_candidates_.push_back(candidate); + } + void RemoveRemoteCandidate(const Candidate& candidate) override { + RTC_DCHECK_RUN_ON(network_thread_); + auto it = absl::c_find(remote_candidates_, candidate); + if (it == remote_candidates_.end()) { + RTC_LOG(LS_INFO) << "Trying to remove a candidate which doesn't exist."; + return; + } + + remote_candidates_.erase(it); + } + + void RemoveAllRemoteCandidates() override { + RTC_DCHECK_RUN_ON(network_thread_); + remote_candidates_.clear(); + } + + bool GetStats(IceTransportStats* ice_transport_stats) override { + CandidateStats candidate_stats; + ConnectionInfo candidate_pair_stats; + ice_transport_stats->candidate_stats_list.clear(); + ice_transport_stats->candidate_stats_list.push_back(candidate_stats); + ice_transport_stats->connection_infos.clear(); + ice_transport_stats->connection_infos.push_back(candidate_pair_stats); + return true; + } + + absl::optional<int> GetRttEstimate() override { return absl::nullopt; } + + const Connection* selected_connection() const override { return nullptr; } + absl::optional<const CandidatePair> GetSelectedCandidatePair() + const override { + return absl::nullopt; + } + + // Fake PacketTransportInternal implementation. + bool writable() const override { + RTC_DCHECK_RUN_ON(network_thread_); + return writable_; + } + bool receiving() const override { + RTC_DCHECK_RUN_ON(network_thread_); + return receiving_; + } + // If combine is enabled, every two consecutive packets to be sent with + // "SendPacket" will be combined into one outgoing packet. + void combine_outgoing_packets(bool combine) { + RTC_DCHECK_RUN_ON(network_thread_); + combine_outgoing_packets_ = combine; + } + int SendPacket(const char* data, + size_t len, + const rtc::PacketOptions& options, + int flags) override { + RTC_DCHECK_RUN_ON(network_thread_); + if (!dest_) { + return -1; + } + + send_packet_.AppendData(data, len); + if (!combine_outgoing_packets_ || send_packet_.size() > len) { + rtc::CopyOnWriteBuffer packet(std::move(send_packet_)); + if (async_) { + network_thread_->PostDelayedTask( + SafeTask(task_safety_.flag(), + [this, packet] { + RTC_DCHECK_RUN_ON(network_thread_); + FakeIceTransport::SendPacketInternal(packet); + }), + TimeDelta::Millis(async_delay_ms_)); + } else { + SendPacketInternal(packet); + } + } + rtc::SentPacket sent_packet(options.packet_id, rtc::TimeMillis()); + SignalSentPacket(this, sent_packet); + return static_cast<int>(len); + } + + int SetOption(rtc::Socket::Option opt, int value) override { + RTC_DCHECK_RUN_ON(network_thread_); + socket_options_[opt] = value; + return true; + } + bool GetOption(rtc::Socket::Option opt, int* value) override { + RTC_DCHECK_RUN_ON(network_thread_); + auto it = socket_options_.find(opt); + if (it != socket_options_.end()) { + *value = it->second; + return true; + } else { + return false; + } + } + + int GetError() override { return 0; } + + rtc::CopyOnWriteBuffer last_sent_packet() { + RTC_DCHECK_RUN_ON(network_thread_); + return last_sent_packet_; + } + + absl::optional<rtc::NetworkRoute> network_route() const override { + RTC_DCHECK_RUN_ON(network_thread_); + return network_route_; + } + void SetNetworkRoute(absl::optional<rtc::NetworkRoute> network_route) { + RTC_DCHECK_RUN_ON(network_thread_); + network_route_ = network_route; + SendTask(network_thread_, [this] { + RTC_DCHECK_RUN_ON(network_thread_); + SignalNetworkRouteChanged(network_route_); + }); + } + + private: + void set_writable(bool writable) + RTC_EXCLUSIVE_LOCKS_REQUIRED(network_thread_) { + if (writable_ == writable) { + return; + } + RTC_LOG(LS_INFO) << "Change writable_ to " << writable; + writable_ = writable; + if (writable_) { + SignalReadyToSend(this); + } + SignalWritableState(this); + } + + void set_receiving(bool receiving) + RTC_EXCLUSIVE_LOCKS_REQUIRED(network_thread_) { + if (receiving_ == receiving) { + return; + } + receiving_ = receiving; + SignalReceivingState(this); + } + + void SendPacketInternal(const rtc::CopyOnWriteBuffer& packet) + RTC_EXCLUSIVE_LOCKS_REQUIRED(network_thread_) { + if (dest_) { + last_sent_packet_ = packet; + dest_->SignalReadPacket(dest_, packet.data<char>(), packet.size(), + rtc::TimeMicros(), 0); + } + } + + const std::string name_; + const int component_; + FakeIceTransport* dest_ RTC_GUARDED_BY(network_thread_) = nullptr; + bool async_ RTC_GUARDED_BY(network_thread_) = false; + int async_delay_ms_ RTC_GUARDED_BY(network_thread_) = 0; + Candidates remote_candidates_ RTC_GUARDED_BY(network_thread_); + IceConfig ice_config_ RTC_GUARDED_BY(network_thread_); + IceRole role_ RTC_GUARDED_BY(network_thread_) = ICEROLE_UNKNOWN; + uint64_t tiebreaker_ RTC_GUARDED_BY(network_thread_) = 0; + IceParameters ice_parameters_ RTC_GUARDED_BY(network_thread_); + IceParameters remote_ice_parameters_ RTC_GUARDED_BY(network_thread_); + IceMode remote_ice_mode_ RTC_GUARDED_BY(network_thread_) = ICEMODE_FULL; + size_t connection_count_ RTC_GUARDED_BY(network_thread_) = 0; + absl::optional<webrtc::IceTransportState> transport_state_ + RTC_GUARDED_BY(network_thread_); + absl::optional<IceTransportState> legacy_transport_state_ + RTC_GUARDED_BY(network_thread_); + IceGatheringState gathering_state_ RTC_GUARDED_BY(network_thread_) = + kIceGatheringNew; + bool had_connection_ RTC_GUARDED_BY(network_thread_) = false; + bool writable_ RTC_GUARDED_BY(network_thread_) = false; + bool receiving_ RTC_GUARDED_BY(network_thread_) = false; + bool combine_outgoing_packets_ RTC_GUARDED_BY(network_thread_) = false; + rtc::CopyOnWriteBuffer send_packet_ RTC_GUARDED_BY(network_thread_); + absl::optional<rtc::NetworkRoute> network_route_ + RTC_GUARDED_BY(network_thread_); + std::map<rtc::Socket::Option, int> socket_options_ + RTC_GUARDED_BY(network_thread_); + rtc::CopyOnWriteBuffer last_sent_packet_ RTC_GUARDED_BY(network_thread_); + rtc::Thread* const network_thread_; + webrtc::ScopedTaskSafetyDetached task_safety_; +}; + +class FakeIceTransportWrapper : public webrtc::IceTransportInterface { + public: + explicit FakeIceTransportWrapper( + std::unique_ptr<cricket::FakeIceTransport> internal) + : internal_(std::move(internal)) {} + + cricket::IceTransportInternal* internal() override { return internal_.get(); } + + private: + std::unique_ptr<cricket::FakeIceTransport> internal_; +}; + +} // namespace cricket + +#endif // P2P_BASE_FAKE_ICE_TRANSPORT_H_ |