1 /*
2 * Copyright 2004 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 #include "p2p/base/p2p_transport_channel.h"
12
13 #include <errno.h>
14 #include <stdlib.h>
15
16 #include <algorithm>
17 #include <functional>
18 #include <memory>
19 #include <set>
20 #include <utility>
21
22 #include "absl/algorithm/container.h"
23 #include "absl/memory/memory.h"
24 #include "absl/strings/match.h"
25 #include "absl/strings/string_view.h"
26 #include "api/async_dns_resolver.h"
27 #include "api/candidate.h"
28 #include "api/field_trials_view.h"
29 #include "api/units/time_delta.h"
30 #include "logging/rtc_event_log/ice_logger.h"
31 #include "p2p/base/basic_async_resolver_factory.h"
32 #include "p2p/base/basic_ice_controller.h"
33 #include "p2p/base/connection.h"
34 #include "p2p/base/connection_info.h"
35 #include "p2p/base/port.h"
36 #include "p2p/base/wrapping_active_ice_controller.h"
37 #include "rtc_base/checks.h"
38 #include "rtc_base/crc32.h"
39 #include "rtc_base/experiments/struct_parameters_parser.h"
40 #include "rtc_base/ip_address.h"
41 #include "rtc_base/logging.h"
42 #include "rtc_base/net_helper.h"
43 #include "rtc_base/network.h"
44 #include "rtc_base/network_constants.h"
45 #include "rtc_base/string_encode.h"
46 #include "rtc_base/third_party/sigslot/sigslot.h"
47 #include "rtc_base/time_utils.h"
48 #include "rtc_base/trace_event.h"
49 #include "system_wrappers/include/metrics.h"
50
51 namespace {
52
GetOrigin(cricket::PortInterface * port,cricket::PortInterface * origin_port)53 cricket::PortInterface::CandidateOrigin GetOrigin(
54 cricket::PortInterface* port,
55 cricket::PortInterface* origin_port) {
56 if (!origin_port)
57 return cricket::PortInterface::ORIGIN_MESSAGE;
58 else if (port == origin_port)
59 return cricket::PortInterface::ORIGIN_THIS_PORT;
60 else
61 return cricket::PortInterface::ORIGIN_OTHER_PORT;
62 }
63
GetWeakPingIntervalInFieldTrial(const webrtc::FieldTrialsView * field_trials)64 uint32_t GetWeakPingIntervalInFieldTrial(
65 const webrtc::FieldTrialsView* field_trials) {
66 if (field_trials != nullptr) {
67 uint32_t weak_ping_interval =
68 ::strtoul(field_trials->Lookup("WebRTC-StunInterPacketDelay").c_str(),
69 nullptr, 10);
70 if (weak_ping_interval) {
71 return static_cast<int>(weak_ping_interval);
72 }
73 }
74 return cricket::WEAK_PING_INTERVAL;
75 }
76
CreateRouteEndpointFromCandidate(bool local,const cricket::Candidate & candidate,bool uses_turn)77 rtc::RouteEndpoint CreateRouteEndpointFromCandidate(
78 bool local,
79 const cricket::Candidate& candidate,
80 bool uses_turn) {
81 auto adapter_type = candidate.network_type();
82 if (!local && adapter_type == rtc::ADAPTER_TYPE_UNKNOWN) {
83 bool vpn;
84 std::tie(adapter_type, vpn) =
85 rtc::Network::GuessAdapterFromNetworkCost(candidate.network_cost());
86 }
87
88 // TODO(bugs.webrtc.org/9446) : Rewrite if information about remote network
89 // adapter becomes available. The implication of this implementation is that
90 // we will only ever report 1 adapter per type. In practice this is probably
91 // fine, since the endpoint also contains network-id.
92 uint16_t adapter_id = static_cast<int>(adapter_type);
93 return rtc::RouteEndpoint(adapter_type, adapter_id, candidate.network_id(),
94 uses_turn);
95 }
96
UseActiveIceControllerFieldTrialEnabled(const webrtc::FieldTrialsView * field_trials)97 bool UseActiveIceControllerFieldTrialEnabled(
98 const webrtc::FieldTrialsView* field_trials) {
99 // Feature to refactor ICE controller and enable active ICE controllers.
100 // Field trial key reserved in bugs.webrtc.org/14367
101 return field_trials &&
102 field_trials->IsEnabled("WebRTC-UseActiveIceController");
103 }
104
105 using ::webrtc::RTCError;
106 using ::webrtc::RTCErrorType;
107 using ::webrtc::SafeTask;
108 using ::webrtc::TimeDelta;
109
110 } // unnamed namespace
111
112 namespace cricket {
113
IceCredentialsChanged(absl::string_view old_ufrag,absl::string_view old_pwd,absl::string_view new_ufrag,absl::string_view new_pwd)114 bool IceCredentialsChanged(absl::string_view old_ufrag,
115 absl::string_view old_pwd,
116 absl::string_view new_ufrag,
117 absl::string_view new_pwd) {
118 // The standard (RFC 5245 Section 9.1.1.1) says that ICE restarts MUST change
119 // both the ufrag and password. However, section 9.2.1.1 says changing the
120 // ufrag OR password indicates an ICE restart. So, to keep compatibility with
121 // endpoints that only change one, we'll treat this as an ICE restart.
122 return (old_ufrag != new_ufrag) || (old_pwd != new_pwd);
123 }
124
Create(absl::string_view transport_name,int component,webrtc::IceTransportInit init)125 std::unique_ptr<P2PTransportChannel> P2PTransportChannel::Create(
126 absl::string_view transport_name,
127 int component,
128 webrtc::IceTransportInit init) {
129 if (init.async_resolver_factory()) {
130 return absl::WrapUnique(new P2PTransportChannel(
131 transport_name, component, init.port_allocator(), nullptr,
132 std::make_unique<webrtc::WrappingAsyncDnsResolverFactory>(
133 init.async_resolver_factory()),
134 init.event_log(), init.ice_controller_factory(),
135 init.active_ice_controller_factory(), init.field_trials()));
136 } else {
137 return absl::WrapUnique(new P2PTransportChannel(
138 transport_name, component, init.port_allocator(),
139 init.async_dns_resolver_factory(), nullptr, init.event_log(),
140 init.ice_controller_factory(), init.active_ice_controller_factory(),
141 init.field_trials()));
142 }
143 }
144
P2PTransportChannel(absl::string_view transport_name,int component,PortAllocator * allocator,const webrtc::FieldTrialsView * field_trials)145 P2PTransportChannel::P2PTransportChannel(
146 absl::string_view transport_name,
147 int component,
148 PortAllocator* allocator,
149 const webrtc::FieldTrialsView* field_trials)
150 : P2PTransportChannel(transport_name,
151 component,
152 allocator,
153 /* async_dns_resolver_factory= */ nullptr,
154 /* owned_dns_resolver_factory= */ nullptr,
155 /* event_log= */ nullptr,
156 /* ice_controller_factory= */ nullptr,
157 /* active_ice_controller_factory= */ nullptr,
158 field_trials) {}
159
160 // Private constructor, called from Create()
P2PTransportChannel(absl::string_view transport_name,int component,PortAllocator * allocator,webrtc::AsyncDnsResolverFactoryInterface * async_dns_resolver_factory,std::unique_ptr<webrtc::AsyncDnsResolverFactoryInterface> owned_dns_resolver_factory,webrtc::RtcEventLog * event_log,IceControllerFactoryInterface * ice_controller_factory,ActiveIceControllerFactoryInterface * active_ice_controller_factory,const webrtc::FieldTrialsView * field_trials)161 P2PTransportChannel::P2PTransportChannel(
162 absl::string_view transport_name,
163 int component,
164 PortAllocator* allocator,
165 webrtc::AsyncDnsResolverFactoryInterface* async_dns_resolver_factory,
166 std::unique_ptr<webrtc::AsyncDnsResolverFactoryInterface>
167 owned_dns_resolver_factory,
168 webrtc::RtcEventLog* event_log,
169 IceControllerFactoryInterface* ice_controller_factory,
170 ActiveIceControllerFactoryInterface* active_ice_controller_factory,
171 const webrtc::FieldTrialsView* field_trials)
172 : transport_name_(transport_name),
173 component_(component),
174 allocator_(allocator),
175 // If owned_dns_resolver_factory is given, async_dns_resolver_factory is
176 // ignored.
177 async_dns_resolver_factory_(owned_dns_resolver_factory
178 ? owned_dns_resolver_factory.get()
179 : async_dns_resolver_factory),
180 owned_dns_resolver_factory_(std::move(owned_dns_resolver_factory)),
181 network_thread_(rtc::Thread::Current()),
182 incoming_only_(false),
183 error_(0),
184 sort_dirty_(false),
185 remote_ice_mode_(ICEMODE_FULL),
186 ice_role_(ICEROLE_UNKNOWN),
187 tiebreaker_(0),
188 gathering_state_(kIceGatheringNew),
189 weak_ping_interval_(GetWeakPingIntervalInFieldTrial(field_trials)),
190 config_(RECEIVING_TIMEOUT,
191 BACKUP_CONNECTION_PING_INTERVAL,
192 GATHER_ONCE /* continual_gathering_policy */,
193 false /* prioritize_most_likely_candidate_pairs */,
194 STRONG_AND_STABLE_WRITABLE_CONNECTION_PING_INTERVAL,
195 true /* presume_writable_when_fully_relayed */,
196 REGATHER_ON_FAILED_NETWORKS_INTERVAL,
197 RECEIVING_SWITCHING_DELAY) {
198 TRACE_EVENT0("webrtc", "P2PTransportChannel::P2PTransportChannel");
199 RTC_DCHECK(allocator_ != nullptr);
200 // Validate IceConfig even for mostly built-in constant default values in case
201 // we change them.
202 RTC_DCHECK(ValidateIceConfig(config_).ok());
203 webrtc::BasicRegatheringController::Config regathering_config;
204 regathering_config.regather_on_failed_networks_interval =
205 config_.regather_on_failed_networks_interval_or_default();
206 regathering_controller_ =
207 std::make_unique<webrtc::BasicRegatheringController>(
208 regathering_config, this, network_thread_);
209 // We populate the change in the candidate filter to the session taken by
210 // the transport.
211 allocator_->SignalCandidateFilterChanged.connect(
212 this, &P2PTransportChannel::OnCandidateFilterChanged);
213 ice_event_log_.set_event_log(event_log);
214
215 ParseFieldTrials(field_trials);
216
217 IceControllerFactoryArgs args{
218 [this] { return GetState(); }, [this] { return GetIceRole(); },
219 [this](const Connection* connection) {
220 return IsPortPruned(connection->port()) ||
221 IsRemoteCandidatePruned(connection->remote_candidate());
222 },
223 &ice_field_trials_,
224 field_trials ? field_trials->Lookup("WebRTC-IceControllerFieldTrials")
225 : ""};
226 ice_adapter_ = std::make_unique<IceControllerAdapter>(
227 args, ice_controller_factory, active_ice_controller_factory, field_trials,
228 /* transport= */ this);
229 }
230
~P2PTransportChannel()231 P2PTransportChannel::~P2PTransportChannel() {
232 TRACE_EVENT0("webrtc", "P2PTransportChannel::~P2PTransportChannel");
233 RTC_DCHECK_RUN_ON(network_thread_);
234 std::vector<Connection*> copy(connections().begin(), connections().end());
235 for (Connection* connection : copy) {
236 connection->SignalDestroyed.disconnect(this);
237 RemoveConnection(connection);
238 connection->Destroy();
239 }
240 resolvers_.clear();
241 }
242
243 // Add the allocator session to our list so that we know which sessions
244 // are still active.
AddAllocatorSession(std::unique_ptr<PortAllocatorSession> session)245 void P2PTransportChannel::AddAllocatorSession(
246 std::unique_ptr<PortAllocatorSession> session) {
247 RTC_DCHECK_RUN_ON(network_thread_);
248
249 session->set_generation(static_cast<uint32_t>(allocator_sessions_.size()));
250 session->SignalPortReady.connect(this, &P2PTransportChannel::OnPortReady);
251 session->SignalPortsPruned.connect(this, &P2PTransportChannel::OnPortsPruned);
252 session->SignalCandidatesReady.connect(
253 this, &P2PTransportChannel::OnCandidatesReady);
254 session->SignalCandidateError.connect(this,
255 &P2PTransportChannel::OnCandidateError);
256 session->SignalCandidatesRemoved.connect(
257 this, &P2PTransportChannel::OnCandidatesRemoved);
258 session->SignalCandidatesAllocationDone.connect(
259 this, &P2PTransportChannel::OnCandidatesAllocationDone);
260 if (!allocator_sessions_.empty()) {
261 allocator_session()->PruneAllPorts();
262 }
263 allocator_sessions_.push_back(std::move(session));
264 regathering_controller_->set_allocator_session(allocator_session());
265
266 // We now only want to apply new candidates that we receive to the ports
267 // created by this new session because these are replacing those of the
268 // previous sessions.
269 PruneAllPorts();
270 }
271
AddConnection(Connection * connection)272 void P2PTransportChannel::AddConnection(Connection* connection) {
273 RTC_DCHECK_RUN_ON(network_thread_);
274 connection->set_receiving_timeout(config_.receiving_timeout);
275 connection->set_unwritable_timeout(config_.ice_unwritable_timeout);
276 connection->set_unwritable_min_checks(config_.ice_unwritable_min_checks);
277 connection->set_inactive_timeout(config_.ice_inactive_timeout);
278 connection->SignalReadPacket.connect(this,
279 &P2PTransportChannel::OnReadPacket);
280 connection->SignalReadyToSend.connect(this,
281 &P2PTransportChannel::OnReadyToSend);
282 connection->SignalStateChange.connect(
283 this, &P2PTransportChannel::OnConnectionStateChange);
284 connection->SignalDestroyed.connect(
285 this, &P2PTransportChannel::OnConnectionDestroyed);
286 connection->SignalNominated.connect(this, &P2PTransportChannel::OnNominated);
287
288 had_connection_ = true;
289
290 connection->set_ice_event_log(&ice_event_log_);
291 connection->SetIceFieldTrials(&ice_field_trials_);
292 LogCandidatePairConfig(connection,
293 webrtc::IceCandidatePairConfigType::kAdded);
294
295 connections_.push_back(connection);
296 ice_adapter_->OnConnectionAdded(connection);
297 }
298
299 // TODO(bugs.webrtc.org/14367) remove once refactor lands.
MaybeSwitchSelectedConnection(const Connection * new_connection,IceSwitchReason reason)300 bool P2PTransportChannel::MaybeSwitchSelectedConnection(
301 const Connection* new_connection,
302 IceSwitchReason reason) {
303 RTC_DCHECK_RUN_ON(network_thread_);
304
305 return MaybeSwitchSelectedConnection(
306 reason,
307 ice_adapter_->LegacyShouldSwitchConnection(reason, new_connection));
308 }
309
310 // TODO(bugs.webrtc.org/14367) remove once refactor lands.
MaybeSwitchSelectedConnection(IceSwitchReason reason,IceControllerInterface::SwitchResult result)311 bool P2PTransportChannel::MaybeSwitchSelectedConnection(
312 IceSwitchReason reason,
313 IceControllerInterface::SwitchResult result) {
314 RTC_DCHECK_RUN_ON(network_thread_);
315 if (result.connection.has_value()) {
316 RTC_LOG(LS_INFO) << "Switching selected connection due to: "
317 << IceSwitchReasonToString(reason);
318 SwitchSelectedConnection(FromIceController(*result.connection), reason);
319 }
320
321 if (result.recheck_event.has_value()) {
322 // If we do not switch to the connection because it missed the receiving
323 // threshold, the new connection is in a better receiving state than the
324 // currently selected connection. So we need to re-check whether it needs
325 // to be switched at a later time.
326 network_thread_->PostDelayedTask(
327 SafeTask(task_safety_.flag(),
328 [this, reason = result.recheck_event->reason]() {
329 SortConnectionsAndUpdateState(reason);
330 }),
331 TimeDelta::Millis(result.recheck_event->recheck_delay_ms));
332 }
333
334 for (const auto* con : result.connections_to_forget_state_on) {
335 FromIceController(con)->ForgetLearnedState();
336 }
337
338 return result.connection.has_value();
339 }
340
ForgetLearnedStateForConnections(rtc::ArrayView<const Connection * const> connections)341 void P2PTransportChannel::ForgetLearnedStateForConnections(
342 rtc::ArrayView<const Connection* const> connections) {
343 for (const Connection* con : connections) {
344 FromIceController(con)->ForgetLearnedState();
345 }
346 }
347
SetIceRole(IceRole ice_role)348 void P2PTransportChannel::SetIceRole(IceRole ice_role) {
349 RTC_DCHECK_RUN_ON(network_thread_);
350 if (ice_role_ != ice_role) {
351 ice_role_ = ice_role;
352 for (PortInterface* port : ports_) {
353 port->SetIceRole(ice_role);
354 }
355 // Update role on pruned ports as well, because they may still have
356 // connections alive that should be using the correct role.
357 for (PortInterface* port : pruned_ports_) {
358 port->SetIceRole(ice_role);
359 }
360 }
361 }
362
GetIceRole() const363 IceRole P2PTransportChannel::GetIceRole() const {
364 RTC_DCHECK_RUN_ON(network_thread_);
365 return ice_role_;
366 }
367
SetIceTiebreaker(uint64_t tiebreaker)368 void P2PTransportChannel::SetIceTiebreaker(uint64_t tiebreaker) {
369 RTC_DCHECK_RUN_ON(network_thread_);
370 if (!ports_.empty() || !pruned_ports_.empty()) {
371 RTC_LOG(LS_ERROR)
372 << "Attempt to change tiebreaker after Port has been allocated.";
373 return;
374 }
375
376 tiebreaker_ = tiebreaker;
377 }
378
GetState() const379 IceTransportState P2PTransportChannel::GetState() const {
380 RTC_DCHECK_RUN_ON(network_thread_);
381 return state_;
382 }
383
GetIceTransportState() const384 webrtc::IceTransportState P2PTransportChannel::GetIceTransportState() const {
385 RTC_DCHECK_RUN_ON(network_thread_);
386 return standardized_state_;
387 }
388
transport_name() const389 const std::string& P2PTransportChannel::transport_name() const {
390 RTC_DCHECK_RUN_ON(network_thread_);
391 return transport_name_;
392 }
393
component() const394 int P2PTransportChannel::component() const {
395 RTC_DCHECK_RUN_ON(network_thread_);
396 return component_;
397 }
398
writable() const399 bool P2PTransportChannel::writable() const {
400 RTC_DCHECK_RUN_ON(network_thread_);
401 return writable_;
402 }
403
receiving() const404 bool P2PTransportChannel::receiving() const {
405 RTC_DCHECK_RUN_ON(network_thread_);
406 return receiving_;
407 }
408
gathering_state() const409 IceGatheringState P2PTransportChannel::gathering_state() const {
410 RTC_DCHECK_RUN_ON(network_thread_);
411 return gathering_state_;
412 }
413
GetRttEstimate()414 absl::optional<int> P2PTransportChannel::GetRttEstimate() {
415 RTC_DCHECK_RUN_ON(network_thread_);
416 if (selected_connection_ != nullptr &&
417 selected_connection_->rtt_samples() > 0) {
418 return selected_connection_->rtt();
419 } else {
420 return absl::nullopt;
421 }
422 }
423
424 absl::optional<const CandidatePair>
GetSelectedCandidatePair() const425 P2PTransportChannel::GetSelectedCandidatePair() const {
426 RTC_DCHECK_RUN_ON(network_thread_);
427 if (selected_connection_ == nullptr) {
428 return absl::nullopt;
429 }
430
431 CandidatePair pair;
432 pair.local = SanitizeLocalCandidate(selected_connection_->local_candidate());
433 pair.remote =
434 SanitizeRemoteCandidate(selected_connection_->remote_candidate());
435 return pair;
436 }
437
438 // A channel is considered ICE completed once there is at most one active
439 // connection per network and at least one active connection.
ComputeState() const440 IceTransportState P2PTransportChannel::ComputeState() const {
441 RTC_DCHECK_RUN_ON(network_thread_);
442 if (!had_connection_) {
443 return IceTransportState::STATE_INIT;
444 }
445
446 std::vector<Connection*> active_connections;
447 for (Connection* connection : connections()) {
448 if (connection->active()) {
449 active_connections.push_back(connection);
450 }
451 }
452 if (active_connections.empty()) {
453 return IceTransportState::STATE_FAILED;
454 }
455
456 std::set<const rtc::Network*> networks;
457 for (Connection* connection : active_connections) {
458 const rtc::Network* network = connection->network();
459 if (networks.find(network) == networks.end()) {
460 networks.insert(network);
461 } else {
462 RTC_LOG(LS_VERBOSE) << ToString()
463 << ": Ice not completed yet for this channel as "
464 << network->ToString()
465 << " has more than 1 connection.";
466 return IceTransportState::STATE_CONNECTING;
467 }
468 }
469
470 ice_event_log_.DumpCandidatePairDescriptionToMemoryAsConfigEvents();
471 return IceTransportState::STATE_COMPLETED;
472 }
473
474 // Compute the current RTCIceTransportState as described in
475 // https://www.w3.org/TR/webrtc/#dom-rtcicetransportstate
476 // TODO(bugs.webrtc.org/9218): Start signaling kCompleted once we have
477 // implemented end-of-candidates signalling.
ComputeIceTransportState() const478 webrtc::IceTransportState P2PTransportChannel::ComputeIceTransportState()
479 const {
480 RTC_DCHECK_RUN_ON(network_thread_);
481 bool has_connection = false;
482 for (Connection* connection : connections()) {
483 if (connection->active()) {
484 has_connection = true;
485 break;
486 }
487 }
488
489 if (had_connection_ && !has_connection) {
490 return webrtc::IceTransportState::kFailed;
491 }
492
493 if (!writable() && has_been_writable_) {
494 return webrtc::IceTransportState::kDisconnected;
495 }
496
497 if (!had_connection_ && !has_connection) {
498 return webrtc::IceTransportState::kNew;
499 }
500
501 if (has_connection && !writable()) {
502 // A candidate pair has been formed by adding a remote candidate
503 // and gathering a local candidate.
504 return webrtc::IceTransportState::kChecking;
505 }
506
507 return webrtc::IceTransportState::kConnected;
508 }
509
SetIceParameters(const IceParameters & ice_params)510 void P2PTransportChannel::SetIceParameters(const IceParameters& ice_params) {
511 RTC_DCHECK_RUN_ON(network_thread_);
512 RTC_LOG(LS_INFO) << "Set ICE ufrag: " << ice_params.ufrag
513 << " pwd: " << ice_params.pwd << " on transport "
514 << transport_name();
515 ice_parameters_ = ice_params;
516 // Note: Candidate gathering will restart when MaybeStartGathering is next
517 // called.
518 }
519
SetRemoteIceParameters(const IceParameters & ice_params)520 void P2PTransportChannel::SetRemoteIceParameters(
521 const IceParameters& ice_params) {
522 RTC_DCHECK_RUN_ON(network_thread_);
523 RTC_LOG(LS_INFO) << "Received remote ICE parameters: ufrag="
524 << ice_params.ufrag << ", renomination "
525 << (ice_params.renomination ? "enabled" : "disabled");
526 IceParameters* current_ice = remote_ice();
527 if (!current_ice || *current_ice != ice_params) {
528 // Keep the ICE credentials so that newer connections
529 // are prioritized over the older ones.
530 remote_ice_parameters_.push_back(ice_params);
531 }
532
533 // Update the pwd of remote candidate if needed.
534 for (RemoteCandidate& candidate : remote_candidates_) {
535 if (candidate.username() == ice_params.ufrag &&
536 candidate.password().empty()) {
537 candidate.set_password(ice_params.pwd);
538 }
539 }
540 // We need to update the credentials and generation for any peer reflexive
541 // candidates.
542 for (Connection* conn : connections()) {
543 conn->MaybeSetRemoteIceParametersAndGeneration(
544 ice_params, static_cast<int>(remote_ice_parameters_.size() - 1));
545 }
546 // Updating the remote ICE candidate generation could change the sort order.
547 ice_adapter_->OnSortAndSwitchRequest(
548 IceSwitchReason::REMOTE_CANDIDATE_GENERATION_CHANGE);
549 }
550
SetRemoteIceMode(IceMode mode)551 void P2PTransportChannel::SetRemoteIceMode(IceMode mode) {
552 RTC_DCHECK_RUN_ON(network_thread_);
553 remote_ice_mode_ = mode;
554 }
555
556 // TODO(qingsi): We apply the convention that setting a absl::optional parameter
557 // to null restores its default value in the implementation. However, some
558 // absl::optional parameters are only processed below if non-null, e.g.,
559 // regather_on_failed_networks_interval, and thus there is no way to restore the
560 // defaults. Fix this issue later for consistency.
SetIceConfig(const IceConfig & config)561 void P2PTransportChannel::SetIceConfig(const IceConfig& config) {
562 RTC_DCHECK_RUN_ON(network_thread_);
563 if (config_.continual_gathering_policy != config.continual_gathering_policy) {
564 if (!allocator_sessions_.empty()) {
565 RTC_LOG(LS_ERROR) << "Trying to change continual gathering policy "
566 "when gathering has already started!";
567 } else {
568 config_.continual_gathering_policy = config.continual_gathering_policy;
569 RTC_LOG(LS_INFO) << "Set continual_gathering_policy to "
570 << config_.continual_gathering_policy;
571 }
572 }
573
574 if (config_.backup_connection_ping_interval !=
575 config.backup_connection_ping_interval) {
576 config_.backup_connection_ping_interval =
577 config.backup_connection_ping_interval;
578 RTC_LOG(LS_INFO) << "Set backup connection ping interval to "
579 << config_.backup_connection_ping_interval_or_default()
580 << " milliseconds.";
581 }
582 if (config_.receiving_timeout != config.receiving_timeout) {
583 config_.receiving_timeout = config.receiving_timeout;
584 for (Connection* connection : connections()) {
585 connection->set_receiving_timeout(config_.receiving_timeout);
586 }
587 RTC_LOG(LS_INFO) << "Set ICE receiving timeout to "
588 << config_.receiving_timeout_or_default()
589 << " milliseconds";
590 }
591
592 config_.prioritize_most_likely_candidate_pairs =
593 config.prioritize_most_likely_candidate_pairs;
594 RTC_LOG(LS_INFO) << "Set ping most likely connection to "
595 << config_.prioritize_most_likely_candidate_pairs;
596
597 if (config_.stable_writable_connection_ping_interval !=
598 config.stable_writable_connection_ping_interval) {
599 config_.stable_writable_connection_ping_interval =
600 config.stable_writable_connection_ping_interval;
601 RTC_LOG(LS_INFO)
602 << "Set stable_writable_connection_ping_interval to "
603 << config_.stable_writable_connection_ping_interval_or_default();
604 }
605
606 if (config_.presume_writable_when_fully_relayed !=
607 config.presume_writable_when_fully_relayed) {
608 if (!connections().empty()) {
609 RTC_LOG(LS_ERROR) << "Trying to change 'presume writable' "
610 "while connections already exist!";
611 } else {
612 config_.presume_writable_when_fully_relayed =
613 config.presume_writable_when_fully_relayed;
614 RTC_LOG(LS_INFO) << "Set presume writable when fully relayed to "
615 << config_.presume_writable_when_fully_relayed;
616 }
617 }
618
619 config_.surface_ice_candidates_on_ice_transport_type_changed =
620 config.surface_ice_candidates_on_ice_transport_type_changed;
621 if (config_.surface_ice_candidates_on_ice_transport_type_changed &&
622 config_.continual_gathering_policy != GATHER_CONTINUALLY) {
623 RTC_LOG(LS_WARNING)
624 << "surface_ice_candidates_on_ice_transport_type_changed is "
625 "ineffective since we do not gather continually.";
626 }
627
628 if (config_.regather_on_failed_networks_interval !=
629 config.regather_on_failed_networks_interval) {
630 config_.regather_on_failed_networks_interval =
631 config.regather_on_failed_networks_interval;
632 RTC_LOG(LS_INFO)
633 << "Set regather_on_failed_networks_interval to "
634 << config_.regather_on_failed_networks_interval_or_default();
635 }
636
637 if (config_.receiving_switching_delay != config.receiving_switching_delay) {
638 config_.receiving_switching_delay = config.receiving_switching_delay;
639 RTC_LOG(LS_INFO) << "Set receiving_switching_delay to "
640 << config_.receiving_switching_delay_or_default();
641 }
642
643 if (config_.default_nomination_mode != config.default_nomination_mode) {
644 config_.default_nomination_mode = config.default_nomination_mode;
645 RTC_LOG(LS_INFO) << "Set default nomination mode to "
646 << static_cast<int>(config_.default_nomination_mode);
647 }
648
649 if (config_.ice_check_interval_strong_connectivity !=
650 config.ice_check_interval_strong_connectivity) {
651 config_.ice_check_interval_strong_connectivity =
652 config.ice_check_interval_strong_connectivity;
653 RTC_LOG(LS_INFO)
654 << "Set strong ping interval to "
655 << config_.ice_check_interval_strong_connectivity_or_default();
656 }
657
658 if (config_.ice_check_interval_weak_connectivity !=
659 config.ice_check_interval_weak_connectivity) {
660 config_.ice_check_interval_weak_connectivity =
661 config.ice_check_interval_weak_connectivity;
662 RTC_LOG(LS_INFO)
663 << "Set weak ping interval to "
664 << config_.ice_check_interval_weak_connectivity_or_default();
665 }
666
667 if (config_.ice_check_min_interval != config.ice_check_min_interval) {
668 config_.ice_check_min_interval = config.ice_check_min_interval;
669 RTC_LOG(LS_INFO) << "Set min ping interval to "
670 << config_.ice_check_min_interval_or_default();
671 }
672
673 if (config_.ice_unwritable_timeout != config.ice_unwritable_timeout) {
674 config_.ice_unwritable_timeout = config.ice_unwritable_timeout;
675 for (Connection* conn : connections()) {
676 conn->set_unwritable_timeout(config_.ice_unwritable_timeout);
677 }
678 RTC_LOG(LS_INFO) << "Set unwritable timeout to "
679 << config_.ice_unwritable_timeout_or_default();
680 }
681
682 if (config_.ice_unwritable_min_checks != config.ice_unwritable_min_checks) {
683 config_.ice_unwritable_min_checks = config.ice_unwritable_min_checks;
684 for (Connection* conn : connections()) {
685 conn->set_unwritable_min_checks(config_.ice_unwritable_min_checks);
686 }
687 RTC_LOG(LS_INFO) << "Set unwritable min checks to "
688 << config_.ice_unwritable_min_checks_or_default();
689 }
690
691 if (config_.ice_inactive_timeout != config.ice_inactive_timeout) {
692 config_.ice_inactive_timeout = config.ice_inactive_timeout;
693 for (Connection* conn : connections()) {
694 conn->set_inactive_timeout(config_.ice_inactive_timeout);
695 }
696 RTC_LOG(LS_INFO) << "Set inactive timeout to "
697 << config_.ice_inactive_timeout_or_default();
698 }
699
700 if (config_.network_preference != config.network_preference) {
701 config_.network_preference = config.network_preference;
702 ice_adapter_->OnSortAndSwitchRequest(
703 IceSwitchReason::NETWORK_PREFERENCE_CHANGE);
704 RTC_LOG(LS_INFO) << "Set network preference to "
705 << (config_.network_preference.has_value()
706 ? config_.network_preference.value()
707 : -1); // network_preference cannot be bound to
708 // int with value_or.
709 }
710
711 // TODO(qingsi): Resolve the naming conflict of stun_keepalive_delay in
712 // UDPPort and stun_keepalive_interval.
713 if (config_.stun_keepalive_interval != config.stun_keepalive_interval) {
714 config_.stun_keepalive_interval = config.stun_keepalive_interval;
715 allocator_session()->SetStunKeepaliveIntervalForReadyPorts(
716 config_.stun_keepalive_interval);
717 RTC_LOG(LS_INFO) << "Set STUN keepalive interval to "
718 << config.stun_keepalive_interval_or_default();
719 }
720
721 webrtc::BasicRegatheringController::Config regathering_config;
722 regathering_config.regather_on_failed_networks_interval =
723 config_.regather_on_failed_networks_interval_or_default();
724 regathering_controller_->SetConfig(regathering_config);
725
726 config_.vpn_preference = config.vpn_preference;
727 allocator_->SetVpnPreference(config_.vpn_preference);
728
729 ice_adapter_->SetIceConfig(config_);
730
731 RTC_DCHECK(ValidateIceConfig(config_).ok());
732 }
733
ParseFieldTrials(const webrtc::FieldTrialsView * field_trials)734 void P2PTransportChannel::ParseFieldTrials(
735 const webrtc::FieldTrialsView* field_trials) {
736 if (field_trials == nullptr) {
737 return;
738 }
739
740 if (field_trials->IsEnabled("WebRTC-ExtraICEPing")) {
741 RTC_LOG(LS_INFO) << "Set WebRTC-ExtraICEPing: Enabled";
742 }
743
744 webrtc::StructParametersParser::Create(
745 // go/skylift-light
746 "skip_relay_to_non_relay_connections",
747 &ice_field_trials_.skip_relay_to_non_relay_connections,
748 // Limiting pings sent.
749 "max_outstanding_pings", &ice_field_trials_.max_outstanding_pings,
750 // Delay initial selection of connection.
751 "initial_select_dampening", &ice_field_trials_.initial_select_dampening,
752 // Delay initial selection of connections, that are receiving.
753 "initial_select_dampening_ping_received",
754 &ice_field_trials_.initial_select_dampening_ping_received,
755 // Reply that we support goog ping.
756 "announce_goog_ping", &ice_field_trials_.announce_goog_ping,
757 // Use goog ping if remote support it.
758 "enable_goog_ping", &ice_field_trials_.enable_goog_ping,
759 // How fast does a RTT sample decay.
760 "rtt_estimate_halftime_ms", &ice_field_trials_.rtt_estimate_halftime_ms,
761 // Make sure that nomination reaching ICE controlled asap.
762 "send_ping_on_switch_ice_controlling",
763 &ice_field_trials_.send_ping_on_switch_ice_controlling,
764 // Make sure that nomination reaching ICE controlled asap.
765 "send_ping_on_selected_ice_controlling",
766 &ice_field_trials_.send_ping_on_selected_ice_controlling,
767 // Reply to nomination ASAP.
768 "send_ping_on_nomination_ice_controlled",
769 &ice_field_trials_.send_ping_on_nomination_ice_controlled,
770 // Allow connections to live untouched longer that 30s.
771 "dead_connection_timeout_ms",
772 &ice_field_trials_.dead_connection_timeout_ms,
773 // Stop gathering on strongly connected.
774 "stop_gather_on_strongly_connected",
775 &ice_field_trials_.stop_gather_on_strongly_connected)
776 ->Parse(field_trials->Lookup("WebRTC-IceFieldTrials"));
777
778 if (ice_field_trials_.dead_connection_timeout_ms < 30000) {
779 RTC_LOG(LS_WARNING) << "dead_connection_timeout_ms set to "
780 << ice_field_trials_.dead_connection_timeout_ms
781 << " increasing it to 30000";
782 ice_field_trials_.dead_connection_timeout_ms = 30000;
783 }
784
785 if (ice_field_trials_.skip_relay_to_non_relay_connections) {
786 RTC_LOG(LS_INFO) << "Set skip_relay_to_non_relay_connections";
787 }
788
789 if (ice_field_trials_.max_outstanding_pings.has_value()) {
790 RTC_LOG(LS_INFO) << "Set max_outstanding_pings: "
791 << *ice_field_trials_.max_outstanding_pings;
792 }
793
794 if (ice_field_trials_.initial_select_dampening.has_value()) {
795 RTC_LOG(LS_INFO) << "Set initial_select_dampening: "
796 << *ice_field_trials_.initial_select_dampening;
797 }
798
799 if (ice_field_trials_.initial_select_dampening_ping_received.has_value()) {
800 RTC_LOG(LS_INFO)
801 << "Set initial_select_dampening_ping_received: "
802 << *ice_field_trials_.initial_select_dampening_ping_received;
803 }
804
805 // DSCP override, allow user to specify (any) int value
806 // that will be used for tagging all packets.
807 webrtc::StructParametersParser::Create("override_dscp",
808 &ice_field_trials_.override_dscp)
809 ->Parse(field_trials->Lookup("WebRTC-DscpFieldTrial"));
810
811 if (ice_field_trials_.override_dscp) {
812 SetOption(rtc::Socket::OPT_DSCP, *ice_field_trials_.override_dscp);
813 }
814
815 std::string field_trial_string =
816 field_trials->Lookup("WebRTC-SetSocketReceiveBuffer");
817 int receive_buffer_size_kb = 0;
818 sscanf(field_trial_string.c_str(), "Enabled-%d", &receive_buffer_size_kb);
819 if (receive_buffer_size_kb > 0) {
820 RTC_LOG(LS_INFO) << "Set WebRTC-SetSocketReceiveBuffer: Enabled and set to "
821 << receive_buffer_size_kb << "kb";
822 SetOption(rtc::Socket::OPT_RCVBUF, receive_buffer_size_kb * 1024);
823 }
824
825 ice_field_trials_.piggyback_ice_check_acknowledgement =
826 field_trials->IsEnabled("WebRTC-PiggybackIceCheckAcknowledgement");
827
828 ice_field_trials_.extra_ice_ping =
829 field_trials->IsEnabled("WebRTC-ExtraICEPing");
830 }
831
config() const832 const IceConfig& P2PTransportChannel::config() const {
833 RTC_DCHECK_RUN_ON(network_thread_);
834 return config_;
835 }
836
837 // TODO(qingsi): Add tests for the config validation starting from
838 // PeerConnection::SetConfiguration.
839 // Static
ValidateIceConfig(const IceConfig & config)840 RTCError P2PTransportChannel::ValidateIceConfig(const IceConfig& config) {
841 if (config.ice_check_interval_strong_connectivity_or_default() <
842 config.ice_check_interval_weak_connectivity.value_or(
843 GetWeakPingIntervalInFieldTrial(nullptr))) {
844 return RTCError(RTCErrorType::INVALID_PARAMETER,
845 "Ping interval of candidate pairs is shorter when ICE is "
846 "strongly connected than that when ICE is weakly "
847 "connected");
848 }
849
850 if (config.receiving_timeout_or_default() <
851 std::max(config.ice_check_interval_strong_connectivity_or_default(),
852 config.ice_check_min_interval_or_default())) {
853 return RTCError(
854 RTCErrorType::INVALID_PARAMETER,
855 "Receiving timeout is shorter than the minimal ping interval.");
856 }
857
858 if (config.backup_connection_ping_interval_or_default() <
859 config.ice_check_interval_strong_connectivity_or_default()) {
860 return RTCError(RTCErrorType::INVALID_PARAMETER,
861 "Ping interval of backup candidate pairs is shorter than "
862 "that of general candidate pairs when ICE is strongly "
863 "connected");
864 }
865
866 if (config.stable_writable_connection_ping_interval_or_default() <
867 config.ice_check_interval_strong_connectivity_or_default()) {
868 return RTCError(RTCErrorType::INVALID_PARAMETER,
869 "Ping interval of stable and writable candidate pairs is "
870 "shorter than that of general candidate pairs when ICE is "
871 "strongly connected");
872 }
873
874 if (config.ice_unwritable_timeout_or_default() >
875 config.ice_inactive_timeout_or_default()) {
876 return RTCError(RTCErrorType::INVALID_PARAMETER,
877 "The timeout period for the writability state to become "
878 "UNRELIABLE is longer than that to become TIMEOUT.");
879 }
880
881 return RTCError::OK();
882 }
883
selected_connection() const884 const Connection* P2PTransportChannel::selected_connection() const {
885 RTC_DCHECK_RUN_ON(network_thread_);
886 return selected_connection_;
887 }
888
check_receiving_interval() const889 int P2PTransportChannel::check_receiving_interval() const {
890 RTC_DCHECK_RUN_ON(network_thread_);
891 return std::max(MIN_CHECK_RECEIVING_INTERVAL,
892 config_.receiving_timeout_or_default() / 10);
893 }
894
MaybeStartGathering()895 void P2PTransportChannel::MaybeStartGathering() {
896 RTC_DCHECK_RUN_ON(network_thread_);
897 // TODO(bugs.webrtc.org/14605): ensure tie_breaker_ is set.
898 if (ice_parameters_.ufrag.empty() || ice_parameters_.pwd.empty()) {
899 RTC_LOG(LS_ERROR)
900 << "Cannot gather candidates because ICE parameters are empty"
901 " ufrag: "
902 << ice_parameters_.ufrag << " pwd: " << ice_parameters_.pwd;
903 return;
904 }
905 // Start gathering if we never started before, or if an ICE restart occurred.
906 if (allocator_sessions_.empty() ||
907 IceCredentialsChanged(allocator_sessions_.back()->ice_ufrag(),
908 allocator_sessions_.back()->ice_pwd(),
909 ice_parameters_.ufrag, ice_parameters_.pwd)) {
910 if (gathering_state_ != kIceGatheringGathering) {
911 gathering_state_ = kIceGatheringGathering;
912 SignalGatheringState(this);
913 }
914
915 if (!allocator_sessions_.empty()) {
916 IceRestartState state;
917 if (writable()) {
918 state = IceRestartState::CONNECTED;
919 } else if (IsGettingPorts()) {
920 state = IceRestartState::CONNECTING;
921 } else {
922 state = IceRestartState::DISCONNECTED;
923 }
924 RTC_HISTOGRAM_ENUMERATION("WebRTC.PeerConnection.IceRestartState",
925 static_cast<int>(state),
926 static_cast<int>(IceRestartState::MAX_VALUE));
927 }
928
929 for (const auto& session : allocator_sessions_) {
930 if (session->IsStopped()) {
931 continue;
932 }
933 session->StopGettingPorts();
934 }
935
936 // Time for a new allocator.
937 std::unique_ptr<PortAllocatorSession> pooled_session =
938 allocator_->TakePooledSession(transport_name(), component(),
939 ice_parameters_.ufrag,
940 ice_parameters_.pwd);
941 if (pooled_session) {
942 pooled_session->set_ice_tiebreaker(tiebreaker_);
943 AddAllocatorSession(std::move(pooled_session));
944 PortAllocatorSession* raw_pooled_session =
945 allocator_sessions_.back().get();
946 // Process the pooled session's existing candidates/ports, if they exist.
947 OnCandidatesReady(raw_pooled_session,
948 raw_pooled_session->ReadyCandidates());
949 for (PortInterface* port : allocator_sessions_.back()->ReadyPorts()) {
950 OnPortReady(raw_pooled_session, port);
951 }
952 if (allocator_sessions_.back()->CandidatesAllocationDone()) {
953 OnCandidatesAllocationDone(raw_pooled_session);
954 }
955 } else {
956 AddAllocatorSession(allocator_->CreateSession(
957 transport_name(), component(), ice_parameters_.ufrag,
958 ice_parameters_.pwd));
959 allocator_sessions_.back()->set_ice_tiebreaker(tiebreaker_);
960 allocator_sessions_.back()->StartGettingPorts();
961 }
962 }
963 }
964
965 // A new port is available, attempt to make connections for it
OnPortReady(PortAllocatorSession * session,PortInterface * port)966 void P2PTransportChannel::OnPortReady(PortAllocatorSession* session,
967 PortInterface* port) {
968 RTC_DCHECK_RUN_ON(network_thread_);
969
970 // Set in-effect options on the new port
971 for (OptionMap::const_iterator it = options_.begin(); it != options_.end();
972 ++it) {
973 int val = port->SetOption(it->first, it->second);
974 if (val < 0) {
975 // Errors are frequent, so use LS_INFO. bugs.webrtc.org/9221
976 RTC_LOG(LS_INFO) << port->ToString() << ": SetOption(" << it->first
977 << ", " << it->second
978 << ") failed: " << port->GetError();
979 }
980 }
981
982 // Remember the ports and candidates, and signal that candidates are ready.
983 // The session will handle this, and send an initiate/accept/modify message
984 // if one is pending.
985
986 port->SetIceRole(ice_role_);
987 port->SetIceTiebreaker(tiebreaker_);
988 ports_.push_back(port);
989 port->SignalUnknownAddress.connect(this,
990 &P2PTransportChannel::OnUnknownAddress);
991 port->SubscribePortDestroyed(
992 [this](PortInterface* port) { OnPortDestroyed(port); });
993
994 port->SignalRoleConflict.connect(this, &P2PTransportChannel::OnRoleConflict);
995 port->SignalSentPacket.connect(this, &P2PTransportChannel::OnSentPacket);
996
997 // Attempt to create a connection from this new port to all of the remote
998 // candidates that we were given so far.
999
1000 std::vector<RemoteCandidate>::iterator iter;
1001 for (iter = remote_candidates_.begin(); iter != remote_candidates_.end();
1002 ++iter) {
1003 CreateConnection(port, *iter, iter->origin_port());
1004 }
1005
1006 ice_adapter_->OnImmediateSortAndSwitchRequest(
1007 IceSwitchReason::NEW_CONNECTION_FROM_LOCAL_CANDIDATE);
1008 }
1009
1010 // A new candidate is available, let listeners know
OnCandidatesReady(PortAllocatorSession * session,const std::vector<Candidate> & candidates)1011 void P2PTransportChannel::OnCandidatesReady(
1012 PortAllocatorSession* session,
1013 const std::vector<Candidate>& candidates) {
1014 RTC_DCHECK_RUN_ON(network_thread_);
1015 for (size_t i = 0; i < candidates.size(); ++i) {
1016 SignalCandidateGathered(this, candidates[i]);
1017 }
1018 }
1019
OnCandidateError(PortAllocatorSession * session,const IceCandidateErrorEvent & event)1020 void P2PTransportChannel::OnCandidateError(
1021 PortAllocatorSession* session,
1022 const IceCandidateErrorEvent& event) {
1023 RTC_DCHECK(network_thread_ == rtc::Thread::Current());
1024 SignalCandidateError(this, event);
1025 }
1026
OnCandidatesAllocationDone(PortAllocatorSession * session)1027 void P2PTransportChannel::OnCandidatesAllocationDone(
1028 PortAllocatorSession* session) {
1029 RTC_DCHECK_RUN_ON(network_thread_);
1030 if (config_.gather_continually()) {
1031 RTC_LOG(LS_INFO) << "P2PTransportChannel: " << transport_name()
1032 << ", component " << component()
1033 << " gathering complete, but using continual "
1034 "gathering so not changing gathering state.";
1035 return;
1036 }
1037 gathering_state_ = kIceGatheringComplete;
1038 RTC_LOG(LS_INFO) << "P2PTransportChannel: " << transport_name()
1039 << ", component " << component() << " gathering complete";
1040 SignalGatheringState(this);
1041 }
1042
1043 // Handle stun packets
OnUnknownAddress(PortInterface * port,const rtc::SocketAddress & address,ProtocolType proto,IceMessage * stun_msg,const std::string & remote_username,bool port_muxed)1044 void P2PTransportChannel::OnUnknownAddress(PortInterface* port,
1045 const rtc::SocketAddress& address,
1046 ProtocolType proto,
1047 IceMessage* stun_msg,
1048 const std::string& remote_username,
1049 bool port_muxed) {
1050 RTC_DCHECK_RUN_ON(network_thread_);
1051
1052 // Port has received a valid stun packet from an address that no Connection
1053 // is currently available for. See if we already have a candidate with the
1054 // address. If it isn't we need to create new candidate for it.
1055 //
1056 // TODO(qingsi): There is a caveat of the logic below if we have remote
1057 // candidates with hostnames. We could create a prflx candidate that is
1058 // identical to a host candidate that are currently in the process of name
1059 // resolution. We would not have a duplicate candidate since when adding the
1060 // resolved host candidate, FinishingAddingRemoteCandidate does
1061 // MaybeUpdatePeerReflexiveCandidate, and the prflx candidate would be updated
1062 // to a host candidate. As a result, for a brief moment we would have a prflx
1063 // candidate showing a private IP address, though we do not signal prflx
1064 // candidates to applications and we could obfuscate the IP addresses of prflx
1065 // candidates in P2PTransportChannel::GetStats. The difficulty of preventing
1066 // creating the prflx from the beginning is that we do not have a reliable way
1067 // to claim two candidates are identical without the address information. If
1068 // we always pause the addition of a prflx candidate when there is ongoing
1069 // name resolution and dedup after we have a resolved address, we run into the
1070 // risk of losing/delaying the addition of a non-identical candidate that
1071 // could be the only way to have a connection, if the resolution never
1072 // completes or is significantly delayed.
1073 const Candidate* candidate = nullptr;
1074 for (const Candidate& c : remote_candidates_) {
1075 if (c.username() == remote_username && c.address() == address &&
1076 c.protocol() == ProtoToString(proto)) {
1077 candidate = &c;
1078 break;
1079 }
1080 }
1081
1082 uint32_t remote_generation = 0;
1083 std::string remote_password;
1084 // The STUN binding request may arrive after setRemoteDescription and before
1085 // adding remote candidate, so we need to set the password to the shared
1086 // password and set the generation if the user name matches.
1087 const IceParameters* ice_param =
1088 FindRemoteIceFromUfrag(remote_username, &remote_generation);
1089 // Note: if not found, the remote_generation will still be 0.
1090 if (ice_param != nullptr) {
1091 remote_password = ice_param->pwd;
1092 }
1093
1094 Candidate remote_candidate;
1095 bool remote_candidate_is_new = (candidate == nullptr);
1096 if (!remote_candidate_is_new) {
1097 remote_candidate = *candidate;
1098 } else {
1099 // Create a new candidate with this address.
1100 // The priority of the candidate is set to the PRIORITY attribute
1101 // from the request.
1102 const StunUInt32Attribute* priority_attr =
1103 stun_msg->GetUInt32(STUN_ATTR_PRIORITY);
1104 if (!priority_attr) {
1105 RTC_LOG(LS_WARNING) << "P2PTransportChannel::OnUnknownAddress - "
1106 "No STUN_ATTR_PRIORITY found in the "
1107 "stun request message";
1108 port->SendBindingErrorResponse(stun_msg, address, STUN_ERROR_BAD_REQUEST,
1109 STUN_ERROR_REASON_BAD_REQUEST);
1110 return;
1111 }
1112 int remote_candidate_priority = priority_attr->value();
1113
1114 uint16_t network_id = 0;
1115 uint16_t network_cost = 0;
1116 const StunUInt32Attribute* network_attr =
1117 stun_msg->GetUInt32(STUN_ATTR_GOOG_NETWORK_INFO);
1118 if (network_attr) {
1119 uint32_t network_info = network_attr->value();
1120 network_id = static_cast<uint16_t>(network_info >> 16);
1121 network_cost = static_cast<uint16_t>(network_info);
1122 }
1123
1124 // RFC 5245
1125 // If the source transport address of the request does not match any
1126 // existing remote candidates, it represents a new peer reflexive remote
1127 // candidate.
1128 remote_candidate = Candidate(
1129 component(), ProtoToString(proto), address, remote_candidate_priority,
1130 remote_username, remote_password, PRFLX_PORT_TYPE, remote_generation,
1131 "", network_id, network_cost);
1132 if (proto == PROTO_TCP) {
1133 remote_candidate.set_tcptype(TCPTYPE_ACTIVE_STR);
1134 }
1135
1136 // From RFC 5245, section-7.2.1.3:
1137 // The foundation of the candidate is set to an arbitrary value, different
1138 // from the foundation for all other remote candidates.
1139 remote_candidate.set_foundation(
1140 rtc::ToString(rtc::ComputeCrc32(remote_candidate.id())));
1141 }
1142
1143 // RFC5245, the agent constructs a pair whose local candidate is equal to
1144 // the transport address on which the STUN request was received, and a
1145 // remote candidate equal to the source transport address where the
1146 // request came from.
1147
1148 // There shouldn't be an existing connection with this remote address.
1149 // When ports are muxed, this channel might get multiple unknown address
1150 // signals. In that case if the connection is already exists, we should
1151 // simply ignore the signal otherwise send server error.
1152 if (port->GetConnection(remote_candidate.address())) {
1153 if (port_muxed) {
1154 RTC_LOG(LS_INFO) << "Connection already exists for peer reflexive "
1155 "candidate: "
1156 << remote_candidate.ToSensitiveString();
1157 return;
1158 } else {
1159 RTC_DCHECK_NOTREACHED();
1160 port->SendBindingErrorResponse(stun_msg, address, STUN_ERROR_SERVER_ERROR,
1161 STUN_ERROR_REASON_SERVER_ERROR);
1162 return;
1163 }
1164 }
1165
1166 Connection* connection =
1167 port->CreateConnection(remote_candidate, PortInterface::ORIGIN_THIS_PORT);
1168 if (!connection) {
1169 // This could happen in some scenarios. For example, a TurnPort may have
1170 // had a refresh request timeout, so it won't create connections.
1171 port->SendBindingErrorResponse(stun_msg, address, STUN_ERROR_SERVER_ERROR,
1172 STUN_ERROR_REASON_SERVER_ERROR);
1173 return;
1174 }
1175
1176 RTC_LOG(LS_INFO) << "Adding connection from "
1177 << (remote_candidate_is_new ? "peer reflexive"
1178 : "resurrected")
1179 << " candidate: " << remote_candidate.ToSensitiveString();
1180 AddConnection(connection);
1181 connection->HandleStunBindingOrGoogPingRequest(stun_msg);
1182
1183 // Update the list of connections since we just added another. We do this
1184 // after sending the response since it could (in principle) delete the
1185 // connection in question.
1186 ice_adapter_->OnImmediateSortAndSwitchRequest(
1187 IceSwitchReason::NEW_CONNECTION_FROM_UNKNOWN_REMOTE_ADDRESS);
1188 }
1189
OnCandidateFilterChanged(uint32_t prev_filter,uint32_t cur_filter)1190 void P2PTransportChannel::OnCandidateFilterChanged(uint32_t prev_filter,
1191 uint32_t cur_filter) {
1192 RTC_DCHECK_RUN_ON(network_thread_);
1193 if (prev_filter == cur_filter || allocator_session() == nullptr) {
1194 return;
1195 }
1196 if (config_.surface_ice_candidates_on_ice_transport_type_changed) {
1197 allocator_session()->SetCandidateFilter(cur_filter);
1198 }
1199 }
1200
OnRoleConflict(PortInterface * port)1201 void P2PTransportChannel::OnRoleConflict(PortInterface* port) {
1202 SignalRoleConflict(this); // STUN ping will be sent when SetRole is called
1203 // from Transport.
1204 }
1205
FindRemoteIceFromUfrag(absl::string_view ufrag,uint32_t * generation)1206 const IceParameters* P2PTransportChannel::FindRemoteIceFromUfrag(
1207 absl::string_view ufrag,
1208 uint32_t* generation) {
1209 RTC_DCHECK_RUN_ON(network_thread_);
1210 const auto& params = remote_ice_parameters_;
1211 auto it = std::find_if(
1212 params.rbegin(), params.rend(),
1213 [ufrag](const IceParameters& param) { return param.ufrag == ufrag; });
1214 if (it == params.rend()) {
1215 // Not found.
1216 return nullptr;
1217 }
1218 *generation = params.rend() - it - 1;
1219 return &(*it);
1220 }
1221
OnNominated(Connection * conn)1222 void P2PTransportChannel::OnNominated(Connection* conn) {
1223 RTC_DCHECK_RUN_ON(network_thread_);
1224 RTC_DCHECK(ice_role_ == ICEROLE_CONTROLLED);
1225
1226 if (selected_connection_ == conn) {
1227 return;
1228 }
1229
1230 if (ice_field_trials_.send_ping_on_nomination_ice_controlled &&
1231 conn != nullptr) {
1232 SendPingRequestInternal(conn);
1233 }
1234
1235 // TODO(qingsi): RequestSortAndStateUpdate will eventually call
1236 // MaybeSwitchSelectedConnection again. Rewrite this logic.
1237 if (ice_adapter_->OnImmediateSwitchRequest(
1238 IceSwitchReason::NOMINATION_ON_CONTROLLED_SIDE, conn)) {
1239 // Now that we have selected a connection, it is time to prune other
1240 // connections and update the read/write state of the channel.
1241 ice_adapter_->OnSortAndSwitchRequest(
1242 IceSwitchReason::NOMINATION_ON_CONTROLLED_SIDE);
1243 } else {
1244 RTC_LOG(LS_INFO)
1245 << "Not switching the selected connection on controlled side yet: "
1246 << conn->ToString();
1247 }
1248 }
1249
ResolveHostnameCandidate(const Candidate & candidate)1250 void P2PTransportChannel::ResolveHostnameCandidate(const Candidate& candidate) {
1251 RTC_DCHECK_RUN_ON(network_thread_);
1252 if (!async_dns_resolver_factory_) {
1253 RTC_LOG(LS_WARNING) << "Dropping ICE candidate with hostname address "
1254 "(no AsyncResolverFactory)";
1255 return;
1256 }
1257
1258 auto resolver = async_dns_resolver_factory_->Create();
1259 auto resptr = resolver.get();
1260 resolvers_.emplace_back(candidate, std::move(resolver));
1261 resptr->Start(candidate.address(),
1262 [this, resptr]() { OnCandidateResolved(resptr); });
1263 RTC_LOG(LS_INFO) << "Asynchronously resolving ICE candidate hostname "
1264 << candidate.address().HostAsSensitiveURIString();
1265 }
1266
AddRemoteCandidate(const Candidate & candidate)1267 void P2PTransportChannel::AddRemoteCandidate(const Candidate& candidate) {
1268 RTC_DCHECK_RUN_ON(network_thread_);
1269
1270 uint32_t generation = GetRemoteCandidateGeneration(candidate);
1271 // If a remote candidate with a previous generation arrives, drop it.
1272 if (generation < remote_ice_generation()) {
1273 RTC_LOG(LS_WARNING) << "Dropping a remote candidate because its ufrag "
1274 << candidate.username()
1275 << " indicates it was for a previous generation.";
1276 return;
1277 }
1278
1279 Candidate new_remote_candidate(candidate);
1280 new_remote_candidate.set_generation(generation);
1281 // ICE candidates don't need to have username and password set, but
1282 // the code below this (specifically, ConnectionRequest::Prepare in
1283 // port.cc) uses the remote candidates's username. So, we set it
1284 // here.
1285 if (remote_ice()) {
1286 if (candidate.username().empty()) {
1287 new_remote_candidate.set_username(remote_ice()->ufrag);
1288 }
1289 if (new_remote_candidate.username() == remote_ice()->ufrag) {
1290 if (candidate.password().empty()) {
1291 new_remote_candidate.set_password(remote_ice()->pwd);
1292 }
1293 } else {
1294 // The candidate belongs to the next generation. Its pwd will be set
1295 // when the new remote ICE credentials arrive.
1296 RTC_LOG(LS_WARNING)
1297 << "A remote candidate arrives with an unknown ufrag: "
1298 << candidate.username();
1299 }
1300 }
1301
1302 if (new_remote_candidate.address().IsUnresolvedIP()) {
1303 // Don't do DNS lookups if the IceTransportPolicy is "none" or "relay".
1304 bool sharing_host = ((allocator_->candidate_filter() & CF_HOST) != 0);
1305 bool sharing_stun = ((allocator_->candidate_filter() & CF_REFLEXIVE) != 0);
1306 if (sharing_host || sharing_stun) {
1307 ResolveHostnameCandidate(new_remote_candidate);
1308 }
1309 return;
1310 }
1311
1312 FinishAddingRemoteCandidate(new_remote_candidate);
1313 }
1314
CandidateAndResolver(const Candidate & candidate,std::unique_ptr<webrtc::AsyncDnsResolverInterface> && resolver)1315 P2PTransportChannel::CandidateAndResolver::CandidateAndResolver(
1316 const Candidate& candidate,
1317 std::unique_ptr<webrtc::AsyncDnsResolverInterface>&& resolver)
1318 : candidate_(candidate), resolver_(std::move(resolver)) {}
1319
~CandidateAndResolver()1320 P2PTransportChannel::CandidateAndResolver::~CandidateAndResolver() {}
1321
OnCandidateResolved(webrtc::AsyncDnsResolverInterface * resolver)1322 void P2PTransportChannel::OnCandidateResolved(
1323 webrtc::AsyncDnsResolverInterface* resolver) {
1324 RTC_DCHECK_RUN_ON(network_thread_);
1325 auto p =
1326 absl::c_find_if(resolvers_, [resolver](const CandidateAndResolver& cr) {
1327 return cr.resolver_.get() == resolver;
1328 });
1329 if (p == resolvers_.end()) {
1330 RTC_LOG(LS_ERROR) << "Unexpected AsyncDnsResolver return";
1331 RTC_DCHECK_NOTREACHED();
1332 return;
1333 }
1334 Candidate candidate = p->candidate_;
1335 AddRemoteCandidateWithResult(candidate, resolver->result());
1336 // Now we can delete the resolver.
1337 // TODO(bugs.webrtc.org/12651): Replace the stuff below with
1338 // resolvers_.erase(p);
1339 std::unique_ptr<webrtc::AsyncDnsResolverInterface> to_delete =
1340 std::move(p->resolver_);
1341 // Delay the actual deletion of the resolver until the lambda executes.
1342 network_thread_->PostTask([to_delete = std::move(to_delete)] {});
1343 resolvers_.erase(p);
1344 }
1345
AddRemoteCandidateWithResult(Candidate candidate,const webrtc::AsyncDnsResolverResult & result)1346 void P2PTransportChannel::AddRemoteCandidateWithResult(
1347 Candidate candidate,
1348 const webrtc::AsyncDnsResolverResult& result) {
1349 RTC_DCHECK_RUN_ON(network_thread_);
1350 if (result.GetError()) {
1351 RTC_LOG(LS_WARNING) << "Failed to resolve ICE candidate hostname "
1352 << candidate.address().HostAsSensitiveURIString()
1353 << " with error " << result.GetError();
1354 return;
1355 }
1356
1357 rtc::SocketAddress resolved_address;
1358 // Prefer IPv6 to IPv4 if we have it (see RFC 5245 Section 15.1).
1359 // TODO(zstein): This won't work if we only have IPv4 locally but receive an
1360 // AAAA DNS record.
1361 bool have_address = result.GetResolvedAddress(AF_INET6, &resolved_address) ||
1362 result.GetResolvedAddress(AF_INET, &resolved_address);
1363 if (!have_address) {
1364 RTC_LOG(LS_INFO) << "ICE candidate hostname "
1365 << candidate.address().HostAsSensitiveURIString()
1366 << " could not be resolved";
1367 return;
1368 }
1369
1370 RTC_LOG(LS_INFO) << "Resolved ICE candidate hostname "
1371 << candidate.address().HostAsSensitiveURIString() << " to "
1372 << resolved_address.ipaddr().ToSensitiveString();
1373 candidate.set_address(resolved_address);
1374 FinishAddingRemoteCandidate(candidate);
1375 }
1376
FinishAddingRemoteCandidate(const Candidate & new_remote_candidate)1377 void P2PTransportChannel::FinishAddingRemoteCandidate(
1378 const Candidate& new_remote_candidate) {
1379 RTC_DCHECK_RUN_ON(network_thread_);
1380 // If this candidate matches what was thought to be a peer reflexive
1381 // candidate, we need to update the candidate priority/etc.
1382 for (Connection* conn : connections()) {
1383 conn->MaybeUpdatePeerReflexiveCandidate(new_remote_candidate);
1384 }
1385
1386 // Create connections to this remote candidate.
1387 CreateConnections(new_remote_candidate, NULL);
1388
1389 // Resort the connections list, which may have new elements.
1390 ice_adapter_->OnImmediateSortAndSwitchRequest(
1391 IceSwitchReason::NEW_CONNECTION_FROM_REMOTE_CANDIDATE);
1392 }
1393
RemoveRemoteCandidate(const Candidate & cand_to_remove)1394 void P2PTransportChannel::RemoveRemoteCandidate(
1395 const Candidate& cand_to_remove) {
1396 RTC_DCHECK_RUN_ON(network_thread_);
1397 auto iter =
1398 std::remove_if(remote_candidates_.begin(), remote_candidates_.end(),
1399 [cand_to_remove](const Candidate& candidate) {
1400 return cand_to_remove.MatchesForRemoval(candidate);
1401 });
1402 if (iter != remote_candidates_.end()) {
1403 RTC_LOG(LS_VERBOSE) << "Removed remote candidate "
1404 << cand_to_remove.ToSensitiveString();
1405 remote_candidates_.erase(iter, remote_candidates_.end());
1406 }
1407 }
1408
RemoveAllRemoteCandidates()1409 void P2PTransportChannel::RemoveAllRemoteCandidates() {
1410 RTC_DCHECK_RUN_ON(network_thread_);
1411 remote_candidates_.clear();
1412 }
1413
1414 // Creates connections from all of the ports that we care about to the given
1415 // remote candidate. The return value is true if we created a connection from
1416 // the origin port.
CreateConnections(const Candidate & remote_candidate,PortInterface * origin_port)1417 bool P2PTransportChannel::CreateConnections(const Candidate& remote_candidate,
1418 PortInterface* origin_port) {
1419 RTC_DCHECK_RUN_ON(network_thread_);
1420
1421 // If we've already seen the new remote candidate (in the current candidate
1422 // generation), then we shouldn't try creating connections for it.
1423 // We either already have a connection for it, or we previously created one
1424 // and then later pruned it. If we don't return, the channel will again
1425 // re-create any connections that were previously pruned, which will then
1426 // immediately be re-pruned, churning the network for no purpose.
1427 // This only applies to candidates received over signaling (i.e. origin_port
1428 // is NULL).
1429 if (!origin_port && IsDuplicateRemoteCandidate(remote_candidate)) {
1430 // return true to indicate success, without creating any new connections.
1431 return true;
1432 }
1433
1434 // Add a new connection for this candidate to every port that allows such a
1435 // connection (i.e., if they have compatible protocols) and that does not
1436 // already have a connection to an equivalent candidate. We must be careful
1437 // to make sure that the origin port is included, even if it was pruned,
1438 // since that may be the only port that can create this connection.
1439 bool created = false;
1440 std::vector<PortInterface*>::reverse_iterator it;
1441 for (it = ports_.rbegin(); it != ports_.rend(); ++it) {
1442 if (CreateConnection(*it, remote_candidate, origin_port)) {
1443 if (*it == origin_port)
1444 created = true;
1445 }
1446 }
1447
1448 if ((origin_port != NULL) && !absl::c_linear_search(ports_, origin_port)) {
1449 if (CreateConnection(origin_port, remote_candidate, origin_port))
1450 created = true;
1451 }
1452
1453 // Remember this remote candidate so that we can add it to future ports.
1454 RememberRemoteCandidate(remote_candidate, origin_port);
1455
1456 return created;
1457 }
1458
1459 // Setup a connection object for the local and remote candidate combination.
1460 // And then listen to connection object for changes.
CreateConnection(PortInterface * port,const Candidate & remote_candidate,PortInterface * origin_port)1461 bool P2PTransportChannel::CreateConnection(PortInterface* port,
1462 const Candidate& remote_candidate,
1463 PortInterface* origin_port) {
1464 RTC_DCHECK_RUN_ON(network_thread_);
1465 if (!port->SupportsProtocol(remote_candidate.protocol())) {
1466 return false;
1467 }
1468
1469 if (ice_field_trials_.skip_relay_to_non_relay_connections) {
1470 if ((port->Type() != remote_candidate.type()) &&
1471 (port->Type() == RELAY_PORT_TYPE ||
1472 remote_candidate.type() == RELAY_PORT_TYPE)) {
1473 RTC_LOG(LS_INFO) << ToString() << ": skip creating connection "
1474 << port->Type() << " to " << remote_candidate.type();
1475 return false;
1476 }
1477 }
1478
1479 // Look for an existing connection with this remote address. If one is not
1480 // found or it is found but the existing remote candidate has an older
1481 // generation, then we can create a new connection for this address.
1482 Connection* connection = port->GetConnection(remote_candidate.address());
1483 if (connection == nullptr || connection->remote_candidate().generation() <
1484 remote_candidate.generation()) {
1485 // Don't create a connection if this is a candidate we received in a
1486 // message and we are not allowed to make outgoing connections.
1487 PortInterface::CandidateOrigin origin = GetOrigin(port, origin_port);
1488 if (origin == PortInterface::ORIGIN_MESSAGE && incoming_only_) {
1489 return false;
1490 }
1491 Connection* connection = port->CreateConnection(remote_candidate, origin);
1492 if (!connection) {
1493 return false;
1494 }
1495 AddConnection(connection);
1496 RTC_LOG(LS_INFO) << ToString()
1497 << ": Created connection with origin: " << origin
1498 << ", total: " << connections().size();
1499 return true;
1500 }
1501
1502 // No new connection was created.
1503 // It is not legal to try to change any of the parameters of an existing
1504 // connection; however, the other side can send a duplicate candidate.
1505 if (!remote_candidate.IsEquivalent(connection->remote_candidate())) {
1506 RTC_LOG(LS_INFO) << "Attempt to change a remote candidate."
1507 " Existing remote candidate: "
1508 << connection->remote_candidate().ToSensitiveString()
1509 << "New remote candidate: "
1510 << remote_candidate.ToSensitiveString();
1511 }
1512 return false;
1513 }
1514
FindConnection(const Connection * connection) const1515 bool P2PTransportChannel::FindConnection(const Connection* connection) const {
1516 RTC_DCHECK_RUN_ON(network_thread_);
1517 return absl::c_linear_search(connections(), connection);
1518 }
1519
GetRemoteCandidateGeneration(const Candidate & candidate)1520 uint32_t P2PTransportChannel::GetRemoteCandidateGeneration(
1521 const Candidate& candidate) {
1522 RTC_DCHECK_RUN_ON(network_thread_);
1523 // If the candidate has a ufrag, use it to find the generation.
1524 if (!candidate.username().empty()) {
1525 uint32_t generation = 0;
1526 if (!FindRemoteIceFromUfrag(candidate.username(), &generation)) {
1527 // If the ufrag is not found, assume the next/future generation.
1528 generation = static_cast<uint32_t>(remote_ice_parameters_.size());
1529 }
1530 return generation;
1531 }
1532 // If candidate generation is set, use that.
1533 if (candidate.generation() > 0) {
1534 return candidate.generation();
1535 }
1536 // Otherwise, assume the generation from remote ice parameters.
1537 return remote_ice_generation();
1538 }
1539
1540 // Check if remote candidate is already cached.
IsDuplicateRemoteCandidate(const Candidate & candidate)1541 bool P2PTransportChannel::IsDuplicateRemoteCandidate(
1542 const Candidate& candidate) {
1543 RTC_DCHECK_RUN_ON(network_thread_);
1544 for (size_t i = 0; i < remote_candidates_.size(); ++i) {
1545 if (remote_candidates_[i].IsEquivalent(candidate)) {
1546 return true;
1547 }
1548 }
1549 return false;
1550 }
1551
1552 // Maintain our remote candidate list, adding this new remote one.
RememberRemoteCandidate(const Candidate & remote_candidate,PortInterface * origin_port)1553 void P2PTransportChannel::RememberRemoteCandidate(
1554 const Candidate& remote_candidate,
1555 PortInterface* origin_port) {
1556 RTC_DCHECK_RUN_ON(network_thread_);
1557 // Remove any candidates whose generation is older than this one. The
1558 // presence of a new generation indicates that the old ones are not useful.
1559 size_t i = 0;
1560 while (i < remote_candidates_.size()) {
1561 if (remote_candidates_[i].generation() < remote_candidate.generation()) {
1562 RTC_LOG(LS_INFO) << "Pruning candidate from old generation: "
1563 << remote_candidates_[i].address().ToSensitiveString();
1564 remote_candidates_.erase(remote_candidates_.begin() + i);
1565 } else {
1566 i += 1;
1567 }
1568 }
1569
1570 // Make sure this candidate is not a duplicate.
1571 if (IsDuplicateRemoteCandidate(remote_candidate)) {
1572 RTC_LOG(LS_INFO) << "Duplicate candidate: "
1573 << remote_candidate.ToSensitiveString();
1574 return;
1575 }
1576
1577 // Try this candidate for all future ports.
1578 remote_candidates_.push_back(RemoteCandidate(remote_candidate, origin_port));
1579 }
1580
1581 // Set options on ourselves is simply setting options on all of our available
1582 // port objects.
SetOption(rtc::Socket::Option opt,int value)1583 int P2PTransportChannel::SetOption(rtc::Socket::Option opt, int value) {
1584 RTC_DCHECK_RUN_ON(network_thread_);
1585 if (ice_field_trials_.override_dscp && opt == rtc::Socket::OPT_DSCP) {
1586 value = *ice_field_trials_.override_dscp;
1587 }
1588
1589 OptionMap::iterator it = options_.find(opt);
1590 if (it == options_.end()) {
1591 options_.insert(std::make_pair(opt, value));
1592 } else if (it->second == value) {
1593 return 0;
1594 } else {
1595 it->second = value;
1596 }
1597
1598 for (PortInterface* port : ports_) {
1599 int val = port->SetOption(opt, value);
1600 if (val < 0) {
1601 // Because this also occurs deferred, probably no point in reporting an
1602 // error
1603 RTC_LOG(LS_WARNING) << "SetOption(" << opt << ", " << value
1604 << ") failed: " << port->GetError();
1605 }
1606 }
1607 return 0;
1608 }
1609
GetOption(rtc::Socket::Option opt,int * value)1610 bool P2PTransportChannel::GetOption(rtc::Socket::Option opt, int* value) {
1611 RTC_DCHECK_RUN_ON(network_thread_);
1612
1613 const auto& found = options_.find(opt);
1614 if (found == options_.end()) {
1615 return false;
1616 }
1617 *value = found->second;
1618 return true;
1619 }
1620
GetError()1621 int P2PTransportChannel::GetError() {
1622 RTC_DCHECK_RUN_ON(network_thread_);
1623 return error_;
1624 }
1625
1626 // Send data to the other side, using our selected connection.
SendPacket(const char * data,size_t len,const rtc::PacketOptions & options,int flags)1627 int P2PTransportChannel::SendPacket(const char* data,
1628 size_t len,
1629 const rtc::PacketOptions& options,
1630 int flags) {
1631 RTC_DCHECK_RUN_ON(network_thread_);
1632 if (flags != 0) {
1633 error_ = EINVAL;
1634 return -1;
1635 }
1636 // If we don't think the connection is working yet, return ENOTCONN
1637 // instead of sending a packet that will probably be dropped.
1638 if (!ReadyToSend(selected_connection_)) {
1639 error_ = ENOTCONN;
1640 return -1;
1641 }
1642
1643 packets_sent_++;
1644 last_sent_packet_id_ = options.packet_id;
1645 rtc::PacketOptions modified_options(options);
1646 modified_options.info_signaled_after_sent.packet_type =
1647 rtc::PacketType::kData;
1648 int sent = selected_connection_->Send(data, len, modified_options);
1649 if (sent <= 0) {
1650 RTC_DCHECK(sent < 0);
1651 error_ = selected_connection_->GetError();
1652 return sent;
1653 }
1654
1655 bytes_sent_ += sent;
1656 return sent;
1657 }
1658
GetStats(IceTransportStats * ice_transport_stats)1659 bool P2PTransportChannel::GetStats(IceTransportStats* ice_transport_stats) {
1660 RTC_DCHECK_RUN_ON(network_thread_);
1661 // Gather candidate and candidate pair stats.
1662 ice_transport_stats->candidate_stats_list.clear();
1663 ice_transport_stats->connection_infos.clear();
1664
1665 if (!allocator_sessions_.empty()) {
1666 allocator_session()->GetCandidateStatsFromReadyPorts(
1667 &ice_transport_stats->candidate_stats_list);
1668 }
1669
1670 // TODO(qingsi): Remove naming inconsistency for candidate pair/connection.
1671 for (Connection* connection : connections()) {
1672 ConnectionInfo stats = connection->stats();
1673 stats.local_candidate = SanitizeLocalCandidate(stats.local_candidate);
1674 stats.remote_candidate = SanitizeRemoteCandidate(stats.remote_candidate);
1675 stats.best_connection = (selected_connection_ == connection);
1676 ice_transport_stats->connection_infos.push_back(std::move(stats));
1677 }
1678
1679 ice_transport_stats->selected_candidate_pair_changes =
1680 selected_candidate_pair_changes_;
1681
1682 ice_transport_stats->bytes_sent = bytes_sent_;
1683 ice_transport_stats->bytes_received = bytes_received_;
1684 ice_transport_stats->packets_sent = packets_sent_;
1685 ice_transport_stats->packets_received = packets_received_;
1686
1687 ice_transport_stats->ice_role = GetIceRole();
1688 ice_transport_stats->ice_local_username_fragment = ice_parameters_.ufrag;
1689 ice_transport_stats->ice_state = ComputeIceTransportState();
1690
1691 return true;
1692 }
1693
network_route() const1694 absl::optional<rtc::NetworkRoute> P2PTransportChannel::network_route() const {
1695 RTC_DCHECK_RUN_ON(network_thread_);
1696 return network_route_;
1697 }
1698
DefaultDscpValue() const1699 rtc::DiffServCodePoint P2PTransportChannel::DefaultDscpValue() const {
1700 RTC_DCHECK_RUN_ON(network_thread_);
1701 OptionMap::const_iterator it = options_.find(rtc::Socket::OPT_DSCP);
1702 if (it == options_.end()) {
1703 return rtc::DSCP_NO_CHANGE;
1704 }
1705 return static_cast<rtc::DiffServCodePoint>(it->second);
1706 }
1707
connections() const1708 rtc::ArrayView<Connection*> P2PTransportChannel::connections() const {
1709 RTC_DCHECK_RUN_ON(network_thread_);
1710 return ice_adapter_->LegacyConnections();
1711 }
1712
RemoveConnectionForTest(Connection * connection)1713 void P2PTransportChannel::RemoveConnectionForTest(Connection* connection) {
1714 RTC_DCHECK_RUN_ON(network_thread_);
1715 RTC_DCHECK(FindConnection(connection));
1716 connection->SignalDestroyed.disconnect(this);
1717 RemoveConnection(connection);
1718 RTC_DCHECK(!FindConnection(connection));
1719 if (selected_connection_ == connection)
1720 selected_connection_ = nullptr;
1721 connection->Destroy();
1722 }
1723
1724 // Monitor connection states.
UpdateConnectionStates()1725 void P2PTransportChannel::UpdateConnectionStates() {
1726 RTC_DCHECK_RUN_ON(network_thread_);
1727 int64_t now = rtc::TimeMillis();
1728
1729 // We need to copy the list of connections since some may delete themselves
1730 // when we call UpdateState.
1731 // NOTE: We copy the connections() vector in case `UpdateState` triggers the
1732 // Connection to be destroyed (which will cause a callback that alters
1733 // the connections() vector).
1734 std::vector<Connection*> copy(connections().begin(), connections().end());
1735 for (Connection* c : copy) {
1736 c->UpdateState(now);
1737 }
1738 }
1739
1740 // Prepare for best candidate sorting.
1741 // TODO(bugs.webrtc.org/14367) remove once refactor lands.
RequestSortAndStateUpdate(IceSwitchReason reason_to_sort)1742 void P2PTransportChannel::RequestSortAndStateUpdate(
1743 IceSwitchReason reason_to_sort) {
1744 RTC_DCHECK_RUN_ON(network_thread_);
1745 if (!sort_dirty_) {
1746 network_thread_->PostTask(
1747 SafeTask(task_safety_.flag(), [this, reason_to_sort]() {
1748 SortConnectionsAndUpdateState(reason_to_sort);
1749 }));
1750 sort_dirty_ = true;
1751 }
1752 }
1753
1754 // TODO(bugs.webrtc.org/14367) remove once refactor lands.
MaybeStartPinging()1755 void P2PTransportChannel::MaybeStartPinging() {
1756 RTC_DCHECK_RUN_ON(network_thread_);
1757 if (started_pinging_) {
1758 return;
1759 }
1760
1761 if (ice_adapter_->LegacyHasPingableConnection()) {
1762 RTC_LOG(LS_INFO) << ToString()
1763 << ": Have a pingable connection for the first time; "
1764 "starting to ping.";
1765 network_thread_->PostTask(
1766 SafeTask(task_safety_.flag(), [this]() { CheckAndPing(); }));
1767 regathering_controller_->Start();
1768 started_pinging_ = true;
1769 }
1770 }
1771
OnStartedPinging()1772 void P2PTransportChannel::OnStartedPinging() {
1773 RTC_DCHECK_RUN_ON(network_thread_);
1774 RTC_LOG(LS_INFO) << ToString()
1775 << ": Have a pingable connection for the first time; "
1776 "starting to ping.";
1777 regathering_controller_->Start();
1778 }
1779
IsPortPruned(const Port * port) const1780 bool P2PTransportChannel::IsPortPruned(const Port* port) const {
1781 RTC_DCHECK_RUN_ON(network_thread_);
1782 return !absl::c_linear_search(ports_, port);
1783 }
1784
IsRemoteCandidatePruned(const Candidate & cand) const1785 bool P2PTransportChannel::IsRemoteCandidatePruned(const Candidate& cand) const {
1786 RTC_DCHECK_RUN_ON(network_thread_);
1787 return !absl::c_linear_search(remote_candidates_, cand);
1788 }
1789
PresumedWritable(const Connection * conn) const1790 bool P2PTransportChannel::PresumedWritable(const Connection* conn) const {
1791 RTC_DCHECK_RUN_ON(network_thread_);
1792 return (conn->write_state() == Connection::STATE_WRITE_INIT &&
1793 config_.presume_writable_when_fully_relayed &&
1794 conn->local_candidate().type() == RELAY_PORT_TYPE &&
1795 (conn->remote_candidate().type() == RELAY_PORT_TYPE ||
1796 conn->remote_candidate().type() == PRFLX_PORT_TYPE));
1797 }
1798
1799 // Sort the available connections to find the best one. We also monitor
1800 // the number of available connections and the current state.
1801 // TODO(bugs.webrtc.org/14367) remove once refactor lands.
SortConnectionsAndUpdateState(IceSwitchReason reason_to_sort)1802 void P2PTransportChannel::SortConnectionsAndUpdateState(
1803 IceSwitchReason reason_to_sort) {
1804 RTC_DCHECK_RUN_ON(network_thread_);
1805
1806 // Make sure the connection states are up-to-date since this affects how they
1807 // will be sorted.
1808 UpdateConnectionStates();
1809
1810 // Any changes after this point will require a re-sort.
1811 sort_dirty_ = false;
1812
1813 // If necessary, switch to the new choice. Note that `top_connection` doesn't
1814 // have to be writable to become the selected connection although it will
1815 // have higher priority if it is writable.
1816 MaybeSwitchSelectedConnection(
1817 reason_to_sort,
1818 ice_adapter_->LegacySortAndSwitchConnection(reason_to_sort));
1819
1820 // The controlled side can prune only if the selected connection has been
1821 // nominated because otherwise it may prune the connection that will be
1822 // selected by the controlling side.
1823 // TODO(honghaiz): This is not enough to prevent a connection from being
1824 // pruned too early because with aggressive nomination, the controlling side
1825 // will nominate every connection until it becomes writable.
1826 if (AllowedToPruneConnections()) {
1827 PruneConnections();
1828 }
1829
1830 // Check if all connections are timedout.
1831 bool all_connections_timedout = true;
1832 for (const Connection* conn : connections()) {
1833 if (conn->write_state() != Connection::STATE_WRITE_TIMEOUT) {
1834 all_connections_timedout = false;
1835 break;
1836 }
1837 }
1838
1839 // Now update the writable state of the channel with the information we have
1840 // so far.
1841 if (all_connections_timedout) {
1842 HandleAllTimedOut();
1843 }
1844
1845 // Update the state of this channel.
1846 UpdateTransportState();
1847
1848 // Also possibly start pinging.
1849 // We could start pinging if:
1850 // * The first connection was created.
1851 // * ICE credentials were provided.
1852 // * A TCP connection became connected.
1853 MaybeStartPinging();
1854 }
1855
UpdateState()1856 void P2PTransportChannel::UpdateState() {
1857 // Check if all connections are timedout.
1858 bool all_connections_timedout = true;
1859 for (const Connection* conn : connections()) {
1860 if (conn->write_state() != Connection::STATE_WRITE_TIMEOUT) {
1861 all_connections_timedout = false;
1862 break;
1863 }
1864 }
1865
1866 // Now update the writable state of the channel with the information we have
1867 // so far.
1868 if (all_connections_timedout) {
1869 HandleAllTimedOut();
1870 }
1871
1872 // Update the state of this channel.
1873 UpdateTransportState();
1874 }
1875
AllowedToPruneConnections() const1876 bool P2PTransportChannel::AllowedToPruneConnections() const {
1877 RTC_DCHECK_RUN_ON(network_thread_);
1878 return ice_role_ == ICEROLE_CONTROLLING ||
1879 (selected_connection_ && selected_connection_->nominated());
1880 }
1881
1882 // TODO(bugs.webrtc.org/14367) remove once refactor lands.
PruneConnections()1883 void P2PTransportChannel::PruneConnections() {
1884 RTC_DCHECK_RUN_ON(network_thread_);
1885 std::vector<const Connection*> connections_to_prune =
1886 ice_adapter_->LegacyPruneConnections();
1887 PruneConnections(connections_to_prune);
1888 }
1889
PruneConnections(rtc::ArrayView<const Connection * const> connections)1890 bool P2PTransportChannel::PruneConnections(
1891 rtc::ArrayView<const Connection* const> connections) {
1892 RTC_DCHECK_RUN_ON(network_thread_);
1893 if (!AllowedToPruneConnections()) {
1894 RTC_LOG(LS_WARNING) << "Not allowed to prune connections";
1895 return false;
1896 }
1897 for (const Connection* conn : connections) {
1898 FromIceController(conn)->Prune();
1899 }
1900 return true;
1901 }
1902
ConfigureNetworkRoute(const Connection * conn)1903 rtc::NetworkRoute P2PTransportChannel::ConfigureNetworkRoute(
1904 const Connection* conn) {
1905 RTC_DCHECK_RUN_ON(network_thread_);
1906 return {
1907 .connected = ReadyToSend(conn),
1908 .local = CreateRouteEndpointFromCandidate(
1909 /* local= */ true, conn->local_candidate(),
1910 /* uses_turn= */
1911 conn->port()->Type() == RELAY_PORT_TYPE),
1912 .remote = CreateRouteEndpointFromCandidate(
1913 /* local= */ false, conn->remote_candidate(),
1914 /* uses_turn= */ conn->remote_candidate().type() == RELAY_PORT_TYPE),
1915 .last_sent_packet_id = last_sent_packet_id_,
1916 .packet_overhead =
1917 conn->local_candidate().address().ipaddr().overhead() +
1918 GetProtocolOverhead(conn->local_candidate().protocol())};
1919 }
1920
SwitchSelectedConnection(const Connection * new_connection,IceSwitchReason reason)1921 void P2PTransportChannel::SwitchSelectedConnection(
1922 const Connection* new_connection,
1923 IceSwitchReason reason) {
1924 RTC_DCHECK_RUN_ON(network_thread_);
1925 SwitchSelectedConnectionInternal(FromIceController(new_connection), reason);
1926 }
1927
1928 // Change the selected connection, and let listeners know.
SwitchSelectedConnectionInternal(Connection * conn,IceSwitchReason reason)1929 void P2PTransportChannel::SwitchSelectedConnectionInternal(
1930 Connection* conn,
1931 IceSwitchReason reason) {
1932 RTC_DCHECK_RUN_ON(network_thread_);
1933 // Note: if conn is NULL, the previous `selected_connection_` has been
1934 // destroyed, so don't use it.
1935 Connection* old_selected_connection = selected_connection_;
1936 selected_connection_ = conn;
1937 LogCandidatePairConfig(conn, webrtc::IceCandidatePairConfigType::kSelected);
1938 network_route_.reset();
1939 if (old_selected_connection) {
1940 old_selected_connection->set_selected(false);
1941 }
1942 if (selected_connection_) {
1943 ++nomination_;
1944 selected_connection_->set_selected(true);
1945 if (old_selected_connection) {
1946 RTC_LOG(LS_INFO) << ToString() << ": Previous selected connection: "
1947 << old_selected_connection->ToString();
1948 }
1949 RTC_LOG(LS_INFO) << ToString() << ": New selected connection: "
1950 << selected_connection_->ToString();
1951 SignalRouteChange(this, selected_connection_->remote_candidate());
1952 // This is a temporary, but safe fix to webrtc issue 5705.
1953 // TODO(honghaiz): Make all ENOTCONN error routed through the transport
1954 // channel so that it knows whether the media channel is allowed to
1955 // send; then it will only signal ready-to-send if the media channel
1956 // has been disallowed to send.
1957 if (selected_connection_->writable() ||
1958 PresumedWritable(selected_connection_)) {
1959 SignalReadyToSend(this);
1960 }
1961
1962 network_route_.emplace(ConfigureNetworkRoute(selected_connection_));
1963 } else {
1964 RTC_LOG(LS_INFO) << ToString() << ": No selected connection";
1965 }
1966
1967 if (conn != nullptr && ice_role_ == ICEROLE_CONTROLLING &&
1968 ((ice_field_trials_.send_ping_on_switch_ice_controlling &&
1969 old_selected_connection != nullptr) ||
1970 ice_field_trials_.send_ping_on_selected_ice_controlling)) {
1971 SendPingRequestInternal(conn);
1972 }
1973
1974 SignalNetworkRouteChanged(network_route_);
1975
1976 // Create event for candidate pair change.
1977 if (selected_connection_) {
1978 CandidatePairChangeEvent pair_change;
1979 pair_change.reason = IceSwitchReasonToString(reason);
1980 pair_change.selected_candidate_pair = *GetSelectedCandidatePair();
1981 pair_change.last_data_received_ms =
1982 selected_connection_->last_data_received();
1983
1984 if (old_selected_connection) {
1985 pair_change.estimated_disconnected_time_ms =
1986 ComputeEstimatedDisconnectedTimeMs(rtc::TimeMillis(),
1987 old_selected_connection);
1988 } else {
1989 pair_change.estimated_disconnected_time_ms = 0;
1990 }
1991
1992 SignalCandidatePairChanged(pair_change);
1993 }
1994
1995 ++selected_candidate_pair_changes_;
1996
1997 ice_adapter_->OnConnectionSwitched(selected_connection_);
1998 }
1999
ComputeEstimatedDisconnectedTimeMs(int64_t now_ms,Connection * old_connection)2000 int64_t P2PTransportChannel::ComputeEstimatedDisconnectedTimeMs(
2001 int64_t now_ms,
2002 Connection* old_connection) {
2003 // TODO(jonaso): nicer keeps estimate of how frequently data _should_ be
2004 // received, this could be used to give better estimate (if needed).
2005 int64_t last_data_or_old_ping =
2006 std::max(old_connection->last_received(), last_data_received_ms_);
2007 return (now_ms - last_data_or_old_ping);
2008 }
2009
2010 // Warning: UpdateTransportState should eventually be called whenever a
2011 // connection is added, deleted, or the write state of any connection changes so
2012 // that the transport controller will get the up-to-date channel state. However
2013 // it should not be called too often; in the case that multiple connection
2014 // states change, it should be called after all the connection states have
2015 // changed. For example, we call this at the end of
2016 // SortConnectionsAndUpdateState.
UpdateTransportState()2017 void P2PTransportChannel::UpdateTransportState() {
2018 RTC_DCHECK_RUN_ON(network_thread_);
2019 // If our selected connection is "presumed writable" (TURN-TURN with no
2020 // CreatePermission required), act like we're already writable to the upper
2021 // layers, so they can start media quicker.
2022 bool writable =
2023 selected_connection_ && (selected_connection_->writable() ||
2024 PresumedWritable(selected_connection_));
2025 SetWritable(writable);
2026
2027 bool receiving = false;
2028 for (const Connection* connection : connections()) {
2029 if (connection->receiving()) {
2030 receiving = true;
2031 break;
2032 }
2033 }
2034 SetReceiving(receiving);
2035
2036 IceTransportState state = ComputeState();
2037 webrtc::IceTransportState current_standardized_state =
2038 ComputeIceTransportState();
2039
2040 if (state_ != state) {
2041 RTC_LOG(LS_INFO) << ToString() << ": Transport channel state changed from "
2042 << static_cast<int>(state_) << " to "
2043 << static_cast<int>(state);
2044 // Check that the requested transition is allowed. Note that
2045 // P2PTransportChannel does not (yet) implement a direct mapping of the
2046 // ICE states from the standard; the difference is covered by
2047 // TransportController and PeerConnection.
2048 switch (state_) {
2049 case IceTransportState::STATE_INIT:
2050 // TODO(deadbeef): Once we implement end-of-candidates signaling,
2051 // we shouldn't go from INIT to COMPLETED.
2052 RTC_DCHECK(state == IceTransportState::STATE_CONNECTING ||
2053 state == IceTransportState::STATE_COMPLETED ||
2054 state == IceTransportState::STATE_FAILED);
2055 break;
2056 case IceTransportState::STATE_CONNECTING:
2057 RTC_DCHECK(state == IceTransportState::STATE_COMPLETED ||
2058 state == IceTransportState::STATE_FAILED);
2059 break;
2060 case IceTransportState::STATE_COMPLETED:
2061 // TODO(deadbeef): Once we implement end-of-candidates signaling,
2062 // we shouldn't go from COMPLETED to CONNECTING.
2063 // Though we *can* go from COMPlETED to FAILED, if consent expires.
2064 RTC_DCHECK(state == IceTransportState::STATE_CONNECTING ||
2065 state == IceTransportState::STATE_FAILED);
2066 break;
2067 case IceTransportState::STATE_FAILED:
2068 // TODO(deadbeef): Once we implement end-of-candidates signaling,
2069 // we shouldn't go from FAILED to CONNECTING or COMPLETED.
2070 RTC_DCHECK(state == IceTransportState::STATE_CONNECTING ||
2071 state == IceTransportState::STATE_COMPLETED);
2072 break;
2073 default:
2074 RTC_DCHECK_NOTREACHED();
2075 break;
2076 }
2077 state_ = state;
2078 SignalStateChanged(this);
2079 }
2080
2081 if (standardized_state_ != current_standardized_state) {
2082 standardized_state_ = current_standardized_state;
2083 SignalIceTransportStateChanged(this);
2084 }
2085 }
2086
MaybeStopPortAllocatorSessions()2087 void P2PTransportChannel::MaybeStopPortAllocatorSessions() {
2088 RTC_DCHECK_RUN_ON(network_thread_);
2089 if (!IsGettingPorts()) {
2090 return;
2091 }
2092
2093 for (const auto& session : allocator_sessions_) {
2094 if (session->IsStopped()) {
2095 continue;
2096 }
2097 // If gathering continually, keep the last session running so that
2098 // it can gather candidates if the networks change.
2099 if (config_.gather_continually() && session == allocator_sessions_.back()) {
2100 session->ClearGettingPorts();
2101 } else {
2102 session->StopGettingPorts();
2103 }
2104 }
2105 }
2106
OnSelectedConnectionDestroyed()2107 void P2PTransportChannel::OnSelectedConnectionDestroyed() {
2108 RTC_DCHECK_RUN_ON(network_thread_);
2109 RTC_LOG(LS_INFO) << "Selected connection destroyed. Will choose a new one.";
2110 IceSwitchReason reason = IceSwitchReason::SELECTED_CONNECTION_DESTROYED;
2111 SwitchSelectedConnectionInternal(nullptr, reason);
2112 ice_adapter_->OnSortAndSwitchRequest(reason);
2113 }
2114
2115 // If all connections timed out, delete them all.
HandleAllTimedOut()2116 void P2PTransportChannel::HandleAllTimedOut() {
2117 RTC_DCHECK_RUN_ON(network_thread_);
2118 bool update_selected_connection = false;
2119 std::vector<Connection*> copy(connections().begin(), connections().end());
2120 for (Connection* connection : copy) {
2121 if (selected_connection_ == connection) {
2122 selected_connection_ = nullptr;
2123 update_selected_connection = true;
2124 }
2125 connection->SignalDestroyed.disconnect(this);
2126 RemoveConnection(connection);
2127 connection->Destroy();
2128 }
2129
2130 if (update_selected_connection)
2131 OnSelectedConnectionDestroyed();
2132 }
2133
ReadyToSend(const Connection * connection) const2134 bool P2PTransportChannel::ReadyToSend(const Connection* connection) const {
2135 RTC_DCHECK_RUN_ON(network_thread_);
2136 // Note that we allow sending on an unreliable connection, because it's
2137 // possible that it became unreliable simply due to bad chance.
2138 // So this shouldn't prevent attempting to send media.
2139 return connection != nullptr &&
2140 (connection->writable() ||
2141 connection->write_state() == Connection::STATE_WRITE_UNRELIABLE ||
2142 PresumedWritable(connection));
2143 }
2144
2145 // Handle queued up check-and-ping request
2146 // TODO(bugs.webrtc.org/14367) remove once refactor lands.
CheckAndPing()2147 void P2PTransportChannel::CheckAndPing() {
2148 RTC_DCHECK_RUN_ON(network_thread_);
2149 // Make sure the states of the connections are up-to-date (since this
2150 // affects which ones are pingable).
2151 UpdateConnectionStates();
2152
2153 auto result = ice_adapter_->LegacySelectConnectionToPing(last_ping_sent_ms_);
2154 TimeDelta delay = TimeDelta::Millis(result.recheck_delay_ms);
2155
2156 if (result.connection.value_or(nullptr)) {
2157 SendPingRequest(result.connection.value());
2158 }
2159
2160 network_thread_->PostDelayedTask(
2161 SafeTask(task_safety_.flag(), [this]() { CheckAndPing(); }), delay);
2162 }
2163
2164 // This method is only for unit testing.
FindNextPingableConnection()2165 Connection* P2PTransportChannel::FindNextPingableConnection() {
2166 RTC_DCHECK_RUN_ON(network_thread_);
2167 const Connection* conn = ice_adapter_->FindNextPingableConnection();
2168 if (conn) {
2169 return FromIceController(conn);
2170 } else {
2171 return nullptr;
2172 }
2173 }
2174
GetLastPingSentMs() const2175 int64_t P2PTransportChannel::GetLastPingSentMs() const {
2176 RTC_DCHECK_RUN_ON(network_thread_);
2177 return last_ping_sent_ms_;
2178 }
2179
SendPingRequest(const Connection * connection)2180 void P2PTransportChannel::SendPingRequest(const Connection* connection) {
2181 RTC_DCHECK_RUN_ON(network_thread_);
2182 SendPingRequestInternal(FromIceController(connection));
2183 }
2184
SendPingRequestInternal(Connection * connection)2185 void P2PTransportChannel::SendPingRequestInternal(Connection* connection) {
2186 RTC_DCHECK_RUN_ON(network_thread_);
2187 PingConnection(connection);
2188 MarkConnectionPinged(connection);
2189 }
2190
2191 // A connection is considered a backup connection if the channel state
2192 // is completed, the connection is not the selected connection and it is
2193 // active.
MarkConnectionPinged(Connection * conn)2194 void P2PTransportChannel::MarkConnectionPinged(Connection* conn) {
2195 RTC_DCHECK_RUN_ON(network_thread_);
2196 ice_adapter_->OnConnectionPinged(conn);
2197 }
2198
2199 // Apart from sending ping from `conn` this method also updates
2200 // `use_candidate_attr` and `nomination` flags. One of the flags is set to
2201 // nominate `conn` if this channel is in CONTROLLING.
PingConnection(Connection * conn)2202 void P2PTransportChannel::PingConnection(Connection* conn) {
2203 RTC_DCHECK_RUN_ON(network_thread_);
2204 bool use_candidate_attr = false;
2205 uint32_t nomination = 0;
2206 if (ice_role_ == ICEROLE_CONTROLLING) {
2207 bool renomination_supported = ice_parameters_.renomination &&
2208 !remote_ice_parameters_.empty() &&
2209 remote_ice_parameters_.back().renomination;
2210 if (renomination_supported) {
2211 nomination = GetNominationAttr(conn);
2212 } else {
2213 use_candidate_attr = GetUseCandidateAttr(conn);
2214 }
2215 }
2216 conn->set_nomination(nomination);
2217 conn->set_use_candidate_attr(use_candidate_attr);
2218 last_ping_sent_ms_ = rtc::TimeMillis();
2219 conn->Ping(last_ping_sent_ms_);
2220 }
2221
GetNominationAttr(Connection * conn) const2222 uint32_t P2PTransportChannel::GetNominationAttr(Connection* conn) const {
2223 RTC_DCHECK_RUN_ON(network_thread_);
2224 return (conn == selected_connection_) ? nomination_ : 0;
2225 }
2226
2227 // Nominate a connection based on the NominationMode.
GetUseCandidateAttr(Connection * conn) const2228 bool P2PTransportChannel::GetUseCandidateAttr(Connection* conn) const {
2229 RTC_DCHECK_RUN_ON(network_thread_);
2230 return ice_adapter_->GetUseCandidateAttribute(
2231 conn, config_.default_nomination_mode, remote_ice_mode_);
2232 }
2233
2234 // When a connection's state changes, we need to figure out who to use as
2235 // the selected connection again. It could have become usable, or become
2236 // unusable.
OnConnectionStateChange(Connection * connection)2237 void P2PTransportChannel::OnConnectionStateChange(Connection* connection) {
2238 RTC_DCHECK_RUN_ON(network_thread_);
2239
2240 // May stop the allocator session when at least one connection becomes
2241 // strongly connected after starting to get ports and the local candidate of
2242 // the connection is at the latest generation. It is not enough to check
2243 // that the connection becomes weakly connected because the connection may
2244 // be changing from (writable, receiving) to (writable, not receiving).
2245 if (ice_field_trials_.stop_gather_on_strongly_connected) {
2246 bool strongly_connected = !connection->weak();
2247 bool latest_generation = connection->local_candidate().generation() >=
2248 allocator_session()->generation();
2249 if (strongly_connected && latest_generation) {
2250 MaybeStopPortAllocatorSessions();
2251 }
2252 }
2253 // We have to unroll the stack before doing this because we may be changing
2254 // the state of connections while sorting.
2255 ice_adapter_->OnSortAndSwitchRequest(
2256 IceSwitchReason::CONNECT_STATE_CHANGE); // "candidate pair state
2257 // changed");
2258 }
2259
2260 // When a connection is removed, edit it out, and then update our best
2261 // connection.
OnConnectionDestroyed(Connection * connection)2262 void P2PTransportChannel::OnConnectionDestroyed(Connection* connection) {
2263 RTC_DCHECK_RUN_ON(network_thread_);
2264
2265 // Note: the previous selected_connection_ may be destroyed by now, so don't
2266 // use it.
2267
2268 // Remove this connection from the list.
2269 RemoveConnection(connection);
2270
2271 RTC_LOG(LS_INFO) << ToString() << ": Removed connection " << connection
2272 << " (" << connections().size() << " remaining)";
2273
2274 // If this is currently the selected connection, then we need to pick a new
2275 // one. The call to SortConnectionsAndUpdateState will pick a new one. It
2276 // looks at the current selected connection in order to avoid switching
2277 // between fairly similar ones. Since this connection is no longer an
2278 // option, we can just set selected to nullptr and re-choose a best assuming
2279 // that there was no selected connection.
2280 if (selected_connection_ == connection) {
2281 OnSelectedConnectionDestroyed();
2282 } else {
2283 // If a non-selected connection was destroyed, we don't need to re-sort but
2284 // we do need to update state, because we could be switching to "failed" or
2285 // "completed".
2286 UpdateTransportState();
2287 }
2288 }
2289
RemoveConnection(const Connection * connection)2290 void P2PTransportChannel::RemoveConnection(const Connection* connection) {
2291 RTC_DCHECK_RUN_ON(network_thread_);
2292 auto it = absl::c_find(connections_, connection);
2293 RTC_DCHECK(it != connections_.end());
2294 connections_.erase(it);
2295 ice_adapter_->OnConnectionDestroyed(connection);
2296 }
2297
2298 // When a port is destroyed, remove it from our list of ports to use for
2299 // connection attempts.
OnPortDestroyed(PortInterface * port)2300 void P2PTransportChannel::OnPortDestroyed(PortInterface* port) {
2301 RTC_DCHECK_RUN_ON(network_thread_);
2302
2303 ports_.erase(std::remove(ports_.begin(), ports_.end(), port), ports_.end());
2304 pruned_ports_.erase(
2305 std::remove(pruned_ports_.begin(), pruned_ports_.end(), port),
2306 pruned_ports_.end());
2307 RTC_LOG(LS_INFO) << "Removed port because it is destroyed: " << ports_.size()
2308 << " remaining";
2309 }
2310
OnPortsPruned(PortAllocatorSession * session,const std::vector<PortInterface * > & ports)2311 void P2PTransportChannel::OnPortsPruned(
2312 PortAllocatorSession* session,
2313 const std::vector<PortInterface*>& ports) {
2314 RTC_DCHECK_RUN_ON(network_thread_);
2315 for (PortInterface* port : ports) {
2316 if (PrunePort(port)) {
2317 RTC_LOG(LS_INFO) << "Removed port: " << port->ToString() << " "
2318 << ports_.size() << " remaining";
2319 }
2320 }
2321 }
2322
OnCandidatesRemoved(PortAllocatorSession * session,const std::vector<Candidate> & candidates)2323 void P2PTransportChannel::OnCandidatesRemoved(
2324 PortAllocatorSession* session,
2325 const std::vector<Candidate>& candidates) {
2326 RTC_DCHECK_RUN_ON(network_thread_);
2327 // Do not signal candidate removals if continual gathering is not enabled,
2328 // or if this is not the last session because an ICE restart would have
2329 // signaled the remote side to remove all candidates in previous sessions.
2330 if (!config_.gather_continually() || session != allocator_session()) {
2331 return;
2332 }
2333
2334 std::vector<Candidate> candidates_to_remove;
2335 for (Candidate candidate : candidates) {
2336 candidate.set_transport_name(transport_name());
2337 candidates_to_remove.push_back(candidate);
2338 }
2339 SignalCandidatesRemoved(this, candidates_to_remove);
2340 }
2341
PruneAllPorts()2342 void P2PTransportChannel::PruneAllPorts() {
2343 RTC_DCHECK_RUN_ON(network_thread_);
2344 pruned_ports_.insert(pruned_ports_.end(), ports_.begin(), ports_.end());
2345 ports_.clear();
2346 }
2347
PrunePort(PortInterface * port)2348 bool P2PTransportChannel::PrunePort(PortInterface* port) {
2349 RTC_DCHECK_RUN_ON(network_thread_);
2350 auto it = absl::c_find(ports_, port);
2351 // Don't need to do anything if the port has been deleted from the port
2352 // list.
2353 if (it == ports_.end()) {
2354 return false;
2355 }
2356 ports_.erase(it);
2357 pruned_ports_.push_back(port);
2358 return true;
2359 }
2360
2361 // We data is available, let listeners know
OnReadPacket(Connection * connection,const char * data,size_t len,int64_t packet_time_us)2362 void P2PTransportChannel::OnReadPacket(Connection* connection,
2363 const char* data,
2364 size_t len,
2365 int64_t packet_time_us) {
2366 RTC_DCHECK_RUN_ON(network_thread_);
2367
2368 if (connection == selected_connection_) {
2369 // Let the client know of an incoming packet
2370 packets_received_++;
2371 bytes_received_ += len;
2372 RTC_DCHECK(connection->last_data_received() >= last_data_received_ms_);
2373 last_data_received_ms_ =
2374 std::max(last_data_received_ms_, connection->last_data_received());
2375 SignalReadPacket(this, data, len, packet_time_us, 0);
2376 return;
2377 }
2378
2379 // Do not deliver, if packet doesn't belong to the correct transport
2380 // channel.
2381 if (!FindConnection(connection))
2382 return;
2383
2384 packets_received_++;
2385 bytes_received_ += len;
2386 RTC_DCHECK(connection->last_data_received() >= last_data_received_ms_);
2387 last_data_received_ms_ =
2388 std::max(last_data_received_ms_, connection->last_data_received());
2389
2390 // Let the client know of an incoming packet
2391 SignalReadPacket(this, data, len, packet_time_us, 0);
2392
2393 // May need to switch the sending connection based on the receiving media
2394 // path if this is the controlled side.
2395 if (ice_role_ == ICEROLE_CONTROLLED) {
2396 ice_adapter_->OnImmediateSwitchRequest(IceSwitchReason::DATA_RECEIVED,
2397 connection);
2398 }
2399 }
2400
OnSentPacket(const rtc::SentPacket & sent_packet)2401 void P2PTransportChannel::OnSentPacket(const rtc::SentPacket& sent_packet) {
2402 RTC_DCHECK_RUN_ON(network_thread_);
2403
2404 SignalSentPacket(this, sent_packet);
2405 }
2406
OnReadyToSend(Connection * connection)2407 void P2PTransportChannel::OnReadyToSend(Connection* connection) {
2408 RTC_DCHECK_RUN_ON(network_thread_);
2409 if (connection == selected_connection_ && writable()) {
2410 SignalReadyToSend(this);
2411 }
2412 }
2413
SetWritable(bool writable)2414 void P2PTransportChannel::SetWritable(bool writable) {
2415 RTC_DCHECK_RUN_ON(network_thread_);
2416 if (writable_ == writable) {
2417 return;
2418 }
2419 RTC_LOG(LS_VERBOSE) << ToString() << ": Changed writable_ to " << writable;
2420 writable_ = writable;
2421 if (writable_) {
2422 has_been_writable_ = true;
2423 SignalReadyToSend(this);
2424 }
2425 SignalWritableState(this);
2426 }
2427
SetReceiving(bool receiving)2428 void P2PTransportChannel::SetReceiving(bool receiving) {
2429 RTC_DCHECK_RUN_ON(network_thread_);
2430 if (receiving_ == receiving) {
2431 return;
2432 }
2433 receiving_ = receiving;
2434 SignalReceivingState(this);
2435 }
2436
SanitizeLocalCandidate(const Candidate & c) const2437 Candidate P2PTransportChannel::SanitizeLocalCandidate(
2438 const Candidate& c) const {
2439 RTC_DCHECK_RUN_ON(network_thread_);
2440 // Delegates to the port allocator.
2441 return allocator_->SanitizeCandidate(c);
2442 }
2443
SanitizeRemoteCandidate(const Candidate & c) const2444 Candidate P2PTransportChannel::SanitizeRemoteCandidate(
2445 const Candidate& c) const {
2446 RTC_DCHECK_RUN_ON(network_thread_);
2447 // If the remote endpoint signaled us an mDNS candidate, we assume it
2448 // is supposed to be sanitized.
2449 bool use_hostname_address = absl::EndsWith(c.address().hostname(), LOCAL_TLD);
2450 // Remove the address for prflx remote candidates. See
2451 // https://w3c.github.io/webrtc-stats/#dom-rtcicecandidatestats.
2452 use_hostname_address |= c.type() == PRFLX_PORT_TYPE;
2453 return c.ToSanitizedCopy(use_hostname_address,
2454 false /* filter_related_address */);
2455 }
2456
LogCandidatePairConfig(Connection * conn,webrtc::IceCandidatePairConfigType type)2457 void P2PTransportChannel::LogCandidatePairConfig(
2458 Connection* conn,
2459 webrtc::IceCandidatePairConfigType type) {
2460 RTC_DCHECK_RUN_ON(network_thread_);
2461 if (conn == nullptr) {
2462 return;
2463 }
2464 ice_event_log_.LogCandidatePairConfig(type, conn->id(),
2465 conn->ToLogDescription());
2466 }
2467
IceControllerAdapter(const IceControllerFactoryArgs & args,IceControllerFactoryInterface * ice_controller_factory,ActiveIceControllerFactoryInterface * active_ice_controller_factory,const webrtc::FieldTrialsView * field_trials,P2PTransportChannel * transport)2468 P2PTransportChannel::IceControllerAdapter::IceControllerAdapter(
2469 const IceControllerFactoryArgs& args,
2470 IceControllerFactoryInterface* ice_controller_factory,
2471 ActiveIceControllerFactoryInterface* active_ice_controller_factory,
2472 const webrtc::FieldTrialsView* field_trials,
2473 P2PTransportChannel* transport)
2474 : transport_(transport) {
2475 if (UseActiveIceControllerFieldTrialEnabled(field_trials)) {
2476 if (active_ice_controller_factory) {
2477 ActiveIceControllerFactoryArgs active_args{args,
2478 /* ice_agent= */ transport};
2479 active_ice_controller_ =
2480 active_ice_controller_factory->Create(active_args);
2481 } else {
2482 active_ice_controller_ = std::make_unique<WrappingActiveIceController>(
2483 /* ice_agent= */ transport, ice_controller_factory, args);
2484 }
2485 } else {
2486 if (ice_controller_factory != nullptr) {
2487 legacy_ice_controller_ = ice_controller_factory->Create(args);
2488 } else {
2489 legacy_ice_controller_ = std::make_unique<BasicIceController>(args);
2490 }
2491 }
2492 }
2493
2494 P2PTransportChannel::IceControllerAdapter::~IceControllerAdapter() = default;
2495
SetIceConfig(const IceConfig & config)2496 void P2PTransportChannel::IceControllerAdapter::SetIceConfig(
2497 const IceConfig& config) {
2498 active_ice_controller_ ? active_ice_controller_->SetIceConfig(config)
2499 : legacy_ice_controller_->SetIceConfig(config);
2500 }
2501
OnConnectionAdded(const Connection * connection)2502 void P2PTransportChannel::IceControllerAdapter::OnConnectionAdded(
2503 const Connection* connection) {
2504 active_ice_controller_ ? active_ice_controller_->OnConnectionAdded(connection)
2505 : legacy_ice_controller_->AddConnection(connection);
2506 }
2507
OnConnectionSwitched(const Connection * connection)2508 void P2PTransportChannel::IceControllerAdapter::OnConnectionSwitched(
2509 const Connection* connection) {
2510 active_ice_controller_
2511 ? active_ice_controller_->OnConnectionSwitched(connection)
2512 : legacy_ice_controller_->SetSelectedConnection(connection);
2513 }
2514
OnConnectionPinged(const Connection * connection)2515 void P2PTransportChannel::IceControllerAdapter::OnConnectionPinged(
2516 const Connection* connection) {
2517 active_ice_controller_
2518 ? active_ice_controller_->OnConnectionPinged(connection)
2519 : legacy_ice_controller_->MarkConnectionPinged(connection);
2520 }
2521
OnConnectionDestroyed(const Connection * connection)2522 void P2PTransportChannel::IceControllerAdapter::OnConnectionDestroyed(
2523 const Connection* connection) {
2524 active_ice_controller_
2525 ? active_ice_controller_->OnConnectionDestroyed(connection)
2526 : legacy_ice_controller_->OnConnectionDestroyed(connection);
2527 }
2528
OnConnectionUpdated(const Connection * connection)2529 void P2PTransportChannel::IceControllerAdapter::OnConnectionUpdated(
2530 const Connection* connection) {
2531 if (active_ice_controller_) {
2532 active_ice_controller_->OnConnectionUpdated(connection);
2533 return;
2534 }
2535 RTC_DCHECK_NOTREACHED();
2536 }
2537
OnSortAndSwitchRequest(IceSwitchReason reason)2538 void P2PTransportChannel::IceControllerAdapter::OnSortAndSwitchRequest(
2539 IceSwitchReason reason) {
2540 active_ice_controller_
2541 ? active_ice_controller_->OnSortAndSwitchRequest(reason)
2542 : transport_->RequestSortAndStateUpdate(reason);
2543 }
2544
OnImmediateSortAndSwitchRequest(IceSwitchReason reason)2545 void P2PTransportChannel::IceControllerAdapter::OnImmediateSortAndSwitchRequest(
2546 IceSwitchReason reason) {
2547 active_ice_controller_
2548 ? active_ice_controller_->OnImmediateSortAndSwitchRequest(reason)
2549 : transport_->SortConnectionsAndUpdateState(reason);
2550 }
2551
OnImmediateSwitchRequest(IceSwitchReason reason,const Connection * connection)2552 bool P2PTransportChannel::IceControllerAdapter::OnImmediateSwitchRequest(
2553 IceSwitchReason reason,
2554 const Connection* connection) {
2555 return active_ice_controller_
2556 ? active_ice_controller_->OnImmediateSwitchRequest(reason,
2557 connection)
2558 : transport_->MaybeSwitchSelectedConnection(connection, reason);
2559 }
2560
GetUseCandidateAttribute(const cricket::Connection * connection,cricket::NominationMode mode,cricket::IceMode remote_ice_mode) const2561 bool P2PTransportChannel::IceControllerAdapter::GetUseCandidateAttribute(
2562 const cricket::Connection* connection,
2563 cricket::NominationMode mode,
2564 cricket::IceMode remote_ice_mode) const {
2565 return active_ice_controller_
2566 ? active_ice_controller_->GetUseCandidateAttribute(
2567 connection, mode, remote_ice_mode)
2568 : legacy_ice_controller_->GetUseCandidateAttr(connection, mode,
2569 remote_ice_mode);
2570 }
2571
2572 const Connection*
FindNextPingableConnection()2573 P2PTransportChannel::IceControllerAdapter::FindNextPingableConnection() {
2574 return active_ice_controller_
2575 ? active_ice_controller_->FindNextPingableConnection()
2576 : legacy_ice_controller_->FindNextPingableConnection();
2577 }
2578
2579 rtc::ArrayView<Connection*>
LegacyConnections() const2580 P2PTransportChannel::IceControllerAdapter::LegacyConnections() const {
2581 RTC_DCHECK_RUN_ON(transport_->network_thread_);
2582 if (active_ice_controller_) {
2583 return rtc::ArrayView<Connection*>(transport_->connections_.data(),
2584 transport_->connections_.size());
2585 }
2586
2587 rtc::ArrayView<const Connection*> res = legacy_ice_controller_->connections();
2588 return rtc::ArrayView<Connection*>(const_cast<Connection**>(res.data()),
2589 res.size());
2590 }
2591
LegacyHasPingableConnection() const2592 bool P2PTransportChannel::IceControllerAdapter::LegacyHasPingableConnection()
2593 const {
2594 if (active_ice_controller_) {
2595 RTC_DCHECK_NOTREACHED();
2596 }
2597 return legacy_ice_controller_->HasPingableConnection();
2598 }
2599
2600 IceControllerInterface::PingResult
LegacySelectConnectionToPing(int64_t last_ping_sent_ms)2601 P2PTransportChannel::IceControllerAdapter::LegacySelectConnectionToPing(
2602 int64_t last_ping_sent_ms) {
2603 if (active_ice_controller_) {
2604 RTC_DCHECK_NOTREACHED();
2605 }
2606 return legacy_ice_controller_->SelectConnectionToPing(last_ping_sent_ms);
2607 }
2608
2609 IceControllerInterface::SwitchResult
LegacyShouldSwitchConnection(IceSwitchReason reason,const Connection * connection)2610 P2PTransportChannel::IceControllerAdapter::LegacyShouldSwitchConnection(
2611 IceSwitchReason reason,
2612 const Connection* connection) {
2613 if (active_ice_controller_) {
2614 RTC_DCHECK_NOTREACHED();
2615 }
2616 return legacy_ice_controller_->ShouldSwitchConnection(reason, connection);
2617 }
2618
2619 IceControllerInterface::SwitchResult
LegacySortAndSwitchConnection(IceSwitchReason reason)2620 P2PTransportChannel::IceControllerAdapter::LegacySortAndSwitchConnection(
2621 IceSwitchReason reason) {
2622 if (active_ice_controller_) {
2623 RTC_DCHECK_NOTREACHED();
2624 }
2625 return legacy_ice_controller_->SortAndSwitchConnection(reason);
2626 }
2627
2628 std::vector<const Connection*>
LegacyPruneConnections()2629 P2PTransportChannel::IceControllerAdapter::LegacyPruneConnections() {
2630 if (active_ice_controller_) {
2631 RTC_DCHECK_NOTREACHED();
2632 }
2633 return legacy_ice_controller_->PruneConnections();
2634 }
2635
2636 } // namespace cricket
2637