/* * 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_PACKET_TRANSPORT_H_ #define P2P_BASE_FAKE_PACKET_TRANSPORT_H_ #include #include #include "p2p/base/packet_transport_internal.h" #include "rtc_base/async_invoker.h" #include "rtc_base/copy_on_write_buffer.h" namespace rtc { // Used to simulate a packet-based transport. class FakePacketTransport : public PacketTransportInternal { public: explicit FakePacketTransport(const std::string& transport_name) : transport_name_(transport_name) {} ~FakePacketTransport() 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) { async_ = async; } void SetAsyncDelay(int delay_ms) { 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) { set_writable(writable); } void SetReceiving(bool receiving) { set_receiving(receiving); } // Simulates the two transports connecting to each other. // If |asymmetric| is true this method only affects this FakePacketTransport. // If false, it affects |dest| as well. void SetDestination(FakePacketTransport* dest, bool asymmetric) { if (dest) { 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); } } // Fake PacketTransportInternal implementation. const std::string& transport_name() const override { return transport_name_; } bool writable() const override { return writable_; } bool receiving() const override { return receiving_; } int SendPacket(const char* data, size_t len, const PacketOptions& options, int flags) override { if (!dest_) { return -1; } CopyOnWriteBuffer packet(data, len); if (async_) { invoker_.AsyncInvokeDelayed( RTC_FROM_HERE, Thread::Current(), Bind(&FakePacketTransport::SendPacketInternal, this, packet), async_delay_ms_); } else { SendPacketInternal(packet); } SentPacket sent_packet(options.packet_id, TimeMillis()); SignalSentPacket(this, sent_packet); return static_cast(len); } int SetOption(Socket::Option opt, int value) override { options_[opt] = value; return 0; } bool GetOption(Socket::Option opt, int* value) override { auto it = options_.find(opt); if (it == options_.end()) { return false; } *value = it->second; return true; } int GetError() override { return error_; } void SetError(int error) { error_ = error; } const CopyOnWriteBuffer* last_sent_packet() { return &last_sent_packet_; } absl::optional network_route() const override { return network_route_; } void SetNetworkRoute(absl::optional network_route) { network_route_ = network_route; SignalNetworkRouteChanged(network_route); } private: void set_writable(bool writable) { if (writable_ == writable) { return; } writable_ = writable; if (writable_) { SignalReadyToSend(this); } SignalWritableState(this); } void set_receiving(bool receiving) { if (receiving_ == receiving) { return; } receiving_ = receiving; SignalReceivingState(this); } void SendPacketInternal(const CopyOnWriteBuffer& packet) { last_sent_packet_ = packet; if (dest_) { dest_->SignalReadPacket(dest_, packet.data(), packet.size(), TimeMicros(), 0); } } CopyOnWriteBuffer last_sent_packet_; AsyncInvoker invoker_; std::string transport_name_; FakePacketTransport* dest_ = nullptr; bool async_ = false; int async_delay_ms_ = 0; bool writable_ = false; bool receiving_ = false; std::map options_; int error_ = 0; absl::optional network_route_; }; } // namespace rtc #endif // P2P_BASE_FAKE_PACKET_TRANSPORT_H_