xref: /aosp_15_r20/external/webrtc/p2p/base/fake_ice_transport.h (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1 /*
2  *  Copyright 2017 The WebRTC Project Authors. All rights reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #ifndef P2P_BASE_FAKE_ICE_TRANSPORT_H_
12 #define P2P_BASE_FAKE_ICE_TRANSPORT_H_
13 
14 #include <map>
15 #include <memory>
16 #include <string>
17 #include <utility>
18 
19 #include "absl/algorithm/container.h"
20 #include "absl/strings/string_view.h"
21 #include "absl/types/optional.h"
22 #include "api/ice_transport_interface.h"
23 #include "api/task_queue/pending_task_safety_flag.h"
24 #include "api/units/time_delta.h"
25 #include "p2p/base/ice_transport_internal.h"
26 #include "rtc_base/copy_on_write_buffer.h"
27 #include "rtc_base/task_queue_for_test.h"
28 
29 namespace cricket {
30 using ::webrtc::SafeTask;
31 using ::webrtc::TimeDelta;
32 
33 // All methods must be called on the network thread (which is either the thread
34 // calling the constructor, or the separate thread explicitly passed to the
35 // constructor).
36 class FakeIceTransport : public IceTransportInternal {
37  public:
38   explicit FakeIceTransport(absl::string_view name,
39                             int component,
40                             rtc::Thread* network_thread = nullptr)
name_(name)41       : name_(name),
42         component_(component),
43         network_thread_(network_thread ? network_thread
44                                        : rtc::Thread::Current()) {
45     RTC_DCHECK(network_thread_);
46   }
47   // Must be called either on the network thread, or after the network thread
48   // has been shut down.
~FakeIceTransport()49   ~FakeIceTransport() override {
50     if (dest_ && dest_->dest_ == this) {
51       dest_->dest_ = nullptr;
52     }
53   }
54 
55   // If async, will send packets by "Post"-ing to message queue instead of
56   // synchronously "Send"-ing.
SetAsync(bool async)57   void SetAsync(bool async) {
58     RTC_DCHECK_RUN_ON(network_thread_);
59     async_ = async;
60   }
SetAsyncDelay(int delay_ms)61   void SetAsyncDelay(int delay_ms) {
62     RTC_DCHECK_RUN_ON(network_thread_);
63     async_delay_ms_ = delay_ms;
64   }
65 
66   // SetWritable, SetReceiving and SetDestination are the main methods that can
67   // be used for testing, to simulate connectivity or lack thereof.
SetWritable(bool writable)68   void SetWritable(bool writable) {
69     RTC_DCHECK_RUN_ON(network_thread_);
70     set_writable(writable);
71   }
SetReceiving(bool receiving)72   void SetReceiving(bool receiving) {
73     RTC_DCHECK_RUN_ON(network_thread_);
74     set_receiving(receiving);
75   }
76 
77   // Simulates the two transports connecting to each other.
78   // If `asymmetric` is true this method only affects this FakeIceTransport.
79   // If false, it affects `dest` as well.
80   void SetDestination(FakeIceTransport* dest, bool asymmetric = false) {
81     RTC_DCHECK_RUN_ON(network_thread_);
82     if (dest == dest_) {
83       return;
84     }
85     RTC_DCHECK(!dest || !dest_)
86         << "Changing fake destination from one to another is not supported.";
87     if (dest) {
88       // This simulates the delivery of candidates.
89       dest_ = dest;
90       set_writable(true);
91       if (!asymmetric) {
92         dest->SetDestination(this, true);
93       }
94     } else {
95       // Simulates loss of connectivity, by asymmetrically forgetting dest_.
96       dest_ = nullptr;
97       set_writable(false);
98     }
99   }
100 
SetTransportState(webrtc::IceTransportState state,IceTransportState legacy_state)101   void SetTransportState(webrtc::IceTransportState state,
102                          IceTransportState legacy_state) {
103     RTC_DCHECK_RUN_ON(network_thread_);
104     transport_state_ = state;
105     legacy_transport_state_ = legacy_state;
106     SignalIceTransportStateChanged(this);
107   }
108 
SetConnectionCount(size_t connection_count)109   void SetConnectionCount(size_t connection_count) {
110     RTC_DCHECK_RUN_ON(network_thread_);
111     size_t old_connection_count = connection_count_;
112     connection_count_ = connection_count;
113     if (connection_count) {
114       had_connection_ = true;
115     }
116     // In this fake transport channel, `connection_count_` determines the
117     // transport state.
118     if (connection_count_ < old_connection_count) {
119       SignalStateChanged(this);
120     }
121   }
122 
SetCandidatesGatheringComplete()123   void SetCandidatesGatheringComplete() {
124     RTC_DCHECK_RUN_ON(network_thread_);
125     if (gathering_state_ != kIceGatheringComplete) {
126       gathering_state_ = kIceGatheringComplete;
127       SignalGatheringState(this);
128     }
129   }
130 
131   // Convenience functions for accessing ICE config and other things.
receiving_timeout()132   int receiving_timeout() const {
133     RTC_DCHECK_RUN_ON(network_thread_);
134     return ice_config_.receiving_timeout_or_default();
135   }
gather_continually()136   bool gather_continually() const {
137     RTC_DCHECK_RUN_ON(network_thread_);
138     return ice_config_.gather_continually();
139   }
remote_candidates()140   const Candidates& remote_candidates() const {
141     RTC_DCHECK_RUN_ON(network_thread_);
142     return remote_candidates_;
143   }
144 
145   // Fake IceTransportInternal implementation.
transport_name()146   const std::string& transport_name() const override { return name_; }
component()147   int component() const override { return component_; }
IceTiebreaker()148   uint64_t IceTiebreaker() const {
149     RTC_DCHECK_RUN_ON(network_thread_);
150     return tiebreaker_;
151   }
remote_ice_mode()152   IceMode remote_ice_mode() const {
153     RTC_DCHECK_RUN_ON(network_thread_);
154     return remote_ice_mode_;
155   }
ice_ufrag()156   const std::string& ice_ufrag() const { return ice_parameters_.ufrag; }
ice_pwd()157   const std::string& ice_pwd() const { return ice_parameters_.pwd; }
remote_ice_ufrag()158   const std::string& remote_ice_ufrag() const {
159     return remote_ice_parameters_.ufrag;
160   }
remote_ice_pwd()161   const std::string& remote_ice_pwd() const {
162     return remote_ice_parameters_.pwd;
163   }
ice_parameters()164   const IceParameters& ice_parameters() const { return ice_parameters_; }
remote_ice_parameters()165   const IceParameters& remote_ice_parameters() const {
166     return remote_ice_parameters_;
167   }
168 
GetState()169   IceTransportState GetState() const override {
170     RTC_DCHECK_RUN_ON(network_thread_);
171     if (legacy_transport_state_) {
172       return *legacy_transport_state_;
173     }
174 
175     if (connection_count_ == 0) {
176       return had_connection_ ? IceTransportState::STATE_FAILED
177                              : IceTransportState::STATE_INIT;
178     }
179 
180     if (connection_count_ == 1) {
181       return IceTransportState::STATE_COMPLETED;
182     }
183 
184     return IceTransportState::STATE_CONNECTING;
185   }
186 
GetIceTransportState()187   webrtc::IceTransportState GetIceTransportState() const override {
188     RTC_DCHECK_RUN_ON(network_thread_);
189     if (transport_state_) {
190       return *transport_state_;
191     }
192 
193     if (connection_count_ == 0) {
194       return had_connection_ ? webrtc::IceTransportState::kFailed
195                              : webrtc::IceTransportState::kNew;
196     }
197 
198     if (connection_count_ == 1) {
199       return webrtc::IceTransportState::kCompleted;
200     }
201 
202     return webrtc::IceTransportState::kConnected;
203   }
204 
SetIceRole(IceRole role)205   void SetIceRole(IceRole role) override {
206     RTC_DCHECK_RUN_ON(network_thread_);
207     role_ = role;
208   }
GetIceRole()209   IceRole GetIceRole() const override {
210     RTC_DCHECK_RUN_ON(network_thread_);
211     return role_;
212   }
SetIceTiebreaker(uint64_t tiebreaker)213   void SetIceTiebreaker(uint64_t tiebreaker) override {
214     RTC_DCHECK_RUN_ON(network_thread_);
215     tiebreaker_ = tiebreaker;
216   }
SetIceParameters(const IceParameters & ice_params)217   void SetIceParameters(const IceParameters& ice_params) override {
218     RTC_DCHECK_RUN_ON(network_thread_);
219     ice_parameters_ = ice_params;
220   }
SetRemoteIceParameters(const IceParameters & params)221   void SetRemoteIceParameters(const IceParameters& params) override {
222     RTC_DCHECK_RUN_ON(network_thread_);
223     remote_ice_parameters_ = params;
224   }
225 
SetRemoteIceMode(IceMode mode)226   void SetRemoteIceMode(IceMode mode) override {
227     RTC_DCHECK_RUN_ON(network_thread_);
228     remote_ice_mode_ = mode;
229   }
230 
MaybeStartGathering()231   void MaybeStartGathering() override {
232     RTC_DCHECK_RUN_ON(network_thread_);
233     if (gathering_state_ == kIceGatheringNew) {
234       gathering_state_ = kIceGatheringGathering;
235       SignalGatheringState(this);
236     }
237   }
238 
gathering_state()239   IceGatheringState gathering_state() const override {
240     RTC_DCHECK_RUN_ON(network_thread_);
241     return gathering_state_;
242   }
243 
SetIceConfig(const IceConfig & config)244   void SetIceConfig(const IceConfig& config) override {
245     RTC_DCHECK_RUN_ON(network_thread_);
246     ice_config_ = config;
247   }
248 
AddRemoteCandidate(const Candidate & candidate)249   void AddRemoteCandidate(const Candidate& candidate) override {
250     RTC_DCHECK_RUN_ON(network_thread_);
251     remote_candidates_.push_back(candidate);
252   }
RemoveRemoteCandidate(const Candidate & candidate)253   void RemoveRemoteCandidate(const Candidate& candidate) override {
254     RTC_DCHECK_RUN_ON(network_thread_);
255     auto it = absl::c_find(remote_candidates_, candidate);
256     if (it == remote_candidates_.end()) {
257       RTC_LOG(LS_INFO) << "Trying to remove a candidate which doesn't exist.";
258       return;
259     }
260 
261     remote_candidates_.erase(it);
262   }
263 
RemoveAllRemoteCandidates()264   void RemoveAllRemoteCandidates() override {
265     RTC_DCHECK_RUN_ON(network_thread_);
266     remote_candidates_.clear();
267   }
268 
GetStats(IceTransportStats * ice_transport_stats)269   bool GetStats(IceTransportStats* ice_transport_stats) override {
270     CandidateStats candidate_stats;
271     ConnectionInfo candidate_pair_stats;
272     ice_transport_stats->candidate_stats_list.clear();
273     ice_transport_stats->candidate_stats_list.push_back(candidate_stats);
274     ice_transport_stats->connection_infos.clear();
275     ice_transport_stats->connection_infos.push_back(candidate_pair_stats);
276     return true;
277   }
278 
GetRttEstimate()279   absl::optional<int> GetRttEstimate() override { return absl::nullopt; }
280 
selected_connection()281   const Connection* selected_connection() const override { return nullptr; }
GetSelectedCandidatePair()282   absl::optional<const CandidatePair> GetSelectedCandidatePair()
283       const override {
284     return absl::nullopt;
285   }
286 
287   // Fake PacketTransportInternal implementation.
writable()288   bool writable() const override {
289     RTC_DCHECK_RUN_ON(network_thread_);
290     return writable_;
291   }
receiving()292   bool receiving() const override {
293     RTC_DCHECK_RUN_ON(network_thread_);
294     return receiving_;
295   }
296   // If combine is enabled, every two consecutive packets to be sent with
297   // "SendPacket" will be combined into one outgoing packet.
combine_outgoing_packets(bool combine)298   void combine_outgoing_packets(bool combine) {
299     RTC_DCHECK_RUN_ON(network_thread_);
300     combine_outgoing_packets_ = combine;
301   }
SendPacket(const char * data,size_t len,const rtc::PacketOptions & options,int flags)302   int SendPacket(const char* data,
303                  size_t len,
304                  const rtc::PacketOptions& options,
305                  int flags) override {
306     RTC_DCHECK_RUN_ON(network_thread_);
307     if (!dest_) {
308       return -1;
309     }
310 
311     send_packet_.AppendData(data, len);
312     if (!combine_outgoing_packets_ || send_packet_.size() > len) {
313       rtc::CopyOnWriteBuffer packet(std::move(send_packet_));
314       if (async_) {
315         network_thread_->PostDelayedTask(
316             SafeTask(task_safety_.flag(),
317                      [this, packet] {
318                        RTC_DCHECK_RUN_ON(network_thread_);
319                        FakeIceTransport::SendPacketInternal(packet);
320                      }),
321             TimeDelta::Millis(async_delay_ms_));
322       } else {
323         SendPacketInternal(packet);
324       }
325     }
326     rtc::SentPacket sent_packet(options.packet_id, rtc::TimeMillis());
327     SignalSentPacket(this, sent_packet);
328     return static_cast<int>(len);
329   }
330 
SetOption(rtc::Socket::Option opt,int value)331   int SetOption(rtc::Socket::Option opt, int value) override {
332     RTC_DCHECK_RUN_ON(network_thread_);
333     socket_options_[opt] = value;
334     return true;
335   }
GetOption(rtc::Socket::Option opt,int * value)336   bool GetOption(rtc::Socket::Option opt, int* value) override {
337     RTC_DCHECK_RUN_ON(network_thread_);
338     auto it = socket_options_.find(opt);
339     if (it != socket_options_.end()) {
340       *value = it->second;
341       return true;
342     } else {
343       return false;
344     }
345   }
346 
GetError()347   int GetError() override { return 0; }
348 
last_sent_packet()349   rtc::CopyOnWriteBuffer last_sent_packet() {
350     RTC_DCHECK_RUN_ON(network_thread_);
351     return last_sent_packet_;
352   }
353 
network_route()354   absl::optional<rtc::NetworkRoute> network_route() const override {
355     RTC_DCHECK_RUN_ON(network_thread_);
356     return network_route_;
357   }
SetNetworkRoute(absl::optional<rtc::NetworkRoute> network_route)358   void SetNetworkRoute(absl::optional<rtc::NetworkRoute> network_route) {
359     RTC_DCHECK_RUN_ON(network_thread_);
360     network_route_ = network_route;
361     SendTask(network_thread_, [this] {
362       RTC_DCHECK_RUN_ON(network_thread_);
363       SignalNetworkRouteChanged(network_route_);
364     });
365   }
366 
367  private:
set_writable(bool writable)368   void set_writable(bool writable)
369       RTC_EXCLUSIVE_LOCKS_REQUIRED(network_thread_) {
370     if (writable_ == writable) {
371       return;
372     }
373     RTC_LOG(LS_INFO) << "Change writable_ to " << writable;
374     writable_ = writable;
375     if (writable_) {
376       SignalReadyToSend(this);
377     }
378     SignalWritableState(this);
379   }
380 
set_receiving(bool receiving)381   void set_receiving(bool receiving)
382       RTC_EXCLUSIVE_LOCKS_REQUIRED(network_thread_) {
383     if (receiving_ == receiving) {
384       return;
385     }
386     receiving_ = receiving;
387     SignalReceivingState(this);
388   }
389 
SendPacketInternal(const rtc::CopyOnWriteBuffer & packet)390   void SendPacketInternal(const rtc::CopyOnWriteBuffer& packet)
391       RTC_EXCLUSIVE_LOCKS_REQUIRED(network_thread_) {
392     if (dest_) {
393       last_sent_packet_ = packet;
394       dest_->SignalReadPacket(dest_, packet.data<char>(), packet.size(),
395                               rtc::TimeMicros(), 0);
396     }
397   }
398 
399   const std::string name_;
400   const int component_;
401   FakeIceTransport* dest_ RTC_GUARDED_BY(network_thread_) = nullptr;
402   bool async_ RTC_GUARDED_BY(network_thread_) = false;
403   int async_delay_ms_ RTC_GUARDED_BY(network_thread_) = 0;
404   Candidates remote_candidates_ RTC_GUARDED_BY(network_thread_);
405   IceConfig ice_config_ RTC_GUARDED_BY(network_thread_);
406   IceRole role_ RTC_GUARDED_BY(network_thread_) = ICEROLE_UNKNOWN;
407   uint64_t tiebreaker_ RTC_GUARDED_BY(network_thread_) = 0;
408   IceParameters ice_parameters_ RTC_GUARDED_BY(network_thread_);
409   IceParameters remote_ice_parameters_ RTC_GUARDED_BY(network_thread_);
410   IceMode remote_ice_mode_ RTC_GUARDED_BY(network_thread_) = ICEMODE_FULL;
411   size_t connection_count_ RTC_GUARDED_BY(network_thread_) = 0;
412   absl::optional<webrtc::IceTransportState> transport_state_
413       RTC_GUARDED_BY(network_thread_);
414   absl::optional<IceTransportState> legacy_transport_state_
415       RTC_GUARDED_BY(network_thread_);
416   IceGatheringState gathering_state_ RTC_GUARDED_BY(network_thread_) =
417       kIceGatheringNew;
418   bool had_connection_ RTC_GUARDED_BY(network_thread_) = false;
419   bool writable_ RTC_GUARDED_BY(network_thread_) = false;
420   bool receiving_ RTC_GUARDED_BY(network_thread_) = false;
421   bool combine_outgoing_packets_ RTC_GUARDED_BY(network_thread_) = false;
422   rtc::CopyOnWriteBuffer send_packet_ RTC_GUARDED_BY(network_thread_);
423   absl::optional<rtc::NetworkRoute> network_route_
424       RTC_GUARDED_BY(network_thread_);
425   std::map<rtc::Socket::Option, int> socket_options_
426       RTC_GUARDED_BY(network_thread_);
427   rtc::CopyOnWriteBuffer last_sent_packet_ RTC_GUARDED_BY(network_thread_);
428   rtc::Thread* const network_thread_;
429   webrtc::ScopedTaskSafetyDetached task_safety_;
430 };
431 
432 class FakeIceTransportWrapper : public webrtc::IceTransportInterface {
433  public:
FakeIceTransportWrapper(std::unique_ptr<cricket::FakeIceTransport> internal)434   explicit FakeIceTransportWrapper(
435       std::unique_ptr<cricket::FakeIceTransport> internal)
436       : internal_(std::move(internal)) {}
437 
internal()438   cricket::IceTransportInternal* internal() override { return internal_.get(); }
439 
440  private:
441   std::unique_ptr<cricket::FakeIceTransport> internal_;
442 };
443 
444 }  // namespace cricket
445 
446 #endif  // P2P_BASE_FAKE_ICE_TRANSPORT_H_
447