blob: 90fe07c275e565f43c94474fdbecde48d8b138ab [file] [log] [blame]
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001/*
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 "webrtc/p2p/base/p2ptransportchannel.h"
12
deadbeefcbecd352015-09-23 11:50:27 -070013#include <algorithm>
honghaiz7252a002016-11-08 20:04:09 -080014#include <iterator>
honghaiza58ea782015-09-24 08:13:36 -070015#include <set>
honghaize3c6c822016-02-17 13:00:28 -080016
skvlad1d3c7e02017-01-11 17:50:30 -080017#include "webrtc/api/umametrics.h"
honghaize3c6c822016-02-17 13:00:28 -080018#include "webrtc/p2p/base/candidate.h"
Honghai Zhangcc411c02016-03-29 17:27:21 -070019#include "webrtc/p2p/base/candidatepairinterface.h"
honghaize3c6c822016-02-17 13:00:28 -080020#include "webrtc/p2p/base/common.h"
21#include "webrtc/p2p/base/relayport.h" // For RELAY_PORT_TYPE.
22#include "webrtc/p2p/base/stunport.h" // For STUN_PORT_TYPE.
Edward Lemurc20978e2017-07-06 19:44:34 +020023#include "webrtc/rtc_base/checks.h"
24#include "webrtc/rtc_base/crc32.h"
25#include "webrtc/rtc_base/logging.h"
26#include "webrtc/rtc_base/stringencode.h"
Steve Anton300bf8e2017-07-14 10:13:10 -070027#include "webrtc/rtc_base/timeutils.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010028#include "webrtc/system_wrappers/include/field_trial.h"
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000029
30namespace {
31
32// messages for queuing up work for ourselves
Honghai Zhang5622c5e2016-07-01 13:59:29 -070033enum {
34 MSG_SORT_AND_UPDATE_STATE = 1,
35 MSG_CHECK_AND_PING,
Steve Anton300bf8e2017-07-14 10:13:10 -070036 MSG_REGATHER_ON_FAILED_NETWORKS,
37 MSG_REGATHER_ON_ALL_NETWORKS
Honghai Zhang5622c5e2016-07-01 13:59:29 -070038};
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000039
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000040// The minimum improvement in RTT that justifies a switch.
Honghai Zhang5622c5e2016-07-01 13:59:29 -070041const int kMinImprovement = 10;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000042
deadbeef14f97f52016-06-22 17:14:15 -070043bool IsRelayRelay(const cricket::Connection* conn) {
guoweis36f01372016-03-02 18:02:40 -080044 return conn->local_candidate().type() == cricket::RELAY_PORT_TYPE &&
45 conn->remote_candidate().type() == cricket::RELAY_PORT_TYPE;
46}
47
48bool IsUdp(cricket::Connection* conn) {
49 return conn->local_candidate().relay_protocol() == cricket::UDP_PROTOCOL_NAME;
50}
51
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000052cricket::PortInterface::CandidateOrigin GetOrigin(cricket::PortInterface* port,
53 cricket::PortInterface* origin_port) {
54 if (!origin_port)
55 return cricket::PortInterface::ORIGIN_MESSAGE;
56 else if (port == origin_port)
57 return cricket::PortInterface::ORIGIN_THIS_PORT;
58 else
59 return cricket::PortInterface::ORIGIN_OTHER_PORT;
60}
61
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000062} // unnamed namespace
63
64namespace cricket {
65
guoweisb0bb77f2015-10-26 15:10:01 -070066// When the socket is unwritable, we will use 10 Kbps (ignoring IP+UDP headers)
67// for pinging. When the socket is writable, we will use only 1 Kbps because
68// we don't want to degrade the quality on a modem. These numbers should work
69// well on a 28.8K modem, which is the slowest connection on which the voice
70// quality is reasonable at all.
Honghai Zhang049fbb12016-03-07 11:13:07 -080071static const int PING_PACKET_SIZE = 60 * 8;
honghaiz7252a002016-11-08 20:04:09 -080072
73// The next two ping intervals are at the channel level.
Honghai Zhang572b0942016-06-23 12:26:57 -070074// STRONG_PING_INTERVAL (480ms) is applied when the selected connection is both
guoweisb0bb77f2015-10-26 15:10:01 -070075// writable and receiving.
skvlad51072462017-02-02 11:50:14 -080076const int STRONG_PING_INTERVAL = 1000 * PING_PACKET_SIZE / 1000;
Honghai Zhang572b0942016-06-23 12:26:57 -070077// WEAK_PING_INTERVAL (48ms) is applied when the selected connection is either
78// not writable or not receiving.
Honghai Zhang049fbb12016-03-07 11:13:07 -080079const int WEAK_PING_INTERVAL = 1000 * PING_PACKET_SIZE / 10000;
guoweisb0bb77f2015-10-26 15:10:01 -070080
honghaiz7252a002016-11-08 20:04:09 -080081// The next two ping intervals are at the connection level.
82// Writable connections are pinged at a faster rate while the connections are
83// stabilizing or the channel is weak.
84const int WEAK_OR_STABILIZING_WRITABLE_CONNECTION_PING_INTERVAL = 900; // ms
85// Writable connections are pinged at a slower rate once they are stabilized and
86// the channel is strongly connected.
87const int STRONG_AND_STABLE_WRITABLE_CONNECTION_PING_INTERVAL = 2500; // ms
guoweisb0bb77f2015-10-26 15:10:01 -070088
Honghai Zhang049fbb12016-03-07 11:13:07 -080089static const int MIN_CHECK_RECEIVING_INTERVAL = 50; // ms
guoweisb0bb77f2015-10-26 15:10:01 -070090
honghaiz9ad0db52016-07-14 19:30:28 -070091static const int RECEIVING_SWITCHING_DELAY = 1000; // ms
92
Honghai Zhang5622c5e2016-07-01 13:59:29 -070093// We periodically check if any existing networks do not have any connection
94// and regather on those networks.
95static const int DEFAULT_REGATHER_ON_FAILED_NETWORKS_INTERVAL = 5 * 60 * 1000;
Honghai Zhang895e1a92016-08-16 16:48:02 -070096
97static constexpr int DEFAULT_BACKUP_CONNECTION_PING_INTERVAL = 25 * 1000;
98
Honghai Zhang572b0942016-06-23 12:26:57 -070099static constexpr int a_is_better = 1;
100static constexpr int b_is_better = -1;
101
deadbeefcbecd352015-09-23 11:50:27 -0700102P2PTransportChannel::P2PTransportChannel(const std::string& transport_name,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000103 int component,
mikescarlettb9dd7c52016-02-19 20:43:45 -0800104 PortAllocator* allocator)
zhihuangd06adf62017-01-12 15:58:31 -0800105 : transport_name_(transport_name),
106 component_(component),
deadbeefcbecd352015-09-23 11:50:27 -0700107 allocator_(allocator),
johan0fd22ef2016-09-29 01:19:20 -0700108 network_thread_(rtc::Thread::Current()),
deadbeefcbecd352015-09-23 11:50:27 -0700109 incoming_only_(false),
110 error_(0),
deadbeefcbecd352015-09-23 11:50:27 -0700111 sort_dirty_(false),
deadbeefcbecd352015-09-23 11:50:27 -0700112 remote_ice_mode_(ICEMODE_FULL),
113 ice_role_(ICEROLE_UNKNOWN),
114 tiebreaker_(0),
deadbeefcbecd352015-09-23 11:50:27 -0700115 gathering_state_(kIceGatheringNew),
Steve Anton300bf8e2017-07-14 10:13:10 -0700116 rand_(rtc::SystemTimeNanos()),
Honghai Zhang049fbb12016-03-07 11:13:07 -0800117 check_receiving_interval_(MIN_CHECK_RECEIVING_INTERVAL * 5),
118 config_(MIN_CHECK_RECEIVING_INTERVAL * 50 /* receiving_timeout */,
Honghai Zhang895e1a92016-08-16 16:48:02 -0700119 DEFAULT_BACKUP_CONNECTION_PING_INTERVAL,
Honghai Zhang5622c5e2016-07-01 13:59:29 -0700120 GATHER_ONCE /* continual_gathering_policy */,
guoweis36f01372016-03-02 18:02:40 -0800121 false /* prioritize_most_likely_candidate_pairs */,
honghaiz7252a002016-11-08 20:04:09 -0800122 STRONG_AND_STABLE_WRITABLE_CONNECTION_PING_INTERVAL,
Honghai Zhang5622c5e2016-07-01 13:59:29 -0700123 true /* presume_writable_when_fully_relayed */,
honghaiz9ad0db52016-07-14 19:30:28 -0700124 DEFAULT_REGATHER_ON_FAILED_NETWORKS_INTERVAL,
125 RECEIVING_SWITCHING_DELAY) {
Honghai Zhang049fbb12016-03-07 11:13:07 -0800126 uint32_t weak_ping_interval = ::strtoul(
guoweisb0bb77f2015-10-26 15:10:01 -0700127 webrtc::field_trial::FindFullName("WebRTC-StunInterPacketDelay").c_str(),
128 nullptr, 10);
Honghai Zhang049fbb12016-03-07 11:13:07 -0800129 if (weak_ping_interval) {
130 weak_ping_interval_ = static_cast<int>(weak_ping_interval);
guoweisb0bb77f2015-10-26 15:10:01 -0700131 }
132}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000133
134P2PTransportChannel::~P2PTransportChannel() {
nisseede5da42017-01-12 05:15:36 -0800135 RTC_DCHECK(network_thread_ == rtc::Thread::Current());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000136}
137
138// Add the allocator session to our list so that we know which sessions
139// are still active.
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700140void P2PTransportChannel::AddAllocatorSession(
141 std::unique_ptr<PortAllocatorSession> session) {
nisseede5da42017-01-12 05:15:36 -0800142 RTC_DCHECK(network_thread_ == rtc::Thread::Current());
honghaiz9b669572015-11-04 12:07:44 -0800143
Peter Boström0c4e06b2015-10-07 12:23:21 +0200144 session->set_generation(static_cast<uint32_t>(allocator_sessions_.size()));
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700145 session->SignalPortReady.connect(this, &P2PTransportChannel::OnPortReady);
Honghai Zhang8eeecab2016-07-28 13:20:15 -0700146 session->SignalPortsPruned.connect(this, &P2PTransportChannel::OnPortsPruned);
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700147 session->SignalCandidatesReady.connect(
148 this, &P2PTransportChannel::OnCandidatesReady);
Honghai Zhang5622c5e2016-07-01 13:59:29 -0700149 session->SignalCandidatesRemoved.connect(
150 this, &P2PTransportChannel::OnCandidatesRemoved);
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700151 session->SignalCandidatesAllocationDone.connect(
152 this, &P2PTransportChannel::OnCandidatesAllocationDone);
Honghai Zhanga74363c2016-07-28 18:06:15 -0700153 if (!allocator_sessions_.empty()) {
154 allocator_session()->PruneAllPorts();
155 }
156 allocator_sessions_.push_back(std::move(session));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000157
158 // We now only want to apply new candidates that we receive to the ports
159 // created by this new session because these are replacing those of the
160 // previous sessions.
Honghai Zhanga74363c2016-07-28 18:06:15 -0700161 PruneAllPorts();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000162}
163
164void P2PTransportChannel::AddConnection(Connection* connection) {
165 connections_.push_back(connection);
guoweis36f01372016-03-02 18:02:40 -0800166 unpinged_connections_.insert(connection);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000167 connection->set_remote_ice_mode(remote_ice_mode_);
Honghai Zhang049fbb12016-03-07 11:13:07 -0800168 connection->set_receiving_timeout(config_.receiving_timeout);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000169 connection->SignalReadPacket.connect(
170 this, &P2PTransportChannel::OnReadPacket);
171 connection->SignalReadyToSend.connect(
172 this, &P2PTransportChannel::OnReadyToSend);
173 connection->SignalStateChange.connect(
174 this, &P2PTransportChannel::OnConnectionStateChange);
175 connection->SignalDestroyed.connect(
176 this, &P2PTransportChannel::OnConnectionDestroyed);
honghaiz5a3acd82015-08-20 15:53:17 -0700177 connection->SignalNominated.connect(this, &P2PTransportChannel::OnNominated);
deadbeefcbecd352015-09-23 11:50:27 -0700178 had_connection_ = true;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000179}
180
Honghai Zhang572b0942016-06-23 12:26:57 -0700181// Determines whether we should switch the selected connection to
182// |new_connection| based the writable/receiving state, the nomination state,
183// and the last data received time. This prevents the controlled side from
184// switching the selected connection too frequently when the controlling side
185// is doing aggressive nominations. The precedence of the connection switching
186// criteria is as follows:
187// i) write/receiving/connected states
188// ii) For controlled side,
189// a) nomination state,
190// b) last data received time.
191// iii) Lower cost / higher priority.
192// iv) rtt.
Honghai Zhangfd16da22016-08-17 16:12:46 -0700193// To further prevent switching to high-cost networks, does not switch to
194// a high-cost connection if it is not receiving.
Honghai Zhang572b0942016-06-23 12:26:57 -0700195// TODO(honghaiz): Stop the aggressive nomination on the controlling side and
196// implement the ice-renomination option.
197bool P2PTransportChannel::ShouldSwitchSelectedConnection(
honghaiz9ad0db52016-07-14 19:30:28 -0700198 Connection* new_connection,
199 bool* missed_receiving_unchanged_threshold) const {
Honghai Zhange05bcc22016-08-16 18:19:14 -0700200 if (!ReadyToSend(new_connection) || selected_connection_ == new_connection) {
Honghai Zhang572b0942016-06-23 12:26:57 -0700201 return false;
202 }
203
204 if (selected_connection_ == nullptr) {
205 return true;
206 }
207
Honghai Zhangfd16da22016-08-17 16:12:46 -0700208 // Do not switch to a connection that is not receiving if it has higher cost
209 // because it may be just spuriously better.
210 if (new_connection->ComputeNetworkCost() >
211 selected_connection_->ComputeNetworkCost() &&
212 !new_connection->receiving()) {
213 return false;
214 }
215
honghaiz9ad0db52016-07-14 19:30:28 -0700216 rtc::Optional<int64_t> receiving_unchanged_threshold(
217 rtc::TimeMillis() - config_.receiving_switching_delay.value_or(0));
218 int cmp = CompareConnections(selected_connection_, new_connection,
219 receiving_unchanged_threshold,
220 missed_receiving_unchanged_threshold);
Honghai Zhang572b0942016-06-23 12:26:57 -0700221 if (cmp != 0) {
222 return cmp < 0;
223 }
224
225 // If everything else is the same, switch only if rtt has improved by
226 // a margin.
227 return new_connection->rtt() <= selected_connection_->rtt() - kMinImprovement;
228}
229
honghaiz9ad0db52016-07-14 19:30:28 -0700230bool P2PTransportChannel::MaybeSwitchSelectedConnection(
231 Connection* new_connection,
232 const std::string& reason) {
233 bool missed_receiving_unchanged_threshold = false;
234 if (ShouldSwitchSelectedConnection(new_connection,
235 &missed_receiving_unchanged_threshold)) {
236 LOG(LS_INFO) << "Switching selected connection due to " << reason;
237 SwitchSelectedConnection(new_connection);
238 return true;
239 }
240 if (missed_receiving_unchanged_threshold &&
241 config_.receiving_switching_delay) {
242 // If we do not switch to the connection because it missed the receiving
243 // threshold, the new connection is in a better receiving state than the
244 // currently selected connection. So we need to re-check whether it needs
245 // to be switched at a later time.
246 thread()->PostDelayed(RTC_FROM_HERE, *config_.receiving_switching_delay,
247 this, MSG_SORT_AND_UPDATE_STATE);
248 }
249 return false;
250}
251
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000252void P2PTransportChannel::SetIceRole(IceRole ice_role) {
nisseede5da42017-01-12 05:15:36 -0800253 RTC_DCHECK(network_thread_ == rtc::Thread::Current());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000254 if (ice_role_ != ice_role) {
255 ice_role_ = ice_role;
deadbeefdfc42442016-06-21 14:19:48 -0700256 for (PortInterface* port : ports_) {
257 port->SetIceRole(ice_role);
258 }
Honghai Zhanga74363c2016-07-28 18:06:15 -0700259 // Update role on pruned ports as well, because they may still have
deadbeefdfc42442016-06-21 14:19:48 -0700260 // connections alive that should be using the correct role.
Honghai Zhang8eeecab2016-07-28 13:20:15 -0700261 for (PortInterface* port : pruned_ports_) {
deadbeefdfc42442016-06-21 14:19:48 -0700262 port->SetIceRole(ice_role);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000263 }
264 }
265}
266
Peter Boström0c4e06b2015-10-07 12:23:21 +0200267void P2PTransportChannel::SetIceTiebreaker(uint64_t tiebreaker) {
nisseede5da42017-01-12 05:15:36 -0800268 RTC_DCHECK(network_thread_ == rtc::Thread::Current());
Honghai Zhang8eeecab2016-07-28 13:20:15 -0700269 if (!ports_.empty() || !pruned_ports_.empty()) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000270 LOG(LS_ERROR)
271 << "Attempt to change tiebreaker after Port has been allocated.";
272 return;
273 }
274
275 tiebreaker_ = tiebreaker;
276}
277
zhihuangd06adf62017-01-12 15:58:31 -0800278IceTransportState P2PTransportChannel::GetState() const {
Honghai Zhang381b4212015-12-04 12:24:03 -0800279 return state_;
280}
281
skvladd0309122017-02-02 17:18:37 -0800282rtc::Optional<int> P2PTransportChannel::GetRttEstimate() {
283 if (selected_connection_ != nullptr
284 && selected_connection_->rtt_samples() > 0) {
285 return rtc::Optional<int>(selected_connection_->rtt());
286 } else {
287 return rtc::Optional<int>();
288 }
289}
290
Honghai Zhang2b342bf2015-09-30 09:51:58 -0700291// A channel is considered ICE completed once there is at most one active
292// connection per network and at least one active connection.
zhihuangd06adf62017-01-12 15:58:31 -0800293IceTransportState P2PTransportChannel::ComputeState() const {
Honghai Zhang2b342bf2015-09-30 09:51:58 -0700294 if (!had_connection_) {
zhihuangd06adf62017-01-12 15:58:31 -0800295 return IceTransportState::STATE_INIT;
guoweis@webrtc.org8c9ff202014-12-04 07:56:02 +0000296 }
297
Honghai Zhang2b342bf2015-09-30 09:51:58 -0700298 std::vector<Connection*> active_connections;
299 for (Connection* connection : connections_) {
300 if (connection->active()) {
301 active_connections.push_back(connection);
302 }
303 }
304 if (active_connections.empty()) {
zhihuangd06adf62017-01-12 15:58:31 -0800305 return IceTransportState::STATE_FAILED;
Honghai Zhang2b342bf2015-09-30 09:51:58 -0700306 }
307
308 std::set<rtc::Network*> networks;
309 for (Connection* connection : active_connections) {
310 rtc::Network* network = connection->port()->Network();
guoweis@webrtc.org8c9ff202014-12-04 07:56:02 +0000311 if (networks.find(network) == networks.end()) {
312 networks.insert(network);
313 } else {
314 LOG_J(LS_VERBOSE, this) << "Ice not completed yet for this channel as "
315 << network->ToString()
316 << " has more than 1 connection.";
zhihuangd06adf62017-01-12 15:58:31 -0800317 return IceTransportState::STATE_CONNECTING;
guoweis@webrtc.org8c9ff202014-12-04 07:56:02 +0000318 }
319 }
guoweis@webrtc.org8c9ff202014-12-04 07:56:02 +0000320
zhihuangd06adf62017-01-12 15:58:31 -0800321 return IceTransportState::STATE_COMPLETED;
guoweis@webrtc.org8c9ff202014-12-04 07:56:02 +0000322}
323
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700324void P2PTransportChannel::SetIceParameters(const IceParameters& ice_params) {
nisseede5da42017-01-12 05:15:36 -0800325 RTC_DCHECK(network_thread_ == rtc::Thread::Current());
Honghai Zhang9ecb0852016-09-15 16:41:04 -0700326 LOG(LS_INFO) << "Set ICE ufrag: " << ice_params.ufrag
327 << " pwd: " << ice_params.pwd << " on transport "
328 << transport_name();
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700329 ice_parameters_ = ice_params;
deadbeefcbecd352015-09-23 11:50:27 -0700330 // Note: Candidate gathering will restart when MaybeStartGathering is next
331 // called.
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000332}
333
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700334void P2PTransportChannel::SetRemoteIceParameters(
335 const IceParameters& ice_params) {
nisseede5da42017-01-12 05:15:36 -0800336 RTC_DCHECK(network_thread_ == rtc::Thread::Current());
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700337 LOG(LS_INFO) << "Remote supports ICE renomination ? "
338 << ice_params.renomination;
honghaiza54a0802015-12-16 18:37:23 -0800339 IceParameters* current_ice = remote_ice();
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700340 if (!current_ice || *current_ice != ice_params) {
honghaiza54a0802015-12-16 18:37:23 -0800341 // Keep the ICE credentials so that newer connections
342 // are prioritized over the older ones.
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700343 remote_ice_parameters_.push_back(ice_params);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000344 }
345
honghaiz112fe432015-12-30 13:32:47 -0800346 // Update the pwd of remote candidate if needed.
347 for (RemoteCandidate& candidate : remote_candidates_) {
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700348 if (candidate.username() == ice_params.ufrag &&
349 candidate.password().empty()) {
350 candidate.set_password(ice_params.pwd);
honghaiz112fe432015-12-30 13:32:47 -0800351 }
352 }
Taylor Brandstetter0a1bc532016-04-19 18:03:26 -0700353 // We need to update the credentials and generation for any peer reflexive
354 // candidates.
honghaiz112fe432015-12-30 13:32:47 -0800355 for (Connection* conn : connections_) {
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700356 conn->MaybeSetRemoteIceParametersAndGeneration(
357 ice_params, static_cast<int>(remote_ice_parameters_.size() - 1));
jiayl@webrtc.orgdacdd942015-01-23 17:33:34 +0000358 }
Taylor Brandstetter0a1bc532016-04-19 18:03:26 -0700359 // Updating the remote ICE candidate generation could change the sort order.
Taylor Brandstetterb825aee2016-06-29 13:07:16 -0700360 RequestSortAndStateUpdate();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000361}
362
363void P2PTransportChannel::SetRemoteIceMode(IceMode mode) {
364 remote_ice_mode_ = mode;
365}
366
honghaiz1f429e32015-09-28 07:57:34 -0700367void P2PTransportChannel::SetIceConfig(const IceConfig& config) {
Honghai Zhang5622c5e2016-07-01 13:59:29 -0700368 if (config_.continual_gathering_policy != config.continual_gathering_policy) {
deadbeefb60a8192016-08-24 15:15:00 -0700369 if (!allocator_sessions_.empty()) {
370 LOG(LS_ERROR) << "Trying to change continual gathering policy "
371 << "when gathering has already started!";
372 } else {
373 config_.continual_gathering_policy = config.continual_gathering_policy;
374 LOG(LS_INFO) << "Set continual_gathering_policy to "
375 << config_.continual_gathering_policy;
376 }
Honghai Zhang5622c5e2016-07-01 13:59:29 -0700377 }
honghaiz1f429e32015-09-28 07:57:34 -0700378
Honghai Zhang381b4212015-12-04 12:24:03 -0800379 if (config.backup_connection_ping_interval >= 0 &&
guoweis36f01372016-03-02 18:02:40 -0800380 config_.backup_connection_ping_interval !=
Honghai Zhang381b4212015-12-04 12:24:03 -0800381 config.backup_connection_ping_interval) {
guoweis36f01372016-03-02 18:02:40 -0800382 config_.backup_connection_ping_interval =
383 config.backup_connection_ping_interval;
Honghai Zhang381b4212015-12-04 12:24:03 -0800384 LOG(LS_INFO) << "Set backup connection ping interval to "
guoweis36f01372016-03-02 18:02:40 -0800385 << config_.backup_connection_ping_interval << " milliseconds.";
honghaiz90099622015-07-13 12:19:33 -0700386 }
Peter Thatcher04ac81f2015-09-21 11:48:28 -0700387
Honghai Zhang049fbb12016-03-07 11:13:07 -0800388 if (config.receiving_timeout >= 0 &&
389 config_.receiving_timeout != config.receiving_timeout) {
390 config_.receiving_timeout = config.receiving_timeout;
391 check_receiving_interval_ =
392 std::max(MIN_CHECK_RECEIVING_INTERVAL, config_.receiving_timeout / 10);
Honghai Zhang381b4212015-12-04 12:24:03 -0800393
394 for (Connection* connection : connections_) {
Honghai Zhang049fbb12016-03-07 11:13:07 -0800395 connection->set_receiving_timeout(config_.receiving_timeout);
Honghai Zhang381b4212015-12-04 12:24:03 -0800396 }
Honghai Zhang049fbb12016-03-07 11:13:07 -0800397 LOG(LS_INFO) << "Set ICE receiving timeout to " << config_.receiving_timeout
398 << " milliseconds";
Peter Thatcher04ac81f2015-09-21 11:48:28 -0700399 }
guoweis36f01372016-03-02 18:02:40 -0800400
401 config_.prioritize_most_likely_candidate_pairs =
402 config.prioritize_most_likely_candidate_pairs;
403 LOG(LS_INFO) << "Set ping most likely connection to "
404 << config_.prioritize_most_likely_candidate_pairs;
405
zhihuang435264a2016-06-21 11:28:38 -0700406 if (config.stable_writable_connection_ping_interval >= 0 &&
407 config_.stable_writable_connection_ping_interval !=
408 config.stable_writable_connection_ping_interval) {
409 config_.stable_writable_connection_ping_interval =
410 config.stable_writable_connection_ping_interval;
411 LOG(LS_INFO) << "Set stable_writable_connection_ping_interval to "
412 << config_.stable_writable_connection_ping_interval;
guoweis36f01372016-03-02 18:02:40 -0800413 }
deadbeef14f97f52016-06-22 17:14:15 -0700414
415 if (config.presume_writable_when_fully_relayed !=
416 config_.presume_writable_when_fully_relayed) {
417 if (!connections_.empty()) {
418 LOG(LS_ERROR) << "Trying to change 'presume writable' "
419 << "while connections already exist!";
420 } else {
421 config_.presume_writable_when_fully_relayed =
422 config.presume_writable_when_fully_relayed;
423 LOG(LS_INFO) << "Set presume writable when fully relayed to "
424 << config_.presume_writable_when_fully_relayed;
425 }
426 }
Honghai Zhang5622c5e2016-07-01 13:59:29 -0700427
428 if (config.regather_on_failed_networks_interval) {
429 config_.regather_on_failed_networks_interval =
430 config.regather_on_failed_networks_interval;
431 LOG(LS_INFO) << "Set regather_on_failed_networks_interval to "
432 << *config_.regather_on_failed_networks_interval;
433 }
Steve Anton300bf8e2017-07-14 10:13:10 -0700434
435 if (config.regather_all_networks_interval_range) {
Steve Anton038834f2017-07-14 15:59:59 -0700436 // Config validation is assumed to have already happened at the API layer.
437 RTC_DCHECK(config.continual_gathering_policy != GATHER_ONCE);
Steve Anton300bf8e2017-07-14 10:13:10 -0700438 config_.regather_all_networks_interval_range =
439 config.regather_all_networks_interval_range;
440 LOG(LS_INFO) << "Set regather_all_networks_interval_range to "
441 << config.regather_all_networks_interval_range->ToString();
442 }
443
honghaiz9ad0db52016-07-14 19:30:28 -0700444 if (config.receiving_switching_delay) {
445 config_.receiving_switching_delay = config.receiving_switching_delay;
446 LOG(LS_INFO) << "Set receiving_switching_delay to"
447 << *config_.receiving_switching_delay;
448 }
Honghai Zhang8cd8f812016-08-03 19:50:41 -0700449
450 if (config_.default_nomination_mode != config.default_nomination_mode) {
451 config_.default_nomination_mode = config.default_nomination_mode;
452 LOG(LS_INFO) << "Set default nomination mode to "
453 << static_cast<int>(config_.default_nomination_mode);
454 }
skvlad51072462017-02-02 11:50:14 -0800455
456 if (config_.ice_check_min_interval != config.ice_check_min_interval) {
457 config_.ice_check_min_interval = config.ice_check_min_interval;
458 LOG(LS_INFO) << "Set min ping interval to "
459 << *config_.ice_check_min_interval;
460 }
guoweis36f01372016-03-02 18:02:40 -0800461}
462
463const IceConfig& P2PTransportChannel::config() const {
464 return config_;
Peter Thatcher54360512015-07-08 11:08:35 -0700465}
466
Honghai Zhangd93f50c2016-10-05 11:47:22 -0700467void P2PTransportChannel::SetMetricsObserver(
468 webrtc::MetricsObserverInterface* observer) {
469 metrics_observer_ = observer;
470}
471
Taylor Brandstetterb825aee2016-06-29 13:07:16 -0700472void P2PTransportChannel::MaybeStartGathering() {
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700473 if (ice_parameters_.ufrag.empty() || ice_parameters_.pwd.empty()) {
Honghai Zhang9ecb0852016-09-15 16:41:04 -0700474 LOG(LS_ERROR) << "Cannot gather candidates because ICE parameters are empty"
475 << " ufrag: " << ice_parameters_.ufrag
476 << " pwd: " << ice_parameters_.pwd;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000477 return;
478 }
deadbeefcbecd352015-09-23 11:50:27 -0700479 // Start gathering if we never started before, or if an ICE restart occurred.
480 if (allocator_sessions_.empty() ||
481 IceCredentialsChanged(allocator_sessions_.back()->ice_ufrag(),
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700482 allocator_sessions_.back()->ice_pwd(),
483 ice_parameters_.ufrag, ice_parameters_.pwd)) {
deadbeefcbecd352015-09-23 11:50:27 -0700484 if (gathering_state_ != kIceGatheringGathering) {
485 gathering_state_ = kIceGatheringGathering;
486 SignalGatheringState(this);
487 }
Honghai Zhangd93f50c2016-10-05 11:47:22 -0700488
489 if (metrics_observer_ && !allocator_sessions_.empty()) {
490 IceRestartState state;
491 if (writable()) {
492 state = IceRestartState::CONNECTED;
493 } else if (IsGettingPorts()) {
494 state = IceRestartState::CONNECTING;
495 } else {
496 state = IceRestartState::DISCONNECTED;
497 }
498 metrics_observer_->IncrementEnumCounter(
499 webrtc::kEnumCounterIceRestart, static_cast<int>(state),
500 static_cast<int>(IceRestartState::MAX_VALUE));
501 }
502
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700503 // Time for a new allocator.
504 std::unique_ptr<PortAllocatorSession> pooled_session =
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700505 allocator_->TakePooledSession(transport_name(), component(),
506 ice_parameters_.ufrag,
507 ice_parameters_.pwd);
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700508 if (pooled_session) {
509 AddAllocatorSession(std::move(pooled_session));
510 PortAllocatorSession* raw_pooled_session =
511 allocator_sessions_.back().get();
512 // Process the pooled session's existing candidates/ports, if they exist.
513 OnCandidatesReady(raw_pooled_session,
514 raw_pooled_session->ReadyCandidates());
515 for (PortInterface* port : allocator_sessions_.back()->ReadyPorts()) {
516 OnPortReady(raw_pooled_session, port);
517 }
518 if (allocator_sessions_.back()->CandidatesAllocationDone()) {
519 OnCandidatesAllocationDone(raw_pooled_session);
520 }
521 } else {
522 AddAllocatorSession(allocator_->CreateSession(
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700523 transport_name(), component(), ice_parameters_.ufrag,
524 ice_parameters_.pwd));
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700525 allocator_sessions_.back()->StartGettingPorts();
526 }
deadbeefcbecd352015-09-23 11:50:27 -0700527 }
528}
529
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000530// A new port is available, attempt to make connections for it
531void P2PTransportChannel::OnPortReady(PortAllocatorSession *session,
532 PortInterface* port) {
nisseede5da42017-01-12 05:15:36 -0800533 RTC_DCHECK(network_thread_ == rtc::Thread::Current());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000534
535 // Set in-effect options on the new port
536 for (OptionMap::const_iterator it = options_.begin();
537 it != options_.end();
538 ++it) {
539 int val = port->SetOption(it->first, it->second);
540 if (val < 0) {
541 LOG_J(LS_WARNING, port) << "SetOption(" << it->first
542 << ", " << it->second
543 << ") failed: " << port->GetError();
544 }
545 }
546
547 // Remember the ports and candidates, and signal that candidates are ready.
548 // The session will handle this, and send an initiate/accept/modify message
549 // if one is pending.
550
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000551 port->SetIceRole(ice_role_);
552 port->SetIceTiebreaker(tiebreaker_);
553 ports_.push_back(port);
554 port->SignalUnknownAddress.connect(
555 this, &P2PTransportChannel::OnUnknownAddress);
556 port->SignalDestroyed.connect(this, &P2PTransportChannel::OnPortDestroyed);
Honghai Zhang5622c5e2016-07-01 13:59:29 -0700557
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000558 port->SignalRoleConflict.connect(
559 this, &P2PTransportChannel::OnRoleConflict);
stefanc1aeaf02015-10-15 07:26:07 -0700560 port->SignalSentPacket.connect(this, &P2PTransportChannel::OnSentPacket);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000561
562 // Attempt to create a connection from this new port to all of the remote
563 // candidates that we were given so far.
564
565 std::vector<RemoteCandidate>::iterator iter;
566 for (iter = remote_candidates_.begin(); iter != remote_candidates_.end();
567 ++iter) {
Peter Thatcher04ac81f2015-09-21 11:48:28 -0700568 CreateConnection(port, *iter, iter->origin_port());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000569 }
570
Taylor Brandstetterb825aee2016-06-29 13:07:16 -0700571 SortConnectionsAndUpdateState();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000572}
573
574// A new candidate is available, let listeners know
575void P2PTransportChannel::OnCandidatesReady(
deadbeefcbecd352015-09-23 11:50:27 -0700576 PortAllocatorSession* session,
577 const std::vector<Candidate>& candidates) {
nisseede5da42017-01-12 05:15:36 -0800578 RTC_DCHECK(network_thread_ == rtc::Thread::Current());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000579 for (size_t i = 0; i < candidates.size(); ++i) {
deadbeefcbecd352015-09-23 11:50:27 -0700580 SignalCandidateGathered(this, candidates[i]);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000581 }
582}
583
584void P2PTransportChannel::OnCandidatesAllocationDone(
585 PortAllocatorSession* session) {
nisseede5da42017-01-12 05:15:36 -0800586 RTC_DCHECK(network_thread_ == rtc::Thread::Current());
deadbeefb60a8192016-08-24 15:15:00 -0700587 if (config_.gather_continually()) {
588 LOG(LS_INFO) << "P2PTransportChannel: " << transport_name()
589 << ", component " << component()
590 << " gathering complete, but using continual "
591 << "gathering so not changing gathering state.";
592 return;
593 }
deadbeefcbecd352015-09-23 11:50:27 -0700594 gathering_state_ = kIceGatheringComplete;
595 LOG(LS_INFO) << "P2PTransportChannel: " << transport_name() << ", component "
596 << component() << " gathering complete";
597 SignalGatheringState(this);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000598}
599
600// Handle stun packets
601void P2PTransportChannel::OnUnknownAddress(
602 PortInterface* port,
603 const rtc::SocketAddress& address, ProtocolType proto,
604 IceMessage* stun_msg, const std::string &remote_username,
605 bool port_muxed) {
nisseede5da42017-01-12 05:15:36 -0800606 RTC_DCHECK(network_thread_ == rtc::Thread::Current());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000607
608 // Port has received a valid stun packet from an address that no Connection
609 // is currently available for. See if we already have a candidate with the
610 // address. If it isn't we need to create new candidate for it.
611
Taylor Brandstetterf7c15a92016-06-22 13:13:55 -0700612 const Candidate* candidate = nullptr;
613 for (const Candidate& c : remote_candidates_) {
614 if (c.username() == remote_username && c.address() == address &&
615 c.protocol() == ProtoToString(proto)) {
616 candidate = &c;
617 break;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000618 }
619 }
620
honghaiz112fe432015-12-30 13:32:47 -0800621 uint32_t remote_generation = 0;
Taylor Brandstetterf7c15a92016-06-22 13:13:55 -0700622 std::string remote_password;
jiayl@webrtc.orgdacdd942015-01-23 17:33:34 +0000623 // The STUN binding request may arrive after setRemoteDescription and before
624 // adding remote candidate, so we need to set the password to the shared
Taylor Brandstetterf7c15a92016-06-22 13:13:55 -0700625 // password and set the generation if the user name matches.
626 const IceParameters* ice_param =
627 FindRemoteIceFromUfrag(remote_username, &remote_generation);
628 // Note: if not found, the remote_generation will still be 0.
629 if (ice_param != nullptr) {
630 remote_password = ice_param->pwd;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000631 }
632
Guo-wei Shieh372f2fc2015-06-12 10:12:46 -0700633 Candidate remote_candidate;
634 bool remote_candidate_is_new = (candidate == nullptr);
635 if (!remote_candidate_is_new) {
636 remote_candidate = *candidate;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000637 } else {
638 // Create a new candidate with this address.
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700639 // The priority of the candidate is set to the PRIORITY attribute
640 // from the request.
641 const StunUInt32Attribute* priority_attr =
642 stun_msg->GetUInt32(STUN_ATTR_PRIORITY);
643 if (!priority_attr) {
644 LOG(LS_WARNING) << "P2PTransportChannel::OnUnknownAddress - "
645 << "No STUN_ATTR_PRIORITY found in the "
646 << "stun request message";
deadbeefcbecd352015-09-23 11:50:27 -0700647 port->SendBindingErrorResponse(stun_msg, address, STUN_ERROR_BAD_REQUEST,
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700648 STUN_ERROR_REASON_BAD_REQUEST);
649 return;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000650 }
honghaize1a0c942016-02-16 14:54:56 -0800651 int remote_candidate_priority = priority_attr->value();
652
honghaiza0c44ea2016-03-23 16:07:48 -0700653 uint16_t network_id = 0;
654 uint16_t network_cost = 0;
655 const StunUInt32Attribute* network_attr =
656 stun_msg->GetUInt32(STUN_ATTR_NETWORK_INFO);
657 if (network_attr) {
658 uint32_t network_info = network_attr->value();
659 network_id = static_cast<uint16_t>(network_info >> 16);
660 network_cost = static_cast<uint16_t>(network_info);
661 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000662
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700663 // RFC 5245
664 // If the source transport address of the request does not match any
665 // existing remote candidates, it represents a new peer reflexive remote
666 // candidate.
honghaiza0c44ea2016-03-23 16:07:48 -0700667 remote_candidate = Candidate(
668 component(), ProtoToString(proto), address, remote_candidate_priority,
669 remote_username, remote_password, PRFLX_PORT_TYPE, remote_generation,
670 "", network_id, network_cost);
guoweis@webrtc.org61c12472015-01-15 06:53:07 +0000671
672 // From RFC 5245, section-7.2.1.3:
673 // The foundation of the candidate is set to an arbitrary value, different
674 // from the foundation for all other remote candidates.
Guo-wei Shieh372f2fc2015-06-12 10:12:46 -0700675 remote_candidate.set_foundation(
Peter Boström0c4e06b2015-10-07 12:23:21 +0200676 rtc::ToString<uint32_t>(rtc::ComputeCrc32(remote_candidate.id())));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000677 }
678
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700679 // RFC5245, the agent constructs a pair whose local candidate is equal to
680 // the transport address on which the STUN request was received, and a
681 // remote candidate equal to the source transport address where the
682 // request came from.
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000683
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700684 // There shouldn't be an existing connection with this remote address.
685 // When ports are muxed, this channel might get multiple unknown address
686 // signals. In that case if the connection is already exists, we should
687 // simply ignore the signal otherwise send server error.
688 if (port->GetConnection(remote_candidate.address())) {
689 if (port_muxed) {
690 LOG(LS_INFO) << "Connection already exists for peer reflexive "
691 << "candidate: " << remote_candidate.ToString();
692 return;
693 } else {
nissec80e7412017-01-11 05:56:46 -0800694 RTC_NOTREACHED();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000695 port->SendBindingErrorResponse(stun_msg, address,
696 STUN_ERROR_SERVER_ERROR,
697 STUN_ERROR_REASON_SERVER_ERROR);
698 return;
699 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000700 }
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700701
guoweis36f01372016-03-02 18:02:40 -0800702 Connection* connection =
703 port->CreateConnection(remote_candidate, PortInterface::ORIGIN_THIS_PORT);
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700704 if (!connection) {
Honghai Zhangd5fff502016-09-09 20:47:53 -0700705 // This could happen in some scenarios. For example, a TurnPort may have
706 // had a refresh request timeout, so it won't create connections.
deadbeefcbecd352015-09-23 11:50:27 -0700707 port->SendBindingErrorResponse(stun_msg, address, STUN_ERROR_SERVER_ERROR,
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700708 STUN_ERROR_REASON_SERVER_ERROR);
709 return;
710 }
711
712 LOG(LS_INFO) << "Adding connection from "
713 << (remote_candidate_is_new ? "peer reflexive" : "resurrected")
714 << " candidate: " << remote_candidate.ToString();
715 AddConnection(connection);
honghaiz9b5ee9c2015-11-11 13:19:17 -0800716 connection->HandleBindingRequest(stun_msg);
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700717
718 // Update the list of connections since we just added another. We do this
719 // after sending the response since it could (in principle) delete the
720 // connection in question.
Taylor Brandstetterb825aee2016-06-29 13:07:16 -0700721 SortConnectionsAndUpdateState();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000722}
723
724void P2PTransportChannel::OnRoleConflict(PortInterface* port) {
725 SignalRoleConflict(this); // STUN ping will be sent when SetRole is called
726 // from Transport.
727}
728
honghaiz112fe432015-12-30 13:32:47 -0800729const IceParameters* P2PTransportChannel::FindRemoteIceFromUfrag(
730 const std::string& ufrag,
731 uint32_t* generation) {
732 const auto& params = remote_ice_parameters_;
733 auto it = std::find_if(
734 params.rbegin(), params.rend(),
735 [ufrag](const IceParameters& param) { return param.ufrag == ufrag; });
736 if (it == params.rend()) {
737 // Not found.
738 return nullptr;
739 }
740 *generation = params.rend() - it - 1;
741 return &(*it);
742}
743
honghaiz5a3acd82015-08-20 15:53:17 -0700744void P2PTransportChannel::OnNominated(Connection* conn) {
nisseede5da42017-01-12 05:15:36 -0800745 RTC_DCHECK(network_thread_ == rtc::Thread::Current());
746 RTC_DCHECK(ice_role_ == ICEROLE_CONTROLLED);
Peter Thatcher42af6ca2015-05-15 12:23:27 -0700747
Honghai Zhang572b0942016-06-23 12:26:57 -0700748 if (selected_connection_ == conn) {
749 return;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000750 }
Honghai Zhang572b0942016-06-23 12:26:57 -0700751
honghaiz9ad0db52016-07-14 19:30:28 -0700752 if (MaybeSwitchSelectedConnection(conn,
753 "nomination on the controlled side")) {
754 // Now that we have selected a connection, it is time to prune other
755 // connections and update the read/write state of the channel.
756 RequestSortAndStateUpdate();
757 } else {
Honghai Zhang572b0942016-06-23 12:26:57 -0700758 LOG(LS_INFO)
759 << "Not switching the selected connection on controlled side yet: "
760 << conn->ToString();
Honghai Zhang572b0942016-06-23 12:26:57 -0700761 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000762}
763
deadbeefcbecd352015-09-23 11:50:27 -0700764void P2PTransportChannel::AddRemoteCandidate(const Candidate& candidate) {
nisseede5da42017-01-12 05:15:36 -0800765 RTC_DCHECK(network_thread_ == rtc::Thread::Current());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000766
honghaiza54a0802015-12-16 18:37:23 -0800767 uint32_t generation = GetRemoteCandidateGeneration(candidate);
768 // If a remote candidate with a previous generation arrives, drop it.
769 if (generation < remote_ice_generation()) {
770 LOG(LS_WARNING) << "Dropping a remote candidate because its ufrag "
771 << candidate.username()
772 << " indicates it was for a previous generation.";
honghaiz503726c2015-07-31 12:37:38 -0700773 return;
774 }
775
honghaiza54a0802015-12-16 18:37:23 -0800776 Candidate new_remote_candidate(candidate);
777 new_remote_candidate.set_generation(generation);
778 // ICE candidates don't need to have username and password set, but
779 // the code below this (specifically, ConnectionRequest::Prepare in
780 // port.cc) uses the remote candidates's username. So, we set it
781 // here.
782 if (remote_ice()) {
783 if (candidate.username().empty()) {
784 new_remote_candidate.set_username(remote_ice()->ufrag);
785 }
786 if (new_remote_candidate.username() == remote_ice()->ufrag) {
787 if (candidate.password().empty()) {
788 new_remote_candidate.set_password(remote_ice()->pwd);
789 }
790 } else {
791 // The candidate belongs to the next generation. Its pwd will be set
792 // when the new remote ICE credentials arrive.
793 LOG(LS_WARNING) << "A remote candidate arrives with an unknown ufrag: "
794 << candidate.username();
795 }
796 }
797
deadbeef0af180b2016-06-21 13:15:32 -0700798 // If this candidate matches what was thought to be a peer reflexive
799 // candidate, we need to update the candidate priority/etc.
800 for (Connection* conn : connections_) {
801 conn->MaybeUpdatePeerReflexiveCandidate(new_remote_candidate);
802 }
803
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000804 // Create connections to this remote candidate.
honghaiza54a0802015-12-16 18:37:23 -0800805 CreateConnections(new_remote_candidate, NULL);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000806
807 // Resort the connections list, which may have new elements.
Taylor Brandstetterb825aee2016-06-29 13:07:16 -0700808 SortConnectionsAndUpdateState();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000809}
810
Honghai Zhang7fb69db2016-03-14 11:59:18 -0700811void P2PTransportChannel::RemoveRemoteCandidate(
812 const Candidate& cand_to_remove) {
813 auto iter =
814 std::remove_if(remote_candidates_.begin(), remote_candidates_.end(),
815 [cand_to_remove](const Candidate& candidate) {
816 return cand_to_remove.MatchesForRemoval(candidate);
817 });
818 if (iter != remote_candidates_.end()) {
819 LOG(LS_VERBOSE) << "Removed remote candidate " << cand_to_remove.ToString();
820 remote_candidates_.erase(iter, remote_candidates_.end());
821 }
822}
823
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000824// Creates connections from all of the ports that we care about to the given
825// remote candidate. The return value is true if we created a connection from
826// the origin port.
827bool P2PTransportChannel::CreateConnections(const Candidate& remote_candidate,
Peter Thatcher04ac81f2015-09-21 11:48:28 -0700828 PortInterface* origin_port) {
nisseede5da42017-01-12 05:15:36 -0800829 RTC_DCHECK(network_thread_ == rtc::Thread::Current());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000830
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000831 // If we've already seen the new remote candidate (in the current candidate
832 // generation), then we shouldn't try creating connections for it.
833 // We either already have a connection for it, or we previously created one
834 // and then later pruned it. If we don't return, the channel will again
835 // re-create any connections that were previously pruned, which will then
836 // immediately be re-pruned, churning the network for no purpose.
837 // This only applies to candidates received over signaling (i.e. origin_port
838 // is NULL).
honghaiza54a0802015-12-16 18:37:23 -0800839 if (!origin_port && IsDuplicateRemoteCandidate(remote_candidate)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000840 // return true to indicate success, without creating any new connections.
841 return true;
842 }
843
844 // Add a new connection for this candidate to every port that allows such a
845 // connection (i.e., if they have compatible protocols) and that does not
846 // already have a connection to an equivalent candidate. We must be careful
847 // to make sure that the origin port is included, even if it was pruned,
848 // since that may be the only port that can create this connection.
849 bool created = false;
850 std::vector<PortInterface *>::reverse_iterator it;
851 for (it = ports_.rbegin(); it != ports_.rend(); ++it) {
honghaiza54a0802015-12-16 18:37:23 -0800852 if (CreateConnection(*it, remote_candidate, origin_port)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000853 if (*it == origin_port)
854 created = true;
855 }
856 }
857
858 if ((origin_port != NULL) &&
859 std::find(ports_.begin(), ports_.end(), origin_port) == ports_.end()) {
honghaiza54a0802015-12-16 18:37:23 -0800860 if (CreateConnection(origin_port, remote_candidate, origin_port))
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000861 created = true;
862 }
863
864 // Remember this remote candidate so that we can add it to future ports.
honghaiza54a0802015-12-16 18:37:23 -0800865 RememberRemoteCandidate(remote_candidate, origin_port);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000866
867 return created;
868}
869
870// Setup a connection object for the local and remote candidate combination.
871// And then listen to connection object for changes.
872bool P2PTransportChannel::CreateConnection(PortInterface* port,
873 const Candidate& remote_candidate,
Peter Thatcher04ac81f2015-09-21 11:48:28 -0700874 PortInterface* origin_port) {
Honghai Zhangf9945b22015-12-15 12:20:13 -0800875 if (!port->SupportsProtocol(remote_candidate.protocol())) {
876 return false;
877 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000878 // Look for an existing connection with this remote address. If one is not
honghaiz36f50e82016-06-01 15:57:03 -0700879 // found or it is found but the existing remote candidate has an older
880 // generation, then we can create a new connection for this address.
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000881 Connection* connection = port->GetConnection(remote_candidate.address());
honghaiz36f50e82016-06-01 15:57:03 -0700882 if (connection == nullptr ||
883 connection->remote_candidate().generation() <
884 remote_candidate.generation()) {
885 // Don't create a connection if this is a candidate we received in a
886 // message and we are not allowed to make outgoing connections.
887 PortInterface::CandidateOrigin origin = GetOrigin(port, origin_port);
888 if (origin == PortInterface::ORIGIN_MESSAGE && incoming_only_) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000889 return false;
890 }
honghaiz36f50e82016-06-01 15:57:03 -0700891 Connection* connection = port->CreateConnection(remote_candidate, origin);
892 if (!connection) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000893 return false;
honghaiz36f50e82016-06-01 15:57:03 -0700894 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000895 AddConnection(connection);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000896 LOG_J(LS_INFO, this) << "Created connection with origin=" << origin << ", ("
897 << connections_.size() << " total)";
honghaiz36f50e82016-06-01 15:57:03 -0700898 return true;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000899 }
900
honghaiz36f50e82016-06-01 15:57:03 -0700901 // No new connection was created.
honghaiz36f50e82016-06-01 15:57:03 -0700902 // It is not legal to try to change any of the parameters of an existing
903 // connection; however, the other side can send a duplicate candidate.
904 if (!remote_candidate.IsEquivalent(connection->remote_candidate())) {
905 LOG(INFO) << "Attempt to change a remote candidate."
906 << " Existing remote candidate: "
907 << connection->remote_candidate().ToString()
908 << "New remote candidate: " << remote_candidate.ToString();
909 }
910 return false;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000911}
912
guoweis36f01372016-03-02 18:02:40 -0800913bool P2PTransportChannel::FindConnection(Connection* connection) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000914 std::vector<Connection*>::const_iterator citer =
915 std::find(connections_.begin(), connections_.end(), connection);
916 return citer != connections_.end();
917}
918
Peter Boström0c4e06b2015-10-07 12:23:21 +0200919uint32_t P2PTransportChannel::GetRemoteCandidateGeneration(
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000920 const Candidate& candidate) {
honghaiz112fe432015-12-30 13:32:47 -0800921 // If the candidate has a ufrag, use it to find the generation.
honghaiza54a0802015-12-16 18:37:23 -0800922 if (!candidate.username().empty()) {
honghaiz112fe432015-12-30 13:32:47 -0800923 uint32_t generation = 0;
924 if (!FindRemoteIceFromUfrag(candidate.username(), &generation)) {
925 // If the ufrag is not found, assume the next/future generation.
926 generation = static_cast<uint32_t>(remote_ice_parameters_.size());
honghaiza54a0802015-12-16 18:37:23 -0800927 }
honghaiz112fe432015-12-30 13:32:47 -0800928 return generation;
honghaiza54a0802015-12-16 18:37:23 -0800929 }
930 // If candidate generation is set, use that.
931 if (candidate.generation() > 0) {
932 return candidate.generation();
933 }
934 // Otherwise, assume the generation from remote ice parameters.
935 return remote_ice_generation();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000936}
937
938// Check if remote candidate is already cached.
939bool P2PTransportChannel::IsDuplicateRemoteCandidate(
940 const Candidate& candidate) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200941 for (size_t i = 0; i < remote_candidates_.size(); ++i) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000942 if (remote_candidates_[i].IsEquivalent(candidate)) {
943 return true;
944 }
945 }
946 return false;
947}
948
949// Maintain our remote candidate list, adding this new remote one.
950void P2PTransportChannel::RememberRemoteCandidate(
951 const Candidate& remote_candidate, PortInterface* origin_port) {
952 // Remove any candidates whose generation is older than this one. The
953 // presence of a new generation indicates that the old ones are not useful.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200954 size_t i = 0;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000955 while (i < remote_candidates_.size()) {
956 if (remote_candidates_[i].generation() < remote_candidate.generation()) {
957 LOG(INFO) << "Pruning candidate from old generation: "
958 << remote_candidates_[i].address().ToSensitiveString();
959 remote_candidates_.erase(remote_candidates_.begin() + i);
960 } else {
961 i += 1;
962 }
963 }
964
965 // Make sure this candidate is not a duplicate.
966 if (IsDuplicateRemoteCandidate(remote_candidate)) {
967 LOG(INFO) << "Duplicate candidate: " << remote_candidate.ToString();
968 return;
969 }
970
971 // Try this candidate for all future ports.
972 remote_candidates_.push_back(RemoteCandidate(remote_candidate, origin_port));
973}
974
975// Set options on ourselves is simply setting options on all of our available
976// port objects.
977int P2PTransportChannel::SetOption(rtc::Socket::Option opt, int value) {
nisseede5da42017-01-12 05:15:36 -0800978 RTC_DCHECK(network_thread_ == rtc::Thread::Current());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000979 OptionMap::iterator it = options_.find(opt);
980 if (it == options_.end()) {
981 options_.insert(std::make_pair(opt, value));
982 } else if (it->second == value) {
983 return 0;
984 } else {
985 it->second = value;
986 }
987
deadbeefdfc42442016-06-21 14:19:48 -0700988 for (PortInterface* port : ports_) {
989 int val = port->SetOption(opt, value);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000990 if (val < 0) {
991 // Because this also occurs deferred, probably no point in reporting an
992 // error
deadbeefdfc42442016-06-21 14:19:48 -0700993 LOG(WARNING) << "SetOption(" << opt << ", " << value
994 << ") failed: " << port->GetError();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000995 }
996 }
997 return 0;
998}
999
pthatcher@webrtc.org877ac762015-02-04 22:03:09 +00001000bool P2PTransportChannel::GetOption(rtc::Socket::Option opt, int* value) {
nisseede5da42017-01-12 05:15:36 -08001001 RTC_DCHECK(network_thread_ == rtc::Thread::Current());
pthatcher@webrtc.org877ac762015-02-04 22:03:09 +00001002
1003 const auto& found = options_.find(opt);
1004 if (found == options_.end()) {
1005 return false;
1006 }
1007 *value = found->second;
1008 return true;
1009}
1010
Honghai Zhang572b0942016-06-23 12:26:57 -07001011// Send data to the other side, using our selected connection.
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001012int P2PTransportChannel::SendPacket(const char *data, size_t len,
1013 const rtc::PacketOptions& options,
1014 int flags) {
nisseede5da42017-01-12 05:15:36 -08001015 RTC_DCHECK(network_thread_ == rtc::Thread::Current());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001016 if (flags != 0) {
1017 error_ = EINVAL;
1018 return -1;
1019 }
skvladc309e0e2016-07-28 17:15:20 -07001020 // If we don't think the connection is working yet, return ENOTCONN
Taylor Brandstetter6bb1ef22016-06-27 18:09:03 -07001021 // instead of sending a packet that will probably be dropped.
Honghai Zhange05bcc22016-08-16 18:19:14 -07001022 if (!ReadyToSend(selected_connection_)) {
skvladc309e0e2016-07-28 17:15:20 -07001023 error_ = ENOTCONN;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001024 return -1;
1025 }
1026
Honghai Zhang52dce732016-03-31 12:37:31 -07001027 last_sent_packet_id_ = options.packet_id;
Honghai Zhang572b0942016-06-23 12:26:57 -07001028 int sent = selected_connection_->Send(data, len, options);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001029 if (sent <= 0) {
nisseede5da42017-01-12 05:15:36 -08001030 RTC_DCHECK(sent < 0);
Honghai Zhang572b0942016-06-23 12:26:57 -07001031 error_ = selected_connection_->GetError();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001032 }
1033 return sent;
1034}
1035
1036bool P2PTransportChannel::GetStats(ConnectionInfos *infos) {
nisseede5da42017-01-12 05:15:36 -08001037 RTC_DCHECK(network_thread_ == rtc::Thread::Current());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001038 // Gather connection infos.
1039 infos->clear();
1040
Honghai Zhang2b342bf2015-09-30 09:51:58 -07001041 for (Connection* connection : connections_) {
zhihuang5ecf16c2016-06-01 17:09:15 -07001042 ConnectionInfo info = connection->stats();
Honghai Zhang572b0942016-06-23 12:26:57 -07001043 info.best_connection = (selected_connection_ == connection);
hbos06495bc2017-01-02 08:08:18 -08001044 infos->push_back(std::move(info));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001045 connection->set_reported(true);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001046 }
1047
1048 return true;
1049}
1050
1051rtc::DiffServCodePoint P2PTransportChannel::DefaultDscpValue() const {
1052 OptionMap::const_iterator it = options_.find(rtc::Socket::OPT_DSCP);
1053 if (it == options_.end()) {
1054 return rtc::DSCP_NO_CHANGE;
1055 }
1056 return static_cast<rtc::DiffServCodePoint> (it->second);
1057}
1058
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001059// Monitor connection states.
1060void P2PTransportChannel::UpdateConnectionStates() {
nisse1bffc1d2016-05-02 08:18:55 -07001061 int64_t now = rtc::TimeMillis();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001062
1063 // We need to copy the list of connections since some may delete themselves
1064 // when we call UpdateState.
Taylor Brandstetterb825aee2016-06-29 13:07:16 -07001065 for (Connection* c : connections_) {
1066 c->UpdateState(now);
1067 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001068}
1069
1070// Prepare for best candidate sorting.
Taylor Brandstetterb825aee2016-06-29 13:07:16 -07001071void P2PTransportChannel::RequestSortAndStateUpdate() {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001072 if (!sort_dirty_) {
johan0fd22ef2016-09-29 01:19:20 -07001073 network_thread_->Post(RTC_FROM_HERE, this, MSG_SORT_AND_UPDATE_STATE);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001074 sort_dirty_ = true;
1075 }
1076}
1077
Taylor Brandstetterb825aee2016-06-29 13:07:16 -07001078void P2PTransportChannel::MaybeStartPinging() {
1079 if (started_pinging_) {
1080 return;
1081 }
1082
1083 int64_t now = rtc::TimeMillis();
1084 if (std::any_of(
1085 connections_.begin(), connections_.end(),
1086 [this, now](const Connection* c) { return IsPingable(c, now); })) {
1087 LOG_J(LS_INFO, this) << "Have a pingable connection for the first time; "
1088 << "starting to ping.";
1089 thread()->Post(RTC_FROM_HERE, this, MSG_CHECK_AND_PING);
Honghai Zhang5622c5e2016-07-01 13:59:29 -07001090 thread()->PostDelayed(RTC_FROM_HERE,
1091 *config_.regather_on_failed_networks_interval, this,
1092 MSG_REGATHER_ON_FAILED_NETWORKS);
Steve Anton300bf8e2017-07-14 10:13:10 -07001093 if (config_.regather_all_networks_interval_range) {
1094 thread()->PostDelayed(RTC_FROM_HERE,
1095 SampleRegatherAllNetworksInterval(), this,
1096 MSG_REGATHER_ON_ALL_NETWORKS);
1097 }
Taylor Brandstetterb825aee2016-06-29 13:07:16 -07001098 started_pinging_ = true;
1099 }
1100}
1101
deadbeef14f97f52016-06-22 17:14:15 -07001102// Compare two connections based on their writing, receiving, and connected
1103// states.
honghaiz9ad0db52016-07-14 19:30:28 -07001104int P2PTransportChannel::CompareConnectionStates(
1105 const Connection* a,
1106 const Connection* b,
1107 rtc::Optional<int64_t> receiving_unchanged_threshold,
1108 bool* missed_receiving_unchanged_threshold) const {
deadbeef14f97f52016-06-22 17:14:15 -07001109 // First, prefer a connection that's writable or presumed writable over
1110 // one that's not writable.
1111 bool a_writable = a->writable() || PresumedWritable(a);
1112 bool b_writable = b->writable() || PresumedWritable(b);
1113 if (a_writable && !b_writable) {
1114 return a_is_better;
1115 }
1116 if (!a_writable && b_writable) {
1117 return b_is_better;
1118 }
1119
1120 // Sort based on write-state. Better states have lower values.
1121 if (a->write_state() < b->write_state()) {
1122 return a_is_better;
1123 }
1124 if (b->write_state() < a->write_state()) {
1125 return b_is_better;
1126 }
1127
1128 // We prefer a receiving connection to a non-receiving, higher-priority
1129 // connection when sorting connections and choosing which connection to
1130 // switch to.
1131 if (a->receiving() && !b->receiving()) {
1132 return a_is_better;
1133 }
1134 if (!a->receiving() && b->receiving()) {
honghaiz9ad0db52016-07-14 19:30:28 -07001135 if (!receiving_unchanged_threshold ||
1136 (a->receiving_unchanged_since() <= *receiving_unchanged_threshold &&
1137 b->receiving_unchanged_since() <= *receiving_unchanged_threshold)) {
1138 return b_is_better;
1139 }
1140 *missed_receiving_unchanged_threshold = true;
deadbeef14f97f52016-06-22 17:14:15 -07001141 }
1142
1143 // WARNING: Some complexity here about TCP reconnecting.
1144 // When a TCP connection fails because of a TCP socket disconnecting, the
1145 // active side of the connection will attempt to reconnect for 5 seconds while
1146 // pretending to be writable (the connection is not set to the unwritable
1147 // state). On the passive side, the connection also remains writable even
1148 // though it is disconnected, and a new connection is created when the active
1149 // side connects. At that point, there are two TCP connections on the passive
1150 // side: 1. the old, disconnected one that is pretending to be writable, and
1151 // 2. the new, connected one that is maybe not yet writable. For purposes of
Honghai Zhang572b0942016-06-23 12:26:57 -07001152 // pruning, pinging, and selecting the selected connection, we want to treat
1153 // the new connection as "better" than the old one. We could add a method
1154 // called something like Connection::ImReallyBadEvenThoughImWritable, but that
1155 // is equivalent to the existing Connection::connected(), which we already
1156 // have. So, in code throughout this file, we'll check whether the connection
1157 // is connected() or not, and if it is not, treat it as "worse" than a
1158 // connected one, even though it's writable. In the code below, we're doing
1159 // so to make sure we treat a new writable connection as better than an old
1160 // disconnected connection.
deadbeef14f97f52016-06-22 17:14:15 -07001161
1162 // In the case where we reconnect TCP connections, the original best
1163 // connection is disconnected without changing to WRITE_TIMEOUT. In this case,
1164 // the new connection, when it becomes writable, should have higher priority.
1165 if (a->write_state() == Connection::STATE_WRITABLE &&
1166 b->write_state() == Connection::STATE_WRITABLE) {
1167 if (a->connected() && !b->connected()) {
1168 return a_is_better;
1169 }
1170 if (!a->connected() && b->connected()) {
1171 return b_is_better;
1172 }
1173 }
1174 return 0;
1175}
1176
1177// Compares two connections based only on the candidate and network information.
1178// Returns positive if |a| is better than |b|.
1179int P2PTransportChannel::CompareConnectionCandidates(
1180 const Connection* a,
1181 const Connection* b) const {
1182 // Prefer lower network cost.
1183 uint32_t a_cost = a->ComputeNetworkCost();
1184 uint32_t b_cost = b->ComputeNetworkCost();
1185 // Smaller cost is better.
1186 if (a_cost < b_cost) {
Honghai Zhang572b0942016-06-23 12:26:57 -07001187 return a_is_better;
deadbeef14f97f52016-06-22 17:14:15 -07001188 }
1189 if (a_cost > b_cost) {
Honghai Zhang572b0942016-06-23 12:26:57 -07001190 return b_is_better;
deadbeef14f97f52016-06-22 17:14:15 -07001191 }
1192
1193 // Compare connection priority. Lower values get sorted last.
1194 if (a->priority() > b->priority()) {
Honghai Zhang572b0942016-06-23 12:26:57 -07001195 return a_is_better;
deadbeef14f97f52016-06-22 17:14:15 -07001196 }
1197 if (a->priority() < b->priority()) {
Honghai Zhang572b0942016-06-23 12:26:57 -07001198 return b_is_better;
deadbeef14f97f52016-06-22 17:14:15 -07001199 }
1200
1201 // If we're still tied at this point, prefer a younger generation.
1202 // (Younger generation means a larger generation number).
Steve Anton300bf8e2017-07-14 10:13:10 -07001203 int cmp = (a->remote_candidate().generation() + a->port()->generation()) -
1204 (b->remote_candidate().generation() + b->port()->generation());
1205 if (cmp != 0) {
1206 return cmp;
1207 }
1208
1209 // A periodic regather (triggered by the regather_all_networks_interval_range)
1210 // will produce candidates that appear the same but would use a new port. We
1211 // want to use the new candidates and purge the old candidates as they come
1212 // in, so use the fact that the old ports get pruned immediately to rank the
1213 // candidates with an active port/remote candidate higher.
1214 bool a_pruned = IsPortPruned(a->port()) ||
1215 IsRemoteCandidatePruned(a->remote_candidate());
1216 bool b_pruned = IsPortPruned(b->port()) ||
1217 IsRemoteCandidatePruned(b->remote_candidate());
1218 if (!a_pruned && b_pruned) {
1219 return a_is_better;
1220 }
1221 if (a_pruned && !b_pruned) {
1222 return b_is_better;
1223 }
1224
1225 // Otherwise, must be equal
1226 return 0;
1227}
1228
1229bool P2PTransportChannel::IsPortPruned(const Port* port) const {
1230 return std::find(ports_.begin(), ports_.end(), port) == ports_.end();
1231}
1232
1233bool P2PTransportChannel::IsRemoteCandidatePruned(const Candidate& cand) const {
1234 return std::find(remote_candidates_.begin(), remote_candidates_.end(), cand)
1235 == remote_candidates_.end();
deadbeef14f97f52016-06-22 17:14:15 -07001236}
1237
honghaiz9ad0db52016-07-14 19:30:28 -07001238int P2PTransportChannel::CompareConnections(
1239 const Connection* a,
1240 const Connection* b,
1241 rtc::Optional<int64_t> receiving_unchanged_threshold,
1242 bool* missed_receiving_unchanged_threshold) const {
Honghai Zhang572b0942016-06-23 12:26:57 -07001243 RTC_CHECK(a != nullptr);
1244 RTC_CHECK(b != nullptr);
1245
1246 // We prefer to switch to a writable and receiving connection over a
1247 // non-writable or non-receiving connection, even if the latter has
1248 // been nominated by the controlling side.
honghaiz9ad0db52016-07-14 19:30:28 -07001249 int state_cmp = CompareConnectionStates(a, b, receiving_unchanged_threshold,
1250 missed_receiving_unchanged_threshold);
deadbeef14f97f52016-06-22 17:14:15 -07001251 if (state_cmp != 0) {
1252 return state_cmp;
1253 }
deadbeef14f97f52016-06-22 17:14:15 -07001254
Honghai Zhang572b0942016-06-23 12:26:57 -07001255 if (ice_role_ == ICEROLE_CONTROLLED) {
1256 // Compare the connections based on the nomination states and the last data
1257 // received time if this is on the controlled side.
Honghai Zhang8cd8f812016-08-03 19:50:41 -07001258 if (a->remote_nomination() > b->remote_nomination()) {
Honghai Zhang572b0942016-06-23 12:26:57 -07001259 return a_is_better;
1260 }
Honghai Zhang8cd8f812016-08-03 19:50:41 -07001261 if (a->remote_nomination() < b->remote_nomination()) {
Honghai Zhang572b0942016-06-23 12:26:57 -07001262 return b_is_better;
1263 }
1264
1265 if (a->last_data_received() > b->last_data_received()) {
1266 return a_is_better;
1267 }
1268 if (a->last_data_received() < b->last_data_received()) {
1269 return b_is_better;
1270 }
1271 }
1272
1273 // Compare the network cost and priority.
1274 return CompareConnectionCandidates(a, b);
deadbeef14f97f52016-06-22 17:14:15 -07001275}
1276
Honghai Zhang572b0942016-06-23 12:26:57 -07001277bool P2PTransportChannel::PresumedWritable(const Connection* conn) const {
deadbeef14f97f52016-06-22 17:14:15 -07001278 return (conn->write_state() == Connection::STATE_WRITE_INIT &&
1279 config_.presume_writable_when_fully_relayed &&
1280 conn->local_candidate().type() == RELAY_PORT_TYPE &&
1281 (conn->remote_candidate().type() == RELAY_PORT_TYPE ||
1282 conn->remote_candidate().type() == PRFLX_PORT_TYPE));
1283}
1284
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001285// Sort the available connections to find the best one. We also monitor
1286// the number of available connections and the current state.
Taylor Brandstetterb825aee2016-06-29 13:07:16 -07001287void P2PTransportChannel::SortConnectionsAndUpdateState() {
nisseede5da42017-01-12 05:15:36 -08001288 RTC_DCHECK(network_thread_ == rtc::Thread::Current());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001289
1290 // Make sure the connection states are up-to-date since this affects how they
1291 // will be sorted.
1292 UpdateConnectionStates();
1293
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001294 // Any changes after this point will require a re-sort.
1295 sort_dirty_ = false;
1296
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001297 // Find the best alternative connection by sorting. It is important to note
1298 // that amongst equal preference, writable connections, this will choose the
1299 // one whose estimated latency is lowest. So it is the only one that we
1300 // need to consider switching to.
honghaiz7252a002016-11-08 20:04:09 -08001301 // TODO(honghaiz): Don't sort; Just use std::max_element in the right places.
deadbeef14f97f52016-06-22 17:14:15 -07001302 std::stable_sort(connections_.begin(), connections_.end(),
1303 [this](const Connection* a, const Connection* b) {
honghaiz9ad0db52016-07-14 19:30:28 -07001304 int cmp = CompareConnections(
1305 a, b, rtc::Optional<int64_t>(), nullptr);
Honghai Zhang572b0942016-06-23 12:26:57 -07001306 if (cmp != 0) {
1307 return cmp > 0;
1308 }
Honghai Zhang572b0942016-06-23 12:26:57 -07001309 // Otherwise, sort based on latency estimate.
1310 return a->rtt() < b->rtt();
deadbeef14f97f52016-06-22 17:14:15 -07001311 });
Honghai Zhang572b0942016-06-23 12:26:57 -07001312
honghaiza58ea782015-09-24 08:13:36 -07001313 LOG(LS_VERBOSE) << "Sorting " << connections_.size()
1314 << " available connections:";
Peter Boström0c4e06b2015-10-07 12:23:21 +02001315 for (size_t i = 0; i < connections_.size(); ++i) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001316 LOG(LS_VERBOSE) << connections_[i]->ToString();
1317 }
1318
honghaiz5a3acd82015-08-20 15:53:17 -07001319 Connection* top_connection =
1320 (connections_.size() > 0) ? connections_[0] : nullptr;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001321
Honghai Zhang572b0942016-06-23 12:26:57 -07001322 // If necessary, switch to the new choice. Note that |top_connection| doesn't
1323 // have to be writable to become the selected connection although it will
1324 // have higher priority if it is writable.
honghaiz9ad0db52016-07-14 19:30:28 -07001325 MaybeSwitchSelectedConnection(top_connection, "sorting");
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001326
Honghai Zhang572b0942016-06-23 12:26:57 -07001327 // The controlled side can prune only if the selected connection has been
1328 // nominated because otherwise it may prune the connection that will be
1329 // selected by the controlling side.
1330 // TODO(honghaiz): This is not enough to prevent a connection from being
1331 // pruned too early because with aggressive nomination, the controlling side
1332 // will nominate every connection until it becomes writable.
1333 if (ice_role_ == ICEROLE_CONTROLLING ||
1334 (selected_connection_ && selected_connection_->nominated())) {
honghaiz5a3acd82015-08-20 15:53:17 -07001335 PruneConnections();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001336 }
1337
1338 // Check if all connections are timedout.
1339 bool all_connections_timedout = true;
Peter Boström0c4e06b2015-10-07 12:23:21 +02001340 for (size_t i = 0; i < connections_.size(); ++i) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001341 if (connections_[i]->write_state() != Connection::STATE_WRITE_TIMEOUT) {
1342 all_connections_timedout = false;
1343 break;
1344 }
1345 }
1346
1347 // Now update the writable state of the channel with the information we have
1348 // so far.
honghaiza8e9f5e2015-11-11 16:15:07 -08001349 if (all_connections_timedout) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001350 HandleAllTimedOut();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001351 }
1352
Taylor Brandstetterb825aee2016-06-29 13:07:16 -07001353 // Update the state of this channel.
Honghai Zhang381b4212015-12-04 12:24:03 -08001354 UpdateState();
Taylor Brandstetterb825aee2016-06-29 13:07:16 -07001355
1356 // Also possibly start pinging.
1357 // We could start pinging if:
1358 // * The first connection was created.
1359 // * ICE credentials were provided.
1360 // * A TCP connection became connected.
1361 MaybeStartPinging();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001362}
1363
honghaiz7252a002016-11-08 20:04:09 -08001364std::map<rtc::Network*, Connection*>
1365P2PTransportChannel::GetBestConnectionByNetwork() const {
1366 // |connections_| has been sorted, so the first one in the list on a given
1367 // network is the best connection on the network, except that the selected
1368 // connection is always the best connection on the network.
1369 std::map<rtc::Network*, Connection*> best_connection_by_network;
1370 if (selected_connection_) {
1371 best_connection_by_network[selected_connection_->port()->Network()] =
1372 selected_connection_;
1373 }
1374 // TODO(honghaiz): Need to update this if |connections_| are not sorted.
1375 for (Connection* conn : connections_) {
1376 rtc::Network* network = conn->port()->Network();
1377 // This only inserts when the network does not exist in the map.
1378 best_connection_by_network.insert(std::make_pair(network, conn));
1379 }
1380 return best_connection_by_network;
1381}
1382
1383std::vector<Connection*>
1384P2PTransportChannel::GetBestWritableConnectionPerNetwork() const {
1385 std::vector<Connection*> connections;
1386 for (auto kv : GetBestConnectionByNetwork()) {
1387 Connection* conn = kv.second;
1388 if (conn->writable() && conn->connected()) {
1389 connections.push_back(conn);
1390 }
1391 }
1392 return connections;
1393}
1394
honghaiz5a3acd82015-08-20 15:53:17 -07001395void P2PTransportChannel::PruneConnections() {
sprang716978d2016-10-11 06:43:28 -07001396 // We can prune any connection for which there is a connected, writable
1397 // connection on the same network with better or equal priority. We leave
1398 // those with better priority just in case they become writable later (at
1399 // which point, we would prune out the current selected connection). We leave
1400 // connections on other networks because they may not be using the same
1401 // resources and they may represent very distinct paths over which we can
honghaiz7252a002016-11-08 20:04:09 -08001402 // switch. If |best_conn_on_network| is not connected, we may be reconnecting
1403 // a TCP connection and should not prune connections in this network.
1404 // See the big comment in CompareConnectionStates.
deadbeef1ee21252017-06-13 15:49:45 -07001405 //
1406 // An exception is made for connections on an "any address" network, meaning
1407 // not bound to any specific network interface. We don't want to keep one of
1408 // these alive as a backup, since it could be using the same network
1409 // interface as the higher-priority, selected candidate pair.
honghaiz7252a002016-11-08 20:04:09 -08001410 auto best_connection_by_network = GetBestConnectionByNetwork();
1411 for (Connection* conn : connections_) {
deadbeef1ee21252017-06-13 15:49:45 -07001412 Connection* best_conn = selected_connection_;
1413 if (!rtc::IPIsAny(conn->port()->Network()->ip())) {
1414 // If the connection is bound to a specific network interface (not an
1415 // "any address" network), compare it against the best connection for
1416 // that network interface rather than the best connection overall. This
1417 // ensures that at least one connection per network will be left
1418 // unpruned.
1419 best_conn = best_connection_by_network[conn->port()->Network()];
1420 }
1421 // Do not prune connections if the connection being compared against is
1422 // weak. Otherwise, it may delete connections prematurely.
1423 if (best_conn && conn != best_conn && !best_conn->weak() &&
1424 CompareConnectionCandidates(best_conn, conn) >= 0) {
honghaiz7252a002016-11-08 20:04:09 -08001425 conn->Prune();
honghaiz5a3acd82015-08-20 15:53:17 -07001426 }
1427 }
1428}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001429
Honghai Zhang572b0942016-06-23 12:26:57 -07001430// Change the selected connection, and let listeners know.
1431void P2PTransportChannel::SwitchSelectedConnection(Connection* conn) {
1432 // Note: if conn is NULL, the previous |selected_connection_| has been
1433 // destroyed, so don't use it.
1434 Connection* old_selected_connection = selected_connection_;
1435 selected_connection_ = conn;
1436 if (selected_connection_) {
Honghai Zhang8cd8f812016-08-03 19:50:41 -07001437 ++nomination_;
Honghai Zhang572b0942016-06-23 12:26:57 -07001438 if (old_selected_connection) {
1439 LOG_J(LS_INFO, this) << "Previous selected connection: "
1440 << old_selected_connection->ToString();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001441 }
Honghai Zhang572b0942016-06-23 12:26:57 -07001442 LOG_J(LS_INFO, this) << "New selected connection: "
1443 << selected_connection_->ToString();
1444 SignalRouteChange(this, selected_connection_->remote_candidate());
Honghai Zhang82f132c2016-03-30 12:55:14 -07001445 // This is a temporary, but safe fix to webrtc issue 5705.
skvladc309e0e2016-07-28 17:15:20 -07001446 // TODO(honghaiz): Make all ENOTCONN error routed through the transport
Honghai Zhang82f132c2016-03-30 12:55:14 -07001447 // channel so that it knows whether the media channel is allowed to
1448 // send; then it will only signal ready-to-send if the media channel
1449 // has been disallowed to send.
Honghai Zhang572b0942016-06-23 12:26:57 -07001450 if (selected_connection_->writable() ||
1451 PresumedWritable(selected_connection_)) {
Honghai Zhang82f132c2016-03-30 12:55:14 -07001452 SignalReadyToSend(this);
1453 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001454 } else {
Honghai Zhang572b0942016-06-23 12:26:57 -07001455 LOG_J(LS_INFO, this) << "No selected connection";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001456 }
Honghai Zhang572b0942016-06-23 12:26:57 -07001457 SignalSelectedCandidatePairChanged(this, selected_connection_,
Honghai Zhange05bcc22016-08-16 18:19:14 -07001458 last_sent_packet_id_,
1459 ReadyToSend(selected_connection_));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001460}
1461
Honghai Zhang381b4212015-12-04 12:24:03 -08001462// Warning: UpdateState should eventually be called whenever a connection
1463// is added, deleted, or the write state of any connection changes so that the
1464// transport controller will get the up-to-date channel state. However it
1465// should not be called too often; in the case that multiple connection states
1466// change, it should be called after all the connection states have changed. For
Taylor Brandstetterb825aee2016-06-29 13:07:16 -07001467// example, we call this at the end of SortConnectionsAndUpdateState.
Honghai Zhang381b4212015-12-04 12:24:03 -08001468void P2PTransportChannel::UpdateState() {
zhihuangd06adf62017-01-12 15:58:31 -08001469 IceTransportState state = ComputeState();
Honghai Zhang1590c392016-05-24 13:15:02 -07001470 if (state_ != state) {
zhihuangd06adf62017-01-12 15:58:31 -08001471 LOG_J(LS_INFO, this) << "Transport channel state changed from "
1472 << static_cast<int>(state_) << " to "
1473 << static_cast<int>(state);
Taylor Brandstetter6aefc632016-05-26 16:08:23 -07001474 // Check that the requested transition is allowed. Note that
1475 // P2PTransportChannel does not (yet) implement a direct mapping of the ICE
1476 // states from the standard; the difference is covered by
1477 // TransportController and PeerConnection.
1478 switch (state_) {
zhihuangd06adf62017-01-12 15:58:31 -08001479 case IceTransportState::STATE_INIT:
Taylor Brandstetter6aefc632016-05-26 16:08:23 -07001480 // TODO(deadbeef): Once we implement end-of-candidates signaling,
1481 // we shouldn't go from INIT to COMPLETED.
zhihuangd06adf62017-01-12 15:58:31 -08001482 RTC_DCHECK(state == IceTransportState::STATE_CONNECTING ||
1483 state == IceTransportState::STATE_COMPLETED);
Taylor Brandstetter6aefc632016-05-26 16:08:23 -07001484 break;
zhihuangd06adf62017-01-12 15:58:31 -08001485 case IceTransportState::STATE_CONNECTING:
1486 RTC_DCHECK(state == IceTransportState::STATE_COMPLETED ||
1487 state == IceTransportState::STATE_FAILED);
Taylor Brandstetter6aefc632016-05-26 16:08:23 -07001488 break;
zhihuangd06adf62017-01-12 15:58:31 -08001489 case IceTransportState::STATE_COMPLETED:
Taylor Brandstetter6aefc632016-05-26 16:08:23 -07001490 // TODO(deadbeef): Once we implement end-of-candidates signaling,
1491 // we shouldn't go from COMPLETED to CONNECTING.
1492 // Though we *can* go from COMPlETED to FAILED, if consent expires.
zhihuangd06adf62017-01-12 15:58:31 -08001493 RTC_DCHECK(state == IceTransportState::STATE_CONNECTING ||
1494 state == IceTransportState::STATE_FAILED);
Taylor Brandstetter6aefc632016-05-26 16:08:23 -07001495 break;
zhihuangd06adf62017-01-12 15:58:31 -08001496 case IceTransportState::STATE_FAILED:
Taylor Brandstetter6aefc632016-05-26 16:08:23 -07001497 // TODO(deadbeef): Once we implement end-of-candidates signaling,
1498 // we shouldn't go from FAILED to CONNECTING or COMPLETED.
zhihuangd06adf62017-01-12 15:58:31 -08001499 RTC_DCHECK(state == IceTransportState::STATE_CONNECTING ||
1500 state == IceTransportState::STATE_COMPLETED);
Taylor Brandstetter6aefc632016-05-26 16:08:23 -07001501 break;
1502 default:
nisseeb4ca4e2017-01-12 02:24:27 -08001503 RTC_NOTREACHED();
Taylor Brandstetter6aefc632016-05-26 16:08:23 -07001504 break;
1505 }
Honghai Zhang1590c392016-05-24 13:15:02 -07001506 state_ = state;
1507 SignalStateChanged(this);
1508 }
Honghai Zhang381b4212015-12-04 12:24:03 -08001509
Honghai Zhang572b0942016-06-23 12:26:57 -07001510 // If our selected connection is "presumed writable" (TURN-TURN with no
deadbeef14f97f52016-06-22 17:14:15 -07001511 // CreatePermission required), act like we're already writable to the upper
1512 // layers, so they can start media quicker.
Honghai Zhang572b0942016-06-23 12:26:57 -07001513 bool writable =
1514 selected_connection_ && (selected_connection_->writable() ||
1515 PresumedWritable(selected_connection_));
1516 set_writable(writable);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001517
honghaiza58ea782015-09-24 08:13:36 -07001518 bool receiving = false;
1519 for (const Connection* connection : connections_) {
1520 if (connection->receiving()) {
1521 receiving = true;
1522 break;
1523 }
1524 }
1525 set_receiving(receiving);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001526}
1527
honghaiz9b669572015-11-04 12:07:44 -08001528void P2PTransportChannel::MaybeStopPortAllocatorSessions() {
1529 if (!IsGettingPorts()) {
honghaiz98db68f2015-09-29 07:58:17 -07001530 return;
1531 }
1532
Taylor Brandstettera1c30352016-05-13 08:15:11 -07001533 for (const auto& session : allocator_sessions_) {
Honghai Zhang5622c5e2016-07-01 13:59:29 -07001534 if (session->IsStopped()) {
honghaiz98db68f2015-09-29 07:58:17 -07001535 continue;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001536 }
Honghai Zhang5622c5e2016-07-01 13:59:29 -07001537 // If gathering continually, keep the last session running so that
1538 // it can gather candidates if the networks change.
1539 if (config_.gather_continually() && session == allocator_sessions_.back()) {
honghaiz98db68f2015-09-29 07:58:17 -07001540 session->ClearGettingPorts();
Honghai Zhang5622c5e2016-07-01 13:59:29 -07001541 } else {
1542 session->StopGettingPorts();
honghaiz98db68f2015-09-29 07:58:17 -07001543 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001544 }
honghaiz9b669572015-11-04 12:07:44 -08001545}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001546
honghaiz77d0d6e2015-10-27 11:34:45 -07001547// If all connections timed out, delete them all.
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001548void P2PTransportChannel::HandleAllTimedOut() {
honghaiz77d0d6e2015-10-27 11:34:45 -07001549 for (Connection* connection : connections_) {
1550 connection->Destroy();
1551 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001552}
1553
Honghai Zhang2b342bf2015-09-30 09:51:58 -07001554bool P2PTransportChannel::weak() const {
Honghai Zhang572b0942016-06-23 12:26:57 -07001555 return !selected_connection_ || selected_connection_->weak();
honghaiza58ea782015-09-24 08:13:36 -07001556}
1557
Honghai Zhange05bcc22016-08-16 18:19:14 -07001558bool P2PTransportChannel::ReadyToSend(Connection* connection) const {
Taylor Brandstetter6bb1ef22016-06-27 18:09:03 -07001559 // Note that we allow sending on an unreliable connection, because it's
1560 // possible that it became unreliable simply due to bad chance.
1561 // So this shouldn't prevent attempting to send media.
Honghai Zhange05bcc22016-08-16 18:19:14 -07001562 return connection != nullptr &&
1563 (connection->writable() ||
1564 connection->write_state() == Connection::STATE_WRITE_UNRELIABLE ||
1565 PresumedWritable(connection));
Taylor Brandstetter6bb1ef22016-06-27 18:09:03 -07001566}
1567
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001568// Handle any queued up requests
1569void P2PTransportChannel::OnMessage(rtc::Message *pmsg) {
1570 switch (pmsg->message_id) {
Taylor Brandstetterb825aee2016-06-29 13:07:16 -07001571 case MSG_SORT_AND_UPDATE_STATE:
1572 SortConnectionsAndUpdateState();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001573 break;
honghaiza58ea782015-09-24 08:13:36 -07001574 case MSG_CHECK_AND_PING:
1575 OnCheckAndPing();
Peter Thatcher54360512015-07-08 11:08:35 -07001576 break;
Honghai Zhang5622c5e2016-07-01 13:59:29 -07001577 case MSG_REGATHER_ON_FAILED_NETWORKS:
1578 OnRegatherOnFailedNetworks();
1579 break;
Steve Anton300bf8e2017-07-14 10:13:10 -07001580 case MSG_REGATHER_ON_ALL_NETWORKS:
1581 OnRegatherOnAllNetworks();
1582 break;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001583 default:
nissec80e7412017-01-11 05:56:46 -08001584 RTC_NOTREACHED();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001585 break;
1586 }
1587}
1588
honghaiza58ea782015-09-24 08:13:36 -07001589// Handle queued up check-and-ping request
1590void P2PTransportChannel::OnCheckAndPing() {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001591 // Make sure the states of the connections are up-to-date (since this affects
1592 // which ones are pingable).
1593 UpdateConnectionStates();
Honghai Zhang572b0942016-06-23 12:26:57 -07001594 // When the selected connection is not receiving or not writable, or any
1595 // active connection has not been pinged enough times, use the weak ping
1596 // interval.
honghaiz524ecc22016-05-25 12:48:31 -07001597 bool need_more_pings_at_weak_interval = std::any_of(
1598 connections_.begin(), connections_.end(), [](Connection* conn) {
1599 return conn->active() &&
1600 conn->num_pings_sent() < MIN_PINGS_AT_WEAK_PING_INTERVAL;
1601 });
1602 int ping_interval = (weak() || need_more_pings_at_weak_interval)
skvlad51072462017-02-02 11:50:14 -08001603 ? weak_ping_interval()
1604 : strong_ping_interval();
nisse1bffc1d2016-05-02 08:18:55 -07001605 if (rtc::TimeMillis() >= last_ping_sent_ms_ + ping_interval) {
honghaiza58ea782015-09-24 08:13:36 -07001606 Connection* conn = FindNextPingableConnection();
1607 if (conn) {
1608 PingConnection(conn);
guoweis36f01372016-03-02 18:02:40 -08001609 MarkConnectionPinged(conn);
honghaiza58ea782015-09-24 08:13:36 -07001610 }
Peter Thatcher54360512015-07-08 11:08:35 -07001611 }
Honghai Zhang049fbb12016-03-07 11:13:07 -08001612 int delay = std::min(ping_interval, check_receiving_interval_);
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -07001613 thread()->PostDelayed(RTC_FROM_HERE, delay, this, MSG_CHECK_AND_PING);
Peter Thatcher54360512015-07-08 11:08:35 -07001614}
1615
Honghai Zhang381b4212015-12-04 12:24:03 -08001616// A connection is considered a backup connection if the channel state
Honghai Zhang572b0942016-06-23 12:26:57 -07001617// is completed, the connection is not the selected connection and it is active.
Taylor Brandstetterb825aee2016-06-29 13:07:16 -07001618bool P2PTransportChannel::IsBackupConnection(const Connection* conn) const {
zhihuangd06adf62017-01-12 15:58:31 -08001619 return state_ == IceTransportState::STATE_COMPLETED &&
1620 conn != selected_connection_ && conn->active();
Honghai Zhang381b4212015-12-04 12:24:03 -08001621}
1622
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001623// Is the connection in a state for us to even consider pinging the other side?
Guo-wei Shiehbe508a12015-04-06 12:48:47 -07001624// We consider a connection pingable even if it's not connected because that's
1625// how a TCP connection is kicked into reconnecting on the active side.
Taylor Brandstetterb825aee2016-06-29 13:07:16 -07001626bool P2PTransportChannel::IsPingable(const Connection* conn,
1627 int64_t now) const {
Peter Thatcher7351f462015-04-02 16:39:16 -07001628 const Candidate& remote = conn->remote_candidate();
1629 // We should never get this far with an empty remote ufrag.
nisseede5da42017-01-12 05:15:36 -08001630 RTC_DCHECK(!remote.username().empty());
Peter Thatcher7351f462015-04-02 16:39:16 -07001631 if (remote.username().empty() || remote.password().empty()) {
1632 // If we don't have an ICE ufrag and pwd, there's no way we can ping.
1633 return false;
1634 }
1635
honghaiz079a7a12016-06-22 16:26:29 -07001636 // A failed connection will not be pinged.
hbos06495bc2017-01-02 08:08:18 -08001637 if (conn->state() == IceCandidatePairState::FAILED) {
honghaiz079a7a12016-06-22 16:26:29 -07001638 return false;
1639 }
1640
Guo-wei Shiehbe508a12015-04-06 12:48:47 -07001641 // An never connected connection cannot be written to at all, so pinging is
1642 // out of the question. However, if it has become WRITABLE, it is in the
1643 // reconnecting state so ping is needed.
Peter Thatcher04ac81f2015-09-21 11:48:28 -07001644 if (!conn->connected() && !conn->writable()) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001645 return false;
Guo-wei Shiehbe508a12015-04-06 12:48:47 -07001646 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001647
Honghai Zhang381b4212015-12-04 12:24:03 -08001648 // If the channel is weakly connected, ping all connections.
1649 if (weak()) {
1650 return true;
1651 }
1652
1653 // Always ping active connections regardless whether the channel is completed
1654 // or not, but backup connections are pinged at a slower rate.
1655 if (IsBackupConnection(conn)) {
Honghai Zhangfd16da22016-08-17 16:12:46 -07001656 return conn->rtt_samples() == 0 ||
1657 (now >= conn->last_ping_response_received() +
guoweis36f01372016-03-02 18:02:40 -08001658 config_.backup_connection_ping_interval);
Honghai Zhang381b4212015-12-04 12:24:03 -08001659 }
zhihuang435264a2016-06-21 11:28:38 -07001660 // Don't ping inactive non-backup connections.
1661 if (!conn->active()) {
1662 return false;
1663 }
1664
1665 // Do ping unwritable, active connections.
1666 if (!conn->writable()) {
1667 return true;
1668 }
1669
1670 // Ping writable, active connections if it's been long enough since the last
1671 // ping.
honghaiz7252a002016-11-08 20:04:09 -08001672 return WritableConnectionPastPingInterval(conn, now);
zhihuang435264a2016-06-21 11:28:38 -07001673}
1674
honghaiz7252a002016-11-08 20:04:09 -08001675bool P2PTransportChannel::WritableConnectionPastPingInterval(
1676 const Connection* conn,
1677 int64_t now) const {
1678 int interval = CalculateActiveWritablePingInterval(conn, now);
1679 return conn->last_ping_sent() + interval <= now;
zhihuang435264a2016-06-21 11:28:38 -07001680}
1681
Taylor Brandstetterb825aee2016-06-29 13:07:16 -07001682int P2PTransportChannel::CalculateActiveWritablePingInterval(
1683 const Connection* conn,
1684 int64_t now) const {
zhihuang435264a2016-06-21 11:28:38 -07001685 // Ping each connection at a higher rate at least
1686 // MIN_PINGS_AT_WEAK_PING_INTERVAL times.
1687 if (conn->num_pings_sent() < MIN_PINGS_AT_WEAK_PING_INTERVAL) {
skvlad51072462017-02-02 11:50:14 -08001688 return weak_ping_interval();
zhihuang435264a2016-06-21 11:28:38 -07001689 }
1690
1691 int stable_interval = config_.stable_writable_connection_ping_interval;
honghaiz7252a002016-11-08 20:04:09 -08001692 int weak_or_stablizing_interval = std::min(
1693 stable_interval, WEAK_OR_STABILIZING_WRITABLE_CONNECTION_PING_INTERVAL);
1694 // If the channel is weak or the connection is not stable yet, use the
1695 // weak_or_stablizing_interval.
1696 return (!weak() && conn->stable(now)) ? stable_interval
1697 : weak_or_stablizing_interval;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001698}
1699
honghaiz7252a002016-11-08 20:04:09 -08001700// Returns the next pingable connection to ping.
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001701Connection* P2PTransportChannel::FindNextPingableConnection() {
nisse1bffc1d2016-05-02 08:18:55 -07001702 int64_t now = rtc::TimeMillis();
honghaiz7252a002016-11-08 20:04:09 -08001703
1704 // Rule 1: Selected connection takes priority over non-selected ones.
1705 if (selected_connection_ && selected_connection_->connected() &&
1706 selected_connection_->writable() &&
1707 WritableConnectionPastPingInterval(selected_connection_, now)) {
1708 return selected_connection_;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001709 }
honghaiz7252a002016-11-08 20:04:09 -08001710
1711 // Rule 2: If the channel is weak, we need to find a new writable and
1712 // receiving connection, probably on a different network. If there are lots of
1713 // connections, it may take several seconds between two pings for every
1714 // non-selected connection. This will cause the receiving state of those
1715 // connections to be false, and thus they won't be selected. This is
1716 // problematic for network fail-over. We want to make sure at least one
1717 // connection per network is pinged frequently enough in order for it to be
1718 // selectable. So we prioritize one connection per network.
1719 // Rule 2.1: Among such connections, pick the one with the earliest
1720 // last-ping-sent time.
1721 if (weak()) {
1722 auto selectable_connections = GetBestWritableConnectionPerNetwork();
1723 std::vector<Connection*> pingable_selectable_connections;
1724 std::copy_if(selectable_connections.begin(), selectable_connections.end(),
1725 std::back_inserter(pingable_selectable_connections),
1726 [this, now](Connection* conn) {
1727 return WritableConnectionPastPingInterval(conn, now);
1728 });
1729 auto iter = std::min_element(pingable_selectable_connections.begin(),
1730 pingable_selectable_connections.end(),
1731 [](Connection* conn1, Connection* conn2) {
1732 return conn1->last_ping_sent() <
1733 conn2->last_ping_sent();
1734 });
1735 if (iter != pingable_selectable_connections.end()) {
1736 return *iter;
1737 }
1738 }
1739
1740 // Rule 3: Triggered checks have priority over non-triggered connections.
1741 // Rule 3.1: Among triggered checks, oldest takes precedence.
1742 Connection* oldest_triggered_check =
1743 FindOldestConnectionNeedingTriggeredCheck(now);
1744 if (oldest_triggered_check) {
1745 return oldest_triggered_check;
1746 }
1747
1748 // Rule 4: Unpinged connections have priority over pinged ones.
1749 RTC_CHECK(connections_.size() ==
1750 pinged_connections_.size() + unpinged_connections_.size());
1751 // If there are unpinged and pingable connections, only ping those.
1752 // Otherwise, treat everything as unpinged.
1753 // TODO(honghaiz): Instead of adding two separate vectors, we can add a state
1754 // "pinged" to filter out unpinged connections.
1755 if (std::find_if(unpinged_connections_.begin(), unpinged_connections_.end(),
1756 [this, now](Connection* conn) {
1757 return this->IsPingable(conn, now);
1758 }) == unpinged_connections_.end()) {
1759 unpinged_connections_.insert(pinged_connections_.begin(),
1760 pinged_connections_.end());
1761 pinged_connections_.clear();
1762 }
1763
1764 // Among un-pinged pingable connections, "more pingable" takes precedence.
1765 std::vector<Connection*> pingable_connections;
1766 std::copy_if(unpinged_connections_.begin(), unpinged_connections_.end(),
1767 std::back_inserter(pingable_connections),
1768 [this, now](Connection* conn) { return IsPingable(conn, now); });
1769 auto iter =
1770 std::max_element(pingable_connections.begin(), pingable_connections.end(),
solenberge08b2532017-01-17 06:18:10 -08001771 [this](Connection* conn1, Connection* conn2) {
honghaiz7252a002016-11-08 20:04:09 -08001772 return MorePingable(conn1, conn2) == conn2;
1773 });
1774 if (iter != pingable_connections.end()) {
1775 return *iter;
1776 }
1777 return nullptr;
guoweis36f01372016-03-02 18:02:40 -08001778}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001779
guoweis36f01372016-03-02 18:02:40 -08001780void P2PTransportChannel::MarkConnectionPinged(Connection* conn) {
1781 if (conn && pinged_connections_.insert(conn).second) {
1782 unpinged_connections_.erase(conn);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001783 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001784}
1785
1786// Apart from sending ping from |conn| this method also updates
Honghai Zhang8cd8f812016-08-03 19:50:41 -07001787// |use_candidate_attr| and |nomination| flags. One of the flags is set to
1788// nominate |conn| if this channel is in CONTROLLING.
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001789void P2PTransportChannel::PingConnection(Connection* conn) {
Honghai Zhang8cd8f812016-08-03 19:50:41 -07001790 bool use_candidate_attr = false;
1791 uint32_t nomination = 0;
1792 if (ice_role_ == ICEROLE_CONTROLLING) {
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07001793 bool renomination_supported = ice_parameters_.renomination &&
1794 !remote_ice_parameters_.empty() &&
1795 remote_ice_parameters_.back().renomination;
1796 if (renomination_supported) {
Honghai Zhang8cd8f812016-08-03 19:50:41 -07001797 nomination = GetNominationAttr(conn);
1798 } else {
1799 use_candidate_attr =
1800 GetUseCandidateAttr(conn, config_.default_nomination_mode);
1801 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001802 }
Honghai Zhang8cd8f812016-08-03 19:50:41 -07001803 conn->set_nomination(nomination);
1804 conn->set_use_candidate_attr(use_candidate_attr);
nisse1bffc1d2016-05-02 08:18:55 -07001805 last_ping_sent_ms_ = rtc::TimeMillis();
honghaiza58ea782015-09-24 08:13:36 -07001806 conn->Ping(last_ping_sent_ms_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001807}
1808
Honghai Zhang8cd8f812016-08-03 19:50:41 -07001809uint32_t P2PTransportChannel::GetNominationAttr(Connection* conn) const {
1810 return (conn == selected_connection_) ? nomination_ : 0;
1811}
1812
1813// Nominate a connection based on the NominationMode.
1814bool P2PTransportChannel::GetUseCandidateAttr(Connection* conn,
1815 NominationMode mode) const {
1816 switch (mode) {
1817 case NominationMode::REGULAR:
1818 // TODO(honghaiz): Implement regular nomination.
1819 return false;
1820 case NominationMode::AGGRESSIVE:
1821 if (remote_ice_mode_ == ICEMODE_LITE) {
1822 return GetUseCandidateAttr(conn, NominationMode::REGULAR);
1823 }
1824 return true;
1825 case NominationMode::SEMI_AGGRESSIVE: {
1826 // Nominate if
1827 // a) Remote is in FULL ICE AND
1828 // a.1) |conn| is the selected connection OR
1829 // a.2) there is no selected connection OR
1830 // a.3) the selected connection is unwritable OR
1831 // a.4) |conn| has higher priority than selected_connection.
1832 // b) Remote is in LITE ICE AND
1833 // b.1) |conn| is the selected_connection AND
1834 // b.2) |conn| is writable.
1835 bool selected = conn == selected_connection_;
1836 if (remote_ice_mode_ == ICEMODE_LITE) {
1837 return selected && conn->writable();
1838 }
1839 bool better_than_selected =
1840 !selected_connection_ || !selected_connection_->writable() ||
1841 CompareConnectionCandidates(selected_connection_, conn) < 0;
1842 return selected || better_than_selected;
1843 }
1844 default:
nisseeb4ca4e2017-01-12 02:24:27 -08001845 RTC_NOTREACHED();
Honghai Zhang8cd8f812016-08-03 19:50:41 -07001846 return false;
1847 }
1848}
1849
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001850// When a connection's state changes, we need to figure out who to use as
Honghai Zhang572b0942016-06-23 12:26:57 -07001851// the selected connection again. It could have become usable, or become
1852// unusable.
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001853void P2PTransportChannel::OnConnectionStateChange(Connection* connection) {
nisseede5da42017-01-12 05:15:36 -08001854 RTC_DCHECK(network_thread_ == rtc::Thread::Current());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001855
honghaiz9b669572015-11-04 12:07:44 -08001856 // May stop the allocator session when at least one connection becomes
Honghai Zhang5a246372016-05-02 17:28:35 -07001857 // strongly connected after starting to get ports and the local candidate of
1858 // the connection is at the latest generation. It is not enough to check
honghaiz9b669572015-11-04 12:07:44 -08001859 // that the connection becomes weakly connected because the connection may be
1860 // changing from (writable, receiving) to (writable, not receiving).
Honghai Zhang5a246372016-05-02 17:28:35 -07001861 bool strongly_connected = !connection->weak();
1862 bool latest_generation = connection->local_candidate().generation() >=
1863 allocator_session()->generation();
1864 if (strongly_connected && latest_generation) {
honghaiz9b669572015-11-04 12:07:44 -08001865 MaybeStopPortAllocatorSessions();
1866 }
1867
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001868 // We have to unroll the stack before doing this because we may be changing
1869 // the state of connections while sorting.
Taylor Brandstetterb825aee2016-06-29 13:07:16 -07001870 RequestSortAndStateUpdate();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001871}
1872
1873// When a connection is removed, edit it out, and then update our best
1874// connection.
1875void P2PTransportChannel::OnConnectionDestroyed(Connection* connection) {
nisseede5da42017-01-12 05:15:36 -08001876 RTC_DCHECK(network_thread_ == rtc::Thread::Current());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001877
Honghai Zhang572b0942016-06-23 12:26:57 -07001878 // Note: the previous selected_connection_ may be destroyed by now, so don't
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001879 // use it.
1880
1881 // Remove this connection from the list.
1882 std::vector<Connection*>::iterator iter =
1883 std::find(connections_.begin(), connections_.end(), connection);
nisseede5da42017-01-12 05:15:36 -08001884 RTC_DCHECK(iter != connections_.end());
guoweis36f01372016-03-02 18:02:40 -08001885 pinged_connections_.erase(*iter);
1886 unpinged_connections_.erase(*iter);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001887 connections_.erase(iter);
1888
honghaiz7252a002016-11-08 20:04:09 -08001889 LOG_J(LS_INFO, this) << "Removed connection " << std::hex << connection
1890 << std::dec << " (" << connections_.size()
1891 << " remaining)";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001892
Honghai Zhang572b0942016-06-23 12:26:57 -07001893 // If this is currently the selected connection, then we need to pick a new
Taylor Brandstetterb825aee2016-06-29 13:07:16 -07001894 // one. The call to SortConnectionsAndUpdateState will pick a new one. It
1895 // looks at the current selected connection in order to avoid switching
1896 // between fairly similar ones. Since this connection is no longer an option,
1897 // we can just set selected to nullptr and re-choose a best assuming that
1898 // there was no selected connection.
Honghai Zhang572b0942016-06-23 12:26:57 -07001899 if (selected_connection_ == connection) {
honghaiz9ad0db52016-07-14 19:30:28 -07001900 LOG(LS_INFO) << "Selected connection destroyed. Will choose a new one.";
Honghai Zhang572b0942016-06-23 12:26:57 -07001901 SwitchSelectedConnection(nullptr);
Taylor Brandstetterb825aee2016-06-29 13:07:16 -07001902 RequestSortAndStateUpdate();
1903 } else {
1904 // If a non-selected connection was destroyed, we don't need to re-sort but
1905 // we do need to update state, because we could be switching to "failed" or
1906 // "completed".
1907 UpdateState();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001908 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001909}
1910
Honghai Zhang5622c5e2016-07-01 13:59:29 -07001911// When a port is destroyed, remove it from our list of ports to use for
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001912// connection attempts.
1913void P2PTransportChannel::OnPortDestroyed(PortInterface* port) {
nisseede5da42017-01-12 05:15:36 -08001914 RTC_DCHECK(network_thread_ == rtc::Thread::Current());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001915
deadbeefdfc42442016-06-21 14:19:48 -07001916 ports_.erase(std::remove(ports_.begin(), ports_.end(), port), ports_.end());
Honghai Zhang8eeecab2016-07-28 13:20:15 -07001917 pruned_ports_.erase(
1918 std::remove(pruned_ports_.begin(), pruned_ports_.end(), port),
1919 pruned_ports_.end());
Honghai Zhang5622c5e2016-07-01 13:59:29 -07001920 LOG(INFO) << "Removed port because it is destroyed: " << ports_.size()
1921 << " remaining";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001922}
1923
Honghai Zhang8eeecab2016-07-28 13:20:15 -07001924void P2PTransportChannel::OnPortsPruned(
Honghai Zhang5622c5e2016-07-01 13:59:29 -07001925 PortAllocatorSession* session,
1926 const std::vector<PortInterface*>& ports) {
nisseede5da42017-01-12 05:15:36 -08001927 RTC_DCHECK(network_thread_ == rtc::Thread::Current());
Honghai Zhang5622c5e2016-07-01 13:59:29 -07001928 for (PortInterface* port : ports) {
Honghai Zhanga74363c2016-07-28 18:06:15 -07001929 if (PrunePort(port)) {
Honghai Zhang5622c5e2016-07-01 13:59:29 -07001930 LOG(INFO) << "Removed port: " << port->ToString() << " " << ports_.size()
1931 << " remaining";
1932 }
1933 }
1934}
1935
1936void P2PTransportChannel::OnCandidatesRemoved(
1937 PortAllocatorSession* session,
1938 const std::vector<Candidate>& candidates) {
nisseede5da42017-01-12 05:15:36 -08001939 RTC_DCHECK(network_thread_ == rtc::Thread::Current());
Honghai Zhang5622c5e2016-07-01 13:59:29 -07001940 // Do not signal candidate removals if continual gathering is not enabled, or
1941 // if this is not the last session because an ICE restart would have signaled
1942 // the remote side to remove all candidates in previous sessions.
1943 if (!config_.gather_continually() || session != allocator_session()) {
honghaize3c6c822016-02-17 13:00:28 -08001944 return;
1945 }
Honghai Zhang5622c5e2016-07-01 13:59:29 -07001946
1947 std::vector<Candidate> candidates_to_remove;
1948 for (Candidate candidate : candidates) {
Honghai Zhang7fb69db2016-03-14 11:59:18 -07001949 candidate.set_transport_name(transport_name());
Honghai Zhang5622c5e2016-07-01 13:59:29 -07001950 candidates_to_remove.push_back(candidate);
Honghai Zhang7fb69db2016-03-14 11:59:18 -07001951 }
Honghai Zhang5622c5e2016-07-01 13:59:29 -07001952 SignalCandidatesRemoved(this, candidates_to_remove);
1953}
1954
1955void P2PTransportChannel::OnRegatherOnFailedNetworks() {
1956 // Only re-gather when the current session is in the CLEARED state (i.e., not
1957 // running or stopped). It is only possible to enter this state when we gather
1958 // continually, so there is an implicit check on continual gathering here.
1959 if (!allocator_sessions_.empty() && allocator_session()->IsCleared()) {
1960 allocator_session()->RegatherOnFailedNetworks();
1961 }
1962
1963 thread()->PostDelayed(RTC_FROM_HERE,
1964 *config_.regather_on_failed_networks_interval, this,
1965 MSG_REGATHER_ON_FAILED_NETWORKS);
honghaize3c6c822016-02-17 13:00:28 -08001966}
1967
Steve Anton300bf8e2017-07-14 10:13:10 -07001968void P2PTransportChannel::OnRegatherOnAllNetworks() {
1969 if (!allocator_sessions_.empty() && allocator_session()->IsCleared()) {
1970 allocator_session()->RegatherOnAllNetworks();
1971 }
1972
1973 thread()->PostDelayed(RTC_FROM_HERE,
1974 SampleRegatherAllNetworksInterval(), this,
1975 MSG_REGATHER_ON_ALL_NETWORKS);
1976}
1977
Honghai Zhanga74363c2016-07-28 18:06:15 -07001978void P2PTransportChannel::PruneAllPorts() {
1979 pruned_ports_.insert(pruned_ports_.end(), ports_.begin(), ports_.end());
1980 ports_.clear();
1981}
1982
1983bool P2PTransportChannel::PrunePort(PortInterface* port) {
Honghai Zhangb9e7b4a2016-06-30 20:52:02 -07001984 auto it = std::find(ports_.begin(), ports_.end(), port);
1985 // Don't need to do anything if the port has been deleted from the port list.
1986 if (it == ports_.end()) {
1987 return false;
1988 }
1989 ports_.erase(it);
Honghai Zhang8eeecab2016-07-28 13:20:15 -07001990 pruned_ports_.push_back(port);
Honghai Zhangb9e7b4a2016-06-30 20:52:02 -07001991 return true;
1992}
1993
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001994// We data is available, let listeners know
deadbeefcbecd352015-09-23 11:50:27 -07001995void P2PTransportChannel::OnReadPacket(Connection* connection,
1996 const char* data,
1997 size_t len,
1998 const rtc::PacketTime& packet_time) {
nisseede5da42017-01-12 05:15:36 -08001999 RTC_DCHECK(network_thread_ == rtc::Thread::Current());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00002000
2001 // Do not deliver, if packet doesn't belong to the correct transport channel.
2002 if (!FindConnection(connection))
2003 return;
2004
2005 // Let the client know of an incoming packet
2006 SignalReadPacket(this, data, len, packet_time, 0);
honghaiz5a3acd82015-08-20 15:53:17 -07002007
2008 // May need to switch the sending connection based on the receiving media path
2009 // if this is the controlled side.
honghaiz9ad0db52016-07-14 19:30:28 -07002010 if (ice_role_ == ICEROLE_CONTROLLED) {
2011 MaybeSwitchSelectedConnection(connection, "data received");
honghaiz5a3acd82015-08-20 15:53:17 -07002012 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00002013}
2014
Stefan Holmer55674ff2016-01-14 15:49:16 +01002015void P2PTransportChannel::OnSentPacket(const rtc::SentPacket& sent_packet) {
nisseede5da42017-01-12 05:15:36 -08002016 RTC_DCHECK(network_thread_ == rtc::Thread::Current());
stefanc1aeaf02015-10-15 07:26:07 -07002017
2018 SignalSentPacket(this, sent_packet);
2019}
2020
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00002021void P2PTransportChannel::OnReadyToSend(Connection* connection) {
Honghai Zhang572b0942016-06-23 12:26:57 -07002022 if (connection == selected_connection_ && writable()) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00002023 SignalReadyToSend(this);
2024 }
2025}
2026
guoweis36f01372016-03-02 18:02:40 -08002027// Find "triggered checks". We ping first those connections that have
2028// received a ping but have not sent a ping since receiving it
honghaiz7252a002016-11-08 20:04:09 -08002029// (last_ping_received > last_ping_sent). But we shouldn't do
guoweis36f01372016-03-02 18:02:40 -08002030// triggered checks if the connection is already writable.
2031Connection* P2PTransportChannel::FindOldestConnectionNeedingTriggeredCheck(
honghaiz34b11eb2016-03-16 08:55:44 -07002032 int64_t now) {
guoweis36f01372016-03-02 18:02:40 -08002033 Connection* oldest_needing_triggered_check = nullptr;
2034 for (auto conn : connections_) {
2035 if (!IsPingable(conn, now)) {
2036 continue;
2037 }
2038 bool needs_triggered_check =
2039 (!conn->writable() &&
2040 conn->last_ping_received() > conn->last_ping_sent());
2041 if (needs_triggered_check &&
2042 (!oldest_needing_triggered_check ||
2043 (conn->last_ping_received() <
2044 oldest_needing_triggered_check->last_ping_received()))) {
2045 oldest_needing_triggered_check = conn;
2046 }
2047 }
2048
2049 if (oldest_needing_triggered_check) {
2050 LOG(LS_INFO) << "Selecting connection for triggered check: "
2051 << oldest_needing_triggered_check->ToString();
2052 }
2053 return oldest_needing_triggered_check;
2054}
2055
guoweis36f01372016-03-02 18:02:40 -08002056Connection* P2PTransportChannel::MostLikelyToWork(Connection* conn1,
2057 Connection* conn2) {
2058 bool rr1 = IsRelayRelay(conn1);
2059 bool rr2 = IsRelayRelay(conn2);
2060 if (rr1 && !rr2) {
2061 return conn1;
2062 } else if (rr2 && !rr1) {
2063 return conn2;
2064 } else if (rr1 && rr2) {
2065 bool udp1 = IsUdp(conn1);
2066 bool udp2 = IsUdp(conn2);
2067 if (udp1 && !udp2) {
2068 return conn1;
2069 } else if (udp2 && udp1) {
2070 return conn2;
2071 }
2072 }
2073 return nullptr;
2074}
2075
2076Connection* P2PTransportChannel::LeastRecentlyPinged(Connection* conn1,
2077 Connection* conn2) {
2078 if (conn1->last_ping_sent() < conn2->last_ping_sent()) {
2079 return conn1;
2080 }
2081 if (conn1->last_ping_sent() > conn2->last_ping_sent()) {
2082 return conn2;
2083 }
2084 return nullptr;
2085}
2086
honghaiz7252a002016-11-08 20:04:09 -08002087Connection* P2PTransportChannel::MorePingable(Connection* conn1,
2088 Connection* conn2) {
guoweis36f01372016-03-02 18:02:40 -08002089 RTC_DCHECK(conn1 != conn2);
2090 if (config_.prioritize_most_likely_candidate_pairs) {
2091 Connection* most_likely_to_work_conn = MostLikelyToWork(conn1, conn2);
2092 if (most_likely_to_work_conn) {
2093 return most_likely_to_work_conn;
2094 }
2095 }
2096
2097 Connection* least_recently_pinged_conn = LeastRecentlyPinged(conn1, conn2);
2098 if (least_recently_pinged_conn) {
2099 return least_recently_pinged_conn;
2100 }
2101
2102 // During the initial state when nothing has been pinged yet, return the first
2103 // one in the ordered |connections_|.
2104 return *(std::find_if(connections_.begin(), connections_.end(),
2105 [conn1, conn2](Connection* conn) {
2106 return conn == conn1 || conn == conn2;
2107 }));
2108}
2109
zhihuangd06adf62017-01-12 15:58:31 -08002110void P2PTransportChannel::set_writable(bool writable) {
2111 if (writable_ == writable) {
2112 return;
2113 }
2114 LOG_J(LS_VERBOSE, this) << "set_writable from:" << writable_ << " to "
2115 << writable;
2116 writable_ = writable;
2117 if (writable_) {
2118 SignalReadyToSend(this);
2119 }
2120 SignalWritableState(this);
2121}
2122
2123void P2PTransportChannel::set_receiving(bool receiving) {
2124 if (receiving_ == receiving) {
2125 return;
2126 }
2127 receiving_ = receiving;
2128 SignalReceivingState(this);
2129}
2130
Steve Anton300bf8e2017-07-14 10:13:10 -07002131int P2PTransportChannel::SampleRegatherAllNetworksInterval() {
2132 auto interval = config_.regather_all_networks_interval_range;
2133 RTC_DCHECK(interval);
2134 return rand_.Rand(interval->min(), interval->max());
2135}
2136
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00002137} // namespace cricket