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