blob: b32d149a84941ba56ef94746bad1b8780c771d0f [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>
honghaiza58ea782015-09-24 08:13:36 -070014#include <set>
honghaize3c6c822016-02-17 13:00:28 -080015
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000016#include "webrtc/base/common.h"
17#include "webrtc/base/crc32.h"
18#include "webrtc/base/logging.h"
19#include "webrtc/base/stringencode.h"
honghaize3c6c822016-02-17 13:00:28 -080020#include "webrtc/p2p/base/candidate.h"
Honghai Zhangcc411c02016-03-29 17:27:21 -070021#include "webrtc/p2p/base/candidatepairinterface.h"
honghaize3c6c822016-02-17 13:00:28 -080022#include "webrtc/p2p/base/common.h"
23#include "webrtc/p2p/base/relayport.h" // For RELAY_PORT_TYPE.
24#include "webrtc/p2p/base/stunport.h" // For STUN_PORT_TYPE.
Henrik Kjellander98f53512015-10-28 18:17:40 +010025#include "webrtc/system_wrappers/include/field_trial.h"
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000026
27namespace {
28
29// messages for queuing up work for ourselves
Honghai Zhang5622c5e2016-07-01 13:59:29 -070030enum {
31 MSG_SORT_AND_UPDATE_STATE = 1,
32 MSG_CHECK_AND_PING,
33 MSG_REGATHER_ON_FAILED_NETWORKS
34};
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000035
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000036// The minimum improvement in RTT that justifies a switch.
Honghai Zhang5622c5e2016-07-01 13:59:29 -070037const int kMinImprovement = 10;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000038
deadbeef14f97f52016-06-22 17:14:15 -070039bool IsRelayRelay(const cricket::Connection* conn) {
guoweis36f01372016-03-02 18:02:40 -080040 return conn->local_candidate().type() == cricket::RELAY_PORT_TYPE &&
41 conn->remote_candidate().type() == cricket::RELAY_PORT_TYPE;
42}
43
44bool IsUdp(cricket::Connection* conn) {
45 return conn->local_candidate().relay_protocol() == cricket::UDP_PROTOCOL_NAME;
46}
47
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000048cricket::PortInterface::CandidateOrigin GetOrigin(cricket::PortInterface* port,
49 cricket::PortInterface* origin_port) {
50 if (!origin_port)
51 return cricket::PortInterface::ORIGIN_MESSAGE;
52 else if (port == origin_port)
53 return cricket::PortInterface::ORIGIN_THIS_PORT;
54 else
55 return cricket::PortInterface::ORIGIN_OTHER_PORT;
56}
57
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000058} // unnamed namespace
59
60namespace cricket {
61
guoweisb0bb77f2015-10-26 15:10:01 -070062// When the socket is unwritable, we will use 10 Kbps (ignoring IP+UDP headers)
63// for pinging. When the socket is writable, we will use only 1 Kbps because
64// we don't want to degrade the quality on a modem. These numbers should work
65// well on a 28.8K modem, which is the slowest connection on which the voice
66// quality is reasonable at all.
Honghai Zhang049fbb12016-03-07 11:13:07 -080067static const int PING_PACKET_SIZE = 60 * 8;
Honghai Zhang572b0942016-06-23 12:26:57 -070068// STRONG_PING_INTERVAL (480ms) is applied when the selected connection is both
guoweisb0bb77f2015-10-26 15:10:01 -070069// writable and receiving.
Honghai Zhang049fbb12016-03-07 11:13:07 -080070static const int STRONG_PING_INTERVAL = 1000 * PING_PACKET_SIZE / 1000;
Honghai Zhang572b0942016-06-23 12:26:57 -070071// WEAK_PING_INTERVAL (48ms) is applied when the selected connection is either
72// not writable or not receiving.
Honghai Zhang049fbb12016-03-07 11:13:07 -080073const int WEAK_PING_INTERVAL = 1000 * PING_PACKET_SIZE / 10000;
guoweisb0bb77f2015-10-26 15:10:01 -070074
zhihuang435264a2016-06-21 11:28:38 -070075// Writable connections are pinged at a faster rate while stabilizing.
76const int STABILIZING_WRITABLE_CONNECTION_PING_INTERVAL = 900; // ms
77
78// Writable connections are pinged at a slower rate once stabilized.
79const int STABLE_WRITABLE_CONNECTION_PING_INTERVAL = 2500; // ms
guoweisb0bb77f2015-10-26 15:10:01 -070080
Honghai Zhang049fbb12016-03-07 11:13:07 -080081static const int MIN_CHECK_RECEIVING_INTERVAL = 50; // ms
guoweisb0bb77f2015-10-26 15:10:01 -070082
honghaiz9ad0db52016-07-14 19:30:28 -070083static const int RECEIVING_SWITCHING_DELAY = 1000; // ms
84
Honghai Zhang5622c5e2016-07-01 13:59:29 -070085// We periodically check if any existing networks do not have any connection
86// and regather on those networks.
87static const int DEFAULT_REGATHER_ON_FAILED_NETWORKS_INTERVAL = 5 * 60 * 1000;
Honghai Zhang572b0942016-06-23 12:26:57 -070088static constexpr int a_is_better = 1;
89static constexpr int b_is_better = -1;
90
deadbeefcbecd352015-09-23 11:50:27 -070091P2PTransportChannel::P2PTransportChannel(const std::string& transport_name,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000092 int component,
guidou74db7772016-02-18 01:57:49 -080093 P2PTransport* transport,
deadbeefcbecd352015-09-23 11:50:27 -070094 PortAllocator* allocator)
mikescarlettb9dd7c52016-02-19 20:43:45 -080095 : P2PTransportChannel(transport_name, component, allocator) {}
96
97P2PTransportChannel::P2PTransportChannel(const std::string& transport_name,
98 int component,
99 PortAllocator* allocator)
deadbeefcbecd352015-09-23 11:50:27 -0700100 : TransportChannelImpl(transport_name, component),
deadbeefcbecd352015-09-23 11:50:27 -0700101 allocator_(allocator),
102 worker_thread_(rtc::Thread::Current()),
103 incoming_only_(false),
104 error_(0),
deadbeefcbecd352015-09-23 11:50:27 -0700105 sort_dirty_(false),
deadbeefcbecd352015-09-23 11:50:27 -0700106 remote_ice_mode_(ICEMODE_FULL),
107 ice_role_(ICEROLE_UNKNOWN),
108 tiebreaker_(0),
deadbeefcbecd352015-09-23 11:50:27 -0700109 gathering_state_(kIceGatheringNew),
Honghai Zhang049fbb12016-03-07 11:13:07 -0800110 check_receiving_interval_(MIN_CHECK_RECEIVING_INTERVAL * 5),
111 config_(MIN_CHECK_RECEIVING_INTERVAL * 50 /* receiving_timeout */,
guoweis36f01372016-03-02 18:02:40 -0800112 0 /* backup_connection_ping_interval */,
Honghai Zhang5622c5e2016-07-01 13:59:29 -0700113 GATHER_ONCE /* continual_gathering_policy */,
guoweis36f01372016-03-02 18:02:40 -0800114 false /* prioritize_most_likely_candidate_pairs */,
deadbeef14f97f52016-06-22 17:14:15 -0700115 STABLE_WRITABLE_CONNECTION_PING_INTERVAL,
Honghai Zhang5622c5e2016-07-01 13:59:29 -0700116 true /* presume_writable_when_fully_relayed */,
honghaiz9ad0db52016-07-14 19:30:28 -0700117 DEFAULT_REGATHER_ON_FAILED_NETWORKS_INTERVAL,
118 RECEIVING_SWITCHING_DELAY) {
Honghai Zhang049fbb12016-03-07 11:13:07 -0800119 uint32_t weak_ping_interval = ::strtoul(
guoweisb0bb77f2015-10-26 15:10:01 -0700120 webrtc::field_trial::FindFullName("WebRTC-StunInterPacketDelay").c_str(),
121 nullptr, 10);
Honghai Zhang049fbb12016-03-07 11:13:07 -0800122 if (weak_ping_interval) {
123 weak_ping_interval_ = static_cast<int>(weak_ping_interval);
guoweisb0bb77f2015-10-26 15:10:01 -0700124 }
125}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000126
127P2PTransportChannel::~P2PTransportChannel() {
128 ASSERT(worker_thread_ == rtc::Thread::Current());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000129}
130
131// Add the allocator session to our list so that we know which sessions
132// are still active.
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700133void P2PTransportChannel::AddAllocatorSession(
134 std::unique_ptr<PortAllocatorSession> session) {
honghaiz9b669572015-11-04 12:07:44 -0800135 ASSERT(worker_thread_ == rtc::Thread::Current());
136
Peter Boström0c4e06b2015-10-07 12:23:21 +0200137 session->set_generation(static_cast<uint32_t>(allocator_sessions_.size()));
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700138 session->SignalPortReady.connect(this, &P2PTransportChannel::OnPortReady);
Honghai Zhang8eeecab2016-07-28 13:20:15 -0700139 session->SignalPortsPruned.connect(this, &P2PTransportChannel::OnPortsPruned);
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700140 session->SignalCandidatesReady.connect(
141 this, &P2PTransportChannel::OnCandidatesReady);
Honghai Zhang5622c5e2016-07-01 13:59:29 -0700142 session->SignalCandidatesRemoved.connect(
143 this, &P2PTransportChannel::OnCandidatesRemoved);
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700144 session->SignalCandidatesAllocationDone.connect(
145 this, &P2PTransportChannel::OnCandidatesAllocationDone);
Honghai Zhanga74363c2016-07-28 18:06:15 -0700146 if (!allocator_sessions_.empty()) {
147 allocator_session()->PruneAllPorts();
148 }
149 allocator_sessions_.push_back(std::move(session));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000150
151 // We now only want to apply new candidates that we receive to the ports
152 // created by this new session because these are replacing those of the
153 // previous sessions.
Honghai Zhanga74363c2016-07-28 18:06:15 -0700154 PruneAllPorts();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000155}
156
157void P2PTransportChannel::AddConnection(Connection* connection) {
158 connections_.push_back(connection);
guoweis36f01372016-03-02 18:02:40 -0800159 unpinged_connections_.insert(connection);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000160 connection->set_remote_ice_mode(remote_ice_mode_);
Honghai Zhang049fbb12016-03-07 11:13:07 -0800161 connection->set_receiving_timeout(config_.receiving_timeout);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000162 connection->SignalReadPacket.connect(
163 this, &P2PTransportChannel::OnReadPacket);
164 connection->SignalReadyToSend.connect(
165 this, &P2PTransportChannel::OnReadyToSend);
166 connection->SignalStateChange.connect(
167 this, &P2PTransportChannel::OnConnectionStateChange);
168 connection->SignalDestroyed.connect(
169 this, &P2PTransportChannel::OnConnectionDestroyed);
honghaiz5a3acd82015-08-20 15:53:17 -0700170 connection->SignalNominated.connect(this, &P2PTransportChannel::OnNominated);
deadbeefcbecd352015-09-23 11:50:27 -0700171 had_connection_ = true;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000172}
173
Honghai Zhang572b0942016-06-23 12:26:57 -0700174// Determines whether we should switch the selected connection to
175// |new_connection| based the writable/receiving state, the nomination state,
176// and the last data received time. This prevents the controlled side from
177// switching the selected connection too frequently when the controlling side
178// is doing aggressive nominations. The precedence of the connection switching
179// criteria is as follows:
180// i) write/receiving/connected states
181// ii) For controlled side,
182// a) nomination state,
183// b) last data received time.
184// iii) Lower cost / higher priority.
185// iv) rtt.
186// TODO(honghaiz): Stop the aggressive nomination on the controlling side and
187// implement the ice-renomination option.
188bool P2PTransportChannel::ShouldSwitchSelectedConnection(
honghaiz9ad0db52016-07-14 19:30:28 -0700189 Connection* new_connection,
190 bool* missed_receiving_unchanged_threshold) const {
Honghai Zhang572b0942016-06-23 12:26:57 -0700191 if (!new_connection || selected_connection_ == new_connection) {
192 return false;
193 }
194
195 if (selected_connection_ == nullptr) {
196 return true;
197 }
198
honghaiz9ad0db52016-07-14 19:30:28 -0700199 rtc::Optional<int64_t> receiving_unchanged_threshold(
200 rtc::TimeMillis() - config_.receiving_switching_delay.value_or(0));
201 int cmp = CompareConnections(selected_connection_, new_connection,
202 receiving_unchanged_threshold,
203 missed_receiving_unchanged_threshold);
Honghai Zhang572b0942016-06-23 12:26:57 -0700204 if (cmp != 0) {
205 return cmp < 0;
206 }
207
208 // If everything else is the same, switch only if rtt has improved by
209 // a margin.
210 return new_connection->rtt() <= selected_connection_->rtt() - kMinImprovement;
211}
212
honghaiz9ad0db52016-07-14 19:30:28 -0700213bool P2PTransportChannel::MaybeSwitchSelectedConnection(
214 Connection* new_connection,
215 const std::string& reason) {
216 bool missed_receiving_unchanged_threshold = false;
217 if (ShouldSwitchSelectedConnection(new_connection,
218 &missed_receiving_unchanged_threshold)) {
219 LOG(LS_INFO) << "Switching selected connection due to " << reason;
220 SwitchSelectedConnection(new_connection);
221 return true;
222 }
223 if (missed_receiving_unchanged_threshold &&
224 config_.receiving_switching_delay) {
225 // If we do not switch to the connection because it missed the receiving
226 // threshold, the new connection is in a better receiving state than the
227 // currently selected connection. So we need to re-check whether it needs
228 // to be switched at a later time.
229 thread()->PostDelayed(RTC_FROM_HERE, *config_.receiving_switching_delay,
230 this, MSG_SORT_AND_UPDATE_STATE);
231 }
232 return false;
233}
234
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000235void P2PTransportChannel::SetIceRole(IceRole ice_role) {
236 ASSERT(worker_thread_ == rtc::Thread::Current());
237 if (ice_role_ != ice_role) {
238 ice_role_ = ice_role;
deadbeefdfc42442016-06-21 14:19:48 -0700239 for (PortInterface* port : ports_) {
240 port->SetIceRole(ice_role);
241 }
Honghai Zhanga74363c2016-07-28 18:06:15 -0700242 // Update role on pruned ports as well, because they may still have
deadbeefdfc42442016-06-21 14:19:48 -0700243 // connections alive that should be using the correct role.
Honghai Zhang8eeecab2016-07-28 13:20:15 -0700244 for (PortInterface* port : pruned_ports_) {
deadbeefdfc42442016-06-21 14:19:48 -0700245 port->SetIceRole(ice_role);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000246 }
247 }
248}
249
Peter Boström0c4e06b2015-10-07 12:23:21 +0200250void P2PTransportChannel::SetIceTiebreaker(uint64_t tiebreaker) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000251 ASSERT(worker_thread_ == rtc::Thread::Current());
Honghai Zhang8eeecab2016-07-28 13:20:15 -0700252 if (!ports_.empty() || !pruned_ports_.empty()) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000253 LOG(LS_ERROR)
254 << "Attempt to change tiebreaker after Port has been allocated.";
255 return;
256 }
257
258 tiebreaker_ = tiebreaker;
259}
260
Honghai Zhang381b4212015-12-04 12:24:03 -0800261TransportChannelState P2PTransportChannel::GetState() const {
262 return state_;
263}
264
Honghai Zhang2b342bf2015-09-30 09:51:58 -0700265// A channel is considered ICE completed once there is at most one active
266// connection per network and at least one active connection.
Honghai Zhang381b4212015-12-04 12:24:03 -0800267TransportChannelState P2PTransportChannel::ComputeState() const {
Honghai Zhang2b342bf2015-09-30 09:51:58 -0700268 if (!had_connection_) {
269 return TransportChannelState::STATE_INIT;
guoweis@webrtc.org8c9ff202014-12-04 07:56:02 +0000270 }
271
Honghai Zhang2b342bf2015-09-30 09:51:58 -0700272 std::vector<Connection*> active_connections;
273 for (Connection* connection : connections_) {
274 if (connection->active()) {
275 active_connections.push_back(connection);
276 }
277 }
278 if (active_connections.empty()) {
279 return TransportChannelState::STATE_FAILED;
280 }
281
282 std::set<rtc::Network*> networks;
283 for (Connection* connection : active_connections) {
284 rtc::Network* network = connection->port()->Network();
guoweis@webrtc.org8c9ff202014-12-04 07:56:02 +0000285 if (networks.find(network) == networks.end()) {
286 networks.insert(network);
287 } else {
288 LOG_J(LS_VERBOSE, this) << "Ice not completed yet for this channel as "
289 << network->ToString()
290 << " has more than 1 connection.";
291 return TransportChannelState::STATE_CONNECTING;
292 }
293 }
guoweis@webrtc.org8c9ff202014-12-04 07:56:02 +0000294
295 return TransportChannelState::STATE_COMPLETED;
296}
297
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000298void P2PTransportChannel::SetIceCredentials(const std::string& ice_ufrag,
299 const std::string& ice_pwd) {
300 ASSERT(worker_thread_ == rtc::Thread::Current());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000301 ice_ufrag_ = ice_ufrag;
302 ice_pwd_ = ice_pwd;
deadbeefcbecd352015-09-23 11:50:27 -0700303 // Note: Candidate gathering will restart when MaybeStartGathering is next
304 // called.
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000305}
306
307void P2PTransportChannel::SetRemoteIceCredentials(const std::string& ice_ufrag,
308 const std::string& ice_pwd) {
309 ASSERT(worker_thread_ == rtc::Thread::Current());
honghaiza54a0802015-12-16 18:37:23 -0800310 IceParameters* current_ice = remote_ice();
311 IceParameters new_ice(ice_ufrag, ice_pwd);
312 if (!current_ice || *current_ice != new_ice) {
313 // Keep the ICE credentials so that newer connections
314 // are prioritized over the older ones.
315 remote_ice_parameters_.push_back(new_ice);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000316 }
317
honghaiz112fe432015-12-30 13:32:47 -0800318 // Update the pwd of remote candidate if needed.
319 for (RemoteCandidate& candidate : remote_candidates_) {
320 if (candidate.username() == ice_ufrag && candidate.password().empty()) {
321 candidate.set_password(ice_pwd);
322 }
323 }
Taylor Brandstetter0a1bc532016-04-19 18:03:26 -0700324 // We need to update the credentials and generation for any peer reflexive
325 // candidates.
honghaiz112fe432015-12-30 13:32:47 -0800326 for (Connection* conn : connections_) {
Taylor Brandstetter0a1bc532016-04-19 18:03:26 -0700327 conn->MaybeSetRemoteIceCredentialsAndGeneration(
328 ice_ufrag, ice_pwd,
329 static_cast<int>(remote_ice_parameters_.size() - 1));
jiayl@webrtc.orgdacdd942015-01-23 17:33:34 +0000330 }
Taylor Brandstetter0a1bc532016-04-19 18:03:26 -0700331 // Updating the remote ICE candidate generation could change the sort order.
Taylor Brandstetterb825aee2016-06-29 13:07:16 -0700332 RequestSortAndStateUpdate();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000333}
334
335void P2PTransportChannel::SetRemoteIceMode(IceMode mode) {
336 remote_ice_mode_ = mode;
337}
338
honghaiz1f429e32015-09-28 07:57:34 -0700339void P2PTransportChannel::SetIceConfig(const IceConfig& config) {
Honghai Zhang5622c5e2016-07-01 13:59:29 -0700340 if (config_.continual_gathering_policy != config.continual_gathering_policy) {
honghaizda2c9452016-07-15 17:55:34 -0700341 config_.continual_gathering_policy = config.continual_gathering_policy;
Honghai Zhang5622c5e2016-07-01 13:59:29 -0700342 LOG(LS_INFO) << "Set continual_gathering_policy to "
343 << config_.continual_gathering_policy;
Honghai Zhang5622c5e2016-07-01 13:59:29 -0700344 }
honghaiz1f429e32015-09-28 07:57:34 -0700345
Honghai Zhang381b4212015-12-04 12:24:03 -0800346 if (config.backup_connection_ping_interval >= 0 &&
guoweis36f01372016-03-02 18:02:40 -0800347 config_.backup_connection_ping_interval !=
Honghai Zhang381b4212015-12-04 12:24:03 -0800348 config.backup_connection_ping_interval) {
guoweis36f01372016-03-02 18:02:40 -0800349 config_.backup_connection_ping_interval =
350 config.backup_connection_ping_interval;
Honghai Zhang381b4212015-12-04 12:24:03 -0800351 LOG(LS_INFO) << "Set backup connection ping interval to "
guoweis36f01372016-03-02 18:02:40 -0800352 << config_.backup_connection_ping_interval << " milliseconds.";
honghaiz90099622015-07-13 12:19:33 -0700353 }
Peter Thatcher04ac81f2015-09-21 11:48:28 -0700354
Honghai Zhang049fbb12016-03-07 11:13:07 -0800355 if (config.receiving_timeout >= 0 &&
356 config_.receiving_timeout != config.receiving_timeout) {
357 config_.receiving_timeout = config.receiving_timeout;
358 check_receiving_interval_ =
359 std::max(MIN_CHECK_RECEIVING_INTERVAL, config_.receiving_timeout / 10);
Honghai Zhang381b4212015-12-04 12:24:03 -0800360
361 for (Connection* connection : connections_) {
Honghai Zhang049fbb12016-03-07 11:13:07 -0800362 connection->set_receiving_timeout(config_.receiving_timeout);
Honghai Zhang381b4212015-12-04 12:24:03 -0800363 }
Honghai Zhang049fbb12016-03-07 11:13:07 -0800364 LOG(LS_INFO) << "Set ICE receiving timeout to " << config_.receiving_timeout
365 << " milliseconds";
Peter Thatcher04ac81f2015-09-21 11:48:28 -0700366 }
guoweis36f01372016-03-02 18:02:40 -0800367
368 config_.prioritize_most_likely_candidate_pairs =
369 config.prioritize_most_likely_candidate_pairs;
370 LOG(LS_INFO) << "Set ping most likely connection to "
371 << config_.prioritize_most_likely_candidate_pairs;
372
zhihuang435264a2016-06-21 11:28:38 -0700373 if (config.stable_writable_connection_ping_interval >= 0 &&
374 config_.stable_writable_connection_ping_interval !=
375 config.stable_writable_connection_ping_interval) {
376 config_.stable_writable_connection_ping_interval =
377 config.stable_writable_connection_ping_interval;
378 LOG(LS_INFO) << "Set stable_writable_connection_ping_interval to "
379 << config_.stable_writable_connection_ping_interval;
guoweis36f01372016-03-02 18:02:40 -0800380 }
deadbeef14f97f52016-06-22 17:14:15 -0700381
382 if (config.presume_writable_when_fully_relayed !=
383 config_.presume_writable_when_fully_relayed) {
384 if (!connections_.empty()) {
385 LOG(LS_ERROR) << "Trying to change 'presume writable' "
386 << "while connections already exist!";
387 } else {
388 config_.presume_writable_when_fully_relayed =
389 config.presume_writable_when_fully_relayed;
390 LOG(LS_INFO) << "Set presume writable when fully relayed to "
391 << config_.presume_writable_when_fully_relayed;
392 }
393 }
Honghai Zhang5622c5e2016-07-01 13:59:29 -0700394
395 if (config.regather_on_failed_networks_interval) {
396 config_.regather_on_failed_networks_interval =
397 config.regather_on_failed_networks_interval;
398 LOG(LS_INFO) << "Set regather_on_failed_networks_interval to "
399 << *config_.regather_on_failed_networks_interval;
400 }
honghaiz9ad0db52016-07-14 19:30:28 -0700401 if (config.receiving_switching_delay) {
402 config_.receiving_switching_delay = config.receiving_switching_delay;
403 LOG(LS_INFO) << "Set receiving_switching_delay to"
404 << *config_.receiving_switching_delay;
405 }
guoweis36f01372016-03-02 18:02:40 -0800406}
407
408const IceConfig& P2PTransportChannel::config() const {
409 return config_;
Peter Thatcher54360512015-07-08 11:08:35 -0700410}
411
Taylor Brandstetterb825aee2016-06-29 13:07:16 -0700412void P2PTransportChannel::MaybeStartGathering() {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000413 if (ice_ufrag_.empty() || ice_pwd_.empty()) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000414 return;
415 }
deadbeefcbecd352015-09-23 11:50:27 -0700416 // Start gathering if we never started before, or if an ICE restart occurred.
417 if (allocator_sessions_.empty() ||
418 IceCredentialsChanged(allocator_sessions_.back()->ice_ufrag(),
419 allocator_sessions_.back()->ice_pwd(), ice_ufrag_,
420 ice_pwd_)) {
421 if (gathering_state_ != kIceGatheringGathering) {
422 gathering_state_ = kIceGatheringGathering;
423 SignalGatheringState(this);
424 }
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700425 // Time for a new allocator.
426 std::unique_ptr<PortAllocatorSession> pooled_session =
427 allocator_->TakePooledSession(transport_name(), component(), ice_ufrag_,
428 ice_pwd_);
429 if (pooled_session) {
430 AddAllocatorSession(std::move(pooled_session));
431 PortAllocatorSession* raw_pooled_session =
432 allocator_sessions_.back().get();
433 // Process the pooled session's existing candidates/ports, if they exist.
434 OnCandidatesReady(raw_pooled_session,
435 raw_pooled_session->ReadyCandidates());
436 for (PortInterface* port : allocator_sessions_.back()->ReadyPorts()) {
437 OnPortReady(raw_pooled_session, port);
438 }
439 if (allocator_sessions_.back()->CandidatesAllocationDone()) {
440 OnCandidatesAllocationDone(raw_pooled_session);
441 }
442 } else {
443 AddAllocatorSession(allocator_->CreateSession(
444 SessionId(), transport_name(), component(), ice_ufrag_, ice_pwd_));
445 allocator_sessions_.back()->StartGettingPorts();
446 }
deadbeefcbecd352015-09-23 11:50:27 -0700447 }
448}
449
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000450// A new port is available, attempt to make connections for it
451void P2PTransportChannel::OnPortReady(PortAllocatorSession *session,
452 PortInterface* port) {
453 ASSERT(worker_thread_ == rtc::Thread::Current());
454
455 // Set in-effect options on the new port
456 for (OptionMap::const_iterator it = options_.begin();
457 it != options_.end();
458 ++it) {
459 int val = port->SetOption(it->first, it->second);
460 if (val < 0) {
461 LOG_J(LS_WARNING, port) << "SetOption(" << it->first
462 << ", " << it->second
463 << ") failed: " << port->GetError();
464 }
465 }
466
467 // Remember the ports and candidates, and signal that candidates are ready.
468 // The session will handle this, and send an initiate/accept/modify message
469 // if one is pending.
470
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000471 port->SetIceRole(ice_role_);
472 port->SetIceTiebreaker(tiebreaker_);
473 ports_.push_back(port);
474 port->SignalUnknownAddress.connect(
475 this, &P2PTransportChannel::OnUnknownAddress);
476 port->SignalDestroyed.connect(this, &P2PTransportChannel::OnPortDestroyed);
Honghai Zhang5622c5e2016-07-01 13:59:29 -0700477
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000478 port->SignalRoleConflict.connect(
479 this, &P2PTransportChannel::OnRoleConflict);
stefanc1aeaf02015-10-15 07:26:07 -0700480 port->SignalSentPacket.connect(this, &P2PTransportChannel::OnSentPacket);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000481
482 // Attempt to create a connection from this new port to all of the remote
483 // candidates that we were given so far.
484
485 std::vector<RemoteCandidate>::iterator iter;
486 for (iter = remote_candidates_.begin(); iter != remote_candidates_.end();
487 ++iter) {
Peter Thatcher04ac81f2015-09-21 11:48:28 -0700488 CreateConnection(port, *iter, iter->origin_port());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000489 }
490
Taylor Brandstetterb825aee2016-06-29 13:07:16 -0700491 SortConnectionsAndUpdateState();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000492}
493
494// A new candidate is available, let listeners know
495void P2PTransportChannel::OnCandidatesReady(
deadbeefcbecd352015-09-23 11:50:27 -0700496 PortAllocatorSession* session,
497 const std::vector<Candidate>& candidates) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000498 ASSERT(worker_thread_ == rtc::Thread::Current());
499 for (size_t i = 0; i < candidates.size(); ++i) {
deadbeefcbecd352015-09-23 11:50:27 -0700500 SignalCandidateGathered(this, candidates[i]);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000501 }
502}
503
504void P2PTransportChannel::OnCandidatesAllocationDone(
505 PortAllocatorSession* session) {
506 ASSERT(worker_thread_ == rtc::Thread::Current());
deadbeefcbecd352015-09-23 11:50:27 -0700507 gathering_state_ = kIceGatheringComplete;
508 LOG(LS_INFO) << "P2PTransportChannel: " << transport_name() << ", component "
509 << component() << " gathering complete";
510 SignalGatheringState(this);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000511}
512
513// Handle stun packets
514void P2PTransportChannel::OnUnknownAddress(
515 PortInterface* port,
516 const rtc::SocketAddress& address, ProtocolType proto,
517 IceMessage* stun_msg, const std::string &remote_username,
518 bool port_muxed) {
519 ASSERT(worker_thread_ == rtc::Thread::Current());
520
521 // Port has received a valid stun packet from an address that no Connection
522 // is currently available for. See if we already have a candidate with the
523 // address. If it isn't we need to create new candidate for it.
524
Taylor Brandstetterf7c15a92016-06-22 13:13:55 -0700525 const Candidate* candidate = nullptr;
526 for (const Candidate& c : remote_candidates_) {
527 if (c.username() == remote_username && c.address() == address &&
528 c.protocol() == ProtoToString(proto)) {
529 candidate = &c;
530 break;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000531 }
532 }
533
honghaiz112fe432015-12-30 13:32:47 -0800534 uint32_t remote_generation = 0;
Taylor Brandstetterf7c15a92016-06-22 13:13:55 -0700535 std::string remote_password;
jiayl@webrtc.orgdacdd942015-01-23 17:33:34 +0000536 // The STUN binding request may arrive after setRemoteDescription and before
537 // adding remote candidate, so we need to set the password to the shared
Taylor Brandstetterf7c15a92016-06-22 13:13:55 -0700538 // password and set the generation if the user name matches.
539 const IceParameters* ice_param =
540 FindRemoteIceFromUfrag(remote_username, &remote_generation);
541 // Note: if not found, the remote_generation will still be 0.
542 if (ice_param != nullptr) {
543 remote_password = ice_param->pwd;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000544 }
545
Guo-wei Shieh372f2fc2015-06-12 10:12:46 -0700546 Candidate remote_candidate;
547 bool remote_candidate_is_new = (candidate == nullptr);
548 if (!remote_candidate_is_new) {
549 remote_candidate = *candidate;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000550 } else {
551 // Create a new candidate with this address.
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700552 // The priority of the candidate is set to the PRIORITY attribute
553 // from the request.
554 const StunUInt32Attribute* priority_attr =
555 stun_msg->GetUInt32(STUN_ATTR_PRIORITY);
556 if (!priority_attr) {
557 LOG(LS_WARNING) << "P2PTransportChannel::OnUnknownAddress - "
558 << "No STUN_ATTR_PRIORITY found in the "
559 << "stun request message";
deadbeefcbecd352015-09-23 11:50:27 -0700560 port->SendBindingErrorResponse(stun_msg, address, STUN_ERROR_BAD_REQUEST,
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700561 STUN_ERROR_REASON_BAD_REQUEST);
562 return;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000563 }
honghaize1a0c942016-02-16 14:54:56 -0800564 int remote_candidate_priority = priority_attr->value();
565
honghaiza0c44ea2016-03-23 16:07:48 -0700566 uint16_t network_id = 0;
567 uint16_t network_cost = 0;
568 const StunUInt32Attribute* network_attr =
569 stun_msg->GetUInt32(STUN_ATTR_NETWORK_INFO);
570 if (network_attr) {
571 uint32_t network_info = network_attr->value();
572 network_id = static_cast<uint16_t>(network_info >> 16);
573 network_cost = static_cast<uint16_t>(network_info);
574 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000575
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700576 // RFC 5245
577 // If the source transport address of the request does not match any
578 // existing remote candidates, it represents a new peer reflexive remote
579 // candidate.
honghaiza0c44ea2016-03-23 16:07:48 -0700580 remote_candidate = Candidate(
581 component(), ProtoToString(proto), address, remote_candidate_priority,
582 remote_username, remote_password, PRFLX_PORT_TYPE, remote_generation,
583 "", network_id, network_cost);
guoweis@webrtc.org61c12472015-01-15 06:53:07 +0000584
585 // From RFC 5245, section-7.2.1.3:
586 // The foundation of the candidate is set to an arbitrary value, different
587 // from the foundation for all other remote candidates.
Guo-wei Shieh372f2fc2015-06-12 10:12:46 -0700588 remote_candidate.set_foundation(
Peter Boström0c4e06b2015-10-07 12:23:21 +0200589 rtc::ToString<uint32_t>(rtc::ComputeCrc32(remote_candidate.id())));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000590 }
591
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700592 // RFC5245, the agent constructs a pair whose local candidate is equal to
593 // the transport address on which the STUN request was received, and a
594 // remote candidate equal to the source transport address where the
595 // request came from.
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000596
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700597 // There shouldn't be an existing connection with this remote address.
598 // When ports are muxed, this channel might get multiple unknown address
599 // signals. In that case if the connection is already exists, we should
600 // simply ignore the signal otherwise send server error.
601 if (port->GetConnection(remote_candidate.address())) {
602 if (port_muxed) {
603 LOG(LS_INFO) << "Connection already exists for peer reflexive "
604 << "candidate: " << remote_candidate.ToString();
605 return;
606 } else {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000607 ASSERT(false);
608 port->SendBindingErrorResponse(stun_msg, address,
609 STUN_ERROR_SERVER_ERROR,
610 STUN_ERROR_REASON_SERVER_ERROR);
611 return;
612 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000613 }
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700614
guoweis36f01372016-03-02 18:02:40 -0800615 Connection* connection =
616 port->CreateConnection(remote_candidate, PortInterface::ORIGIN_THIS_PORT);
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700617 if (!connection) {
618 ASSERT(false);
deadbeefcbecd352015-09-23 11:50:27 -0700619 port->SendBindingErrorResponse(stun_msg, address, STUN_ERROR_SERVER_ERROR,
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700620 STUN_ERROR_REASON_SERVER_ERROR);
621 return;
622 }
623
624 LOG(LS_INFO) << "Adding connection from "
625 << (remote_candidate_is_new ? "peer reflexive" : "resurrected")
626 << " candidate: " << remote_candidate.ToString();
627 AddConnection(connection);
honghaiz9b5ee9c2015-11-11 13:19:17 -0800628 connection->HandleBindingRequest(stun_msg);
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700629
630 // Update the list of connections since we just added another. We do this
631 // after sending the response since it could (in principle) delete the
632 // connection in question.
Taylor Brandstetterb825aee2016-06-29 13:07:16 -0700633 SortConnectionsAndUpdateState();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000634}
635
636void P2PTransportChannel::OnRoleConflict(PortInterface* port) {
637 SignalRoleConflict(this); // STUN ping will be sent when SetRole is called
638 // from Transport.
639}
640
honghaiz112fe432015-12-30 13:32:47 -0800641const IceParameters* P2PTransportChannel::FindRemoteIceFromUfrag(
642 const std::string& ufrag,
643 uint32_t* generation) {
644 const auto& params = remote_ice_parameters_;
645 auto it = std::find_if(
646 params.rbegin(), params.rend(),
647 [ufrag](const IceParameters& param) { return param.ufrag == ufrag; });
648 if (it == params.rend()) {
649 // Not found.
650 return nullptr;
651 }
652 *generation = params.rend() - it - 1;
653 return &(*it);
654}
655
honghaiz5a3acd82015-08-20 15:53:17 -0700656void P2PTransportChannel::OnNominated(Connection* conn) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000657 ASSERT(worker_thread_ == rtc::Thread::Current());
658 ASSERT(ice_role_ == ICEROLE_CONTROLLED);
Peter Thatcher42af6ca2015-05-15 12:23:27 -0700659
Honghai Zhang572b0942016-06-23 12:26:57 -0700660 if (selected_connection_ == conn) {
661 return;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000662 }
Honghai Zhang572b0942016-06-23 12:26:57 -0700663
honghaiz9ad0db52016-07-14 19:30:28 -0700664 if (MaybeSwitchSelectedConnection(conn,
665 "nomination on the controlled side")) {
666 // Now that we have selected a connection, it is time to prune other
667 // connections and update the read/write state of the channel.
668 RequestSortAndStateUpdate();
669 } else {
Honghai Zhang572b0942016-06-23 12:26:57 -0700670 LOG(LS_INFO)
671 << "Not switching the selected connection on controlled side yet: "
672 << conn->ToString();
Honghai Zhang572b0942016-06-23 12:26:57 -0700673 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000674}
675
deadbeefcbecd352015-09-23 11:50:27 -0700676void P2PTransportChannel::AddRemoteCandidate(const Candidate& candidate) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000677 ASSERT(worker_thread_ == rtc::Thread::Current());
678
honghaiza54a0802015-12-16 18:37:23 -0800679 uint32_t generation = GetRemoteCandidateGeneration(candidate);
680 // If a remote candidate with a previous generation arrives, drop it.
681 if (generation < remote_ice_generation()) {
682 LOG(LS_WARNING) << "Dropping a remote candidate because its ufrag "
683 << candidate.username()
684 << " indicates it was for a previous generation.";
honghaiz503726c2015-07-31 12:37:38 -0700685 return;
686 }
687
honghaiza54a0802015-12-16 18:37:23 -0800688 Candidate new_remote_candidate(candidate);
689 new_remote_candidate.set_generation(generation);
690 // ICE candidates don't need to have username and password set, but
691 // the code below this (specifically, ConnectionRequest::Prepare in
692 // port.cc) uses the remote candidates's username. So, we set it
693 // here.
694 if (remote_ice()) {
695 if (candidate.username().empty()) {
696 new_remote_candidate.set_username(remote_ice()->ufrag);
697 }
698 if (new_remote_candidate.username() == remote_ice()->ufrag) {
699 if (candidate.password().empty()) {
700 new_remote_candidate.set_password(remote_ice()->pwd);
701 }
702 } else {
703 // The candidate belongs to the next generation. Its pwd will be set
704 // when the new remote ICE credentials arrive.
705 LOG(LS_WARNING) << "A remote candidate arrives with an unknown ufrag: "
706 << candidate.username();
707 }
708 }
709
deadbeef0af180b2016-06-21 13:15:32 -0700710 // If this candidate matches what was thought to be a peer reflexive
711 // candidate, we need to update the candidate priority/etc.
712 for (Connection* conn : connections_) {
713 conn->MaybeUpdatePeerReflexiveCandidate(new_remote_candidate);
714 }
715
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000716 // Create connections to this remote candidate.
honghaiza54a0802015-12-16 18:37:23 -0800717 CreateConnections(new_remote_candidate, NULL);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000718
719 // Resort the connections list, which may have new elements.
Taylor Brandstetterb825aee2016-06-29 13:07:16 -0700720 SortConnectionsAndUpdateState();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000721}
722
Honghai Zhang7fb69db2016-03-14 11:59:18 -0700723void P2PTransportChannel::RemoveRemoteCandidate(
724 const Candidate& cand_to_remove) {
725 auto iter =
726 std::remove_if(remote_candidates_.begin(), remote_candidates_.end(),
727 [cand_to_remove](const Candidate& candidate) {
728 return cand_to_remove.MatchesForRemoval(candidate);
729 });
730 if (iter != remote_candidates_.end()) {
731 LOG(LS_VERBOSE) << "Removed remote candidate " << cand_to_remove.ToString();
732 remote_candidates_.erase(iter, remote_candidates_.end());
733 }
734}
735
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000736// Creates connections from all of the ports that we care about to the given
737// remote candidate. The return value is true if we created a connection from
738// the origin port.
739bool P2PTransportChannel::CreateConnections(const Candidate& remote_candidate,
Peter Thatcher04ac81f2015-09-21 11:48:28 -0700740 PortInterface* origin_port) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000741 ASSERT(worker_thread_ == rtc::Thread::Current());
742
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000743 // If we've already seen the new remote candidate (in the current candidate
744 // generation), then we shouldn't try creating connections for it.
745 // We either already have a connection for it, or we previously created one
746 // and then later pruned it. If we don't return, the channel will again
747 // re-create any connections that were previously pruned, which will then
748 // immediately be re-pruned, churning the network for no purpose.
749 // This only applies to candidates received over signaling (i.e. origin_port
750 // is NULL).
honghaiza54a0802015-12-16 18:37:23 -0800751 if (!origin_port && IsDuplicateRemoteCandidate(remote_candidate)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000752 // return true to indicate success, without creating any new connections.
753 return true;
754 }
755
756 // Add a new connection for this candidate to every port that allows such a
757 // connection (i.e., if they have compatible protocols) and that does not
758 // already have a connection to an equivalent candidate. We must be careful
759 // to make sure that the origin port is included, even if it was pruned,
760 // since that may be the only port that can create this connection.
761 bool created = false;
762 std::vector<PortInterface *>::reverse_iterator it;
763 for (it = ports_.rbegin(); it != ports_.rend(); ++it) {
honghaiza54a0802015-12-16 18:37:23 -0800764 if (CreateConnection(*it, remote_candidate, origin_port)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000765 if (*it == origin_port)
766 created = true;
767 }
768 }
769
770 if ((origin_port != NULL) &&
771 std::find(ports_.begin(), ports_.end(), origin_port) == ports_.end()) {
honghaiza54a0802015-12-16 18:37:23 -0800772 if (CreateConnection(origin_port, remote_candidate, origin_port))
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000773 created = true;
774 }
775
776 // Remember this remote candidate so that we can add it to future ports.
honghaiza54a0802015-12-16 18:37:23 -0800777 RememberRemoteCandidate(remote_candidate, origin_port);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000778
779 return created;
780}
781
782// Setup a connection object for the local and remote candidate combination.
783// And then listen to connection object for changes.
784bool P2PTransportChannel::CreateConnection(PortInterface* port,
785 const Candidate& remote_candidate,
Peter Thatcher04ac81f2015-09-21 11:48:28 -0700786 PortInterface* origin_port) {
Honghai Zhangf9945b22015-12-15 12:20:13 -0800787 if (!port->SupportsProtocol(remote_candidate.protocol())) {
788 return false;
789 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000790 // Look for an existing connection with this remote address. If one is not
honghaiz36f50e82016-06-01 15:57:03 -0700791 // found or it is found but the existing remote candidate has an older
792 // generation, then we can create a new connection for this address.
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000793 Connection* connection = port->GetConnection(remote_candidate.address());
honghaiz36f50e82016-06-01 15:57:03 -0700794 if (connection == nullptr ||
795 connection->remote_candidate().generation() <
796 remote_candidate.generation()) {
797 // Don't create a connection if this is a candidate we received in a
798 // message and we are not allowed to make outgoing connections.
799 PortInterface::CandidateOrigin origin = GetOrigin(port, origin_port);
800 if (origin == PortInterface::ORIGIN_MESSAGE && incoming_only_) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000801 return false;
802 }
honghaiz36f50e82016-06-01 15:57:03 -0700803 Connection* connection = port->CreateConnection(remote_candidate, origin);
804 if (!connection) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000805 return false;
honghaiz36f50e82016-06-01 15:57:03 -0700806 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000807 AddConnection(connection);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000808 LOG_J(LS_INFO, this) << "Created connection with origin=" << origin << ", ("
809 << connections_.size() << " total)";
honghaiz36f50e82016-06-01 15:57:03 -0700810 return true;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000811 }
812
honghaiz36f50e82016-06-01 15:57:03 -0700813 // No new connection was created.
honghaiz36f50e82016-06-01 15:57:03 -0700814 // It is not legal to try to change any of the parameters of an existing
815 // connection; however, the other side can send a duplicate candidate.
816 if (!remote_candidate.IsEquivalent(connection->remote_candidate())) {
817 LOG(INFO) << "Attempt to change a remote candidate."
818 << " Existing remote candidate: "
819 << connection->remote_candidate().ToString()
820 << "New remote candidate: " << remote_candidate.ToString();
821 }
822 return false;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000823}
824
guoweis36f01372016-03-02 18:02:40 -0800825bool P2PTransportChannel::FindConnection(Connection* connection) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000826 std::vector<Connection*>::const_iterator citer =
827 std::find(connections_.begin(), connections_.end(), connection);
828 return citer != connections_.end();
829}
830
Peter Boström0c4e06b2015-10-07 12:23:21 +0200831uint32_t P2PTransportChannel::GetRemoteCandidateGeneration(
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000832 const Candidate& candidate) {
honghaiz112fe432015-12-30 13:32:47 -0800833 // If the candidate has a ufrag, use it to find the generation.
honghaiza54a0802015-12-16 18:37:23 -0800834 if (!candidate.username().empty()) {
honghaiz112fe432015-12-30 13:32:47 -0800835 uint32_t generation = 0;
836 if (!FindRemoteIceFromUfrag(candidate.username(), &generation)) {
837 // If the ufrag is not found, assume the next/future generation.
838 generation = static_cast<uint32_t>(remote_ice_parameters_.size());
honghaiza54a0802015-12-16 18:37:23 -0800839 }
honghaiz112fe432015-12-30 13:32:47 -0800840 return generation;
honghaiza54a0802015-12-16 18:37:23 -0800841 }
842 // If candidate generation is set, use that.
843 if (candidate.generation() > 0) {
844 return candidate.generation();
845 }
846 // Otherwise, assume the generation from remote ice parameters.
847 return remote_ice_generation();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000848}
849
850// Check if remote candidate is already cached.
851bool P2PTransportChannel::IsDuplicateRemoteCandidate(
852 const Candidate& candidate) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200853 for (size_t i = 0; i < remote_candidates_.size(); ++i) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000854 if (remote_candidates_[i].IsEquivalent(candidate)) {
855 return true;
856 }
857 }
858 return false;
859}
860
861// Maintain our remote candidate list, adding this new remote one.
862void P2PTransportChannel::RememberRemoteCandidate(
863 const Candidate& remote_candidate, PortInterface* origin_port) {
864 // Remove any candidates whose generation is older than this one. The
865 // presence of a new generation indicates that the old ones are not useful.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200866 size_t i = 0;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000867 while (i < remote_candidates_.size()) {
868 if (remote_candidates_[i].generation() < remote_candidate.generation()) {
869 LOG(INFO) << "Pruning candidate from old generation: "
870 << remote_candidates_[i].address().ToSensitiveString();
871 remote_candidates_.erase(remote_candidates_.begin() + i);
872 } else {
873 i += 1;
874 }
875 }
876
877 // Make sure this candidate is not a duplicate.
878 if (IsDuplicateRemoteCandidate(remote_candidate)) {
879 LOG(INFO) << "Duplicate candidate: " << remote_candidate.ToString();
880 return;
881 }
882
883 // Try this candidate for all future ports.
884 remote_candidates_.push_back(RemoteCandidate(remote_candidate, origin_port));
885}
886
887// Set options on ourselves is simply setting options on all of our available
888// port objects.
889int P2PTransportChannel::SetOption(rtc::Socket::Option opt, int value) {
pthatcher@webrtc.org877ac762015-02-04 22:03:09 +0000890 ASSERT(worker_thread_ == rtc::Thread::Current());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000891 OptionMap::iterator it = options_.find(opt);
892 if (it == options_.end()) {
893 options_.insert(std::make_pair(opt, value));
894 } else if (it->second == value) {
895 return 0;
896 } else {
897 it->second = value;
898 }
899
deadbeefdfc42442016-06-21 14:19:48 -0700900 for (PortInterface* port : ports_) {
901 int val = port->SetOption(opt, value);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000902 if (val < 0) {
903 // Because this also occurs deferred, probably no point in reporting an
904 // error
deadbeefdfc42442016-06-21 14:19:48 -0700905 LOG(WARNING) << "SetOption(" << opt << ", " << value
906 << ") failed: " << port->GetError();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000907 }
908 }
909 return 0;
910}
911
pthatcher@webrtc.org877ac762015-02-04 22:03:09 +0000912bool P2PTransportChannel::GetOption(rtc::Socket::Option opt, int* value) {
913 ASSERT(worker_thread_ == rtc::Thread::Current());
914
915 const auto& found = options_.find(opt);
916 if (found == options_.end()) {
917 return false;
918 }
919 *value = found->second;
920 return true;
921}
922
Honghai Zhang572b0942016-06-23 12:26:57 -0700923// Send data to the other side, using our selected connection.
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000924int P2PTransportChannel::SendPacket(const char *data, size_t len,
925 const rtc::PacketOptions& options,
926 int flags) {
927 ASSERT(worker_thread_ == rtc::Thread::Current());
928 if (flags != 0) {
929 error_ = EINVAL;
930 return -1;
931 }
skvladc309e0e2016-07-28 17:15:20 -0700932 // If we don't think the connection is working yet, return ENOTCONN
Taylor Brandstetter6bb1ef22016-06-27 18:09:03 -0700933 // instead of sending a packet that will probably be dropped.
934 if (!ReadyToSend()) {
skvladc309e0e2016-07-28 17:15:20 -0700935 error_ = ENOTCONN;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000936 return -1;
937 }
938
Honghai Zhang52dce732016-03-31 12:37:31 -0700939 last_sent_packet_id_ = options.packet_id;
Honghai Zhang572b0942016-06-23 12:26:57 -0700940 int sent = selected_connection_->Send(data, len, options);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000941 if (sent <= 0) {
942 ASSERT(sent < 0);
Honghai Zhang572b0942016-06-23 12:26:57 -0700943 error_ = selected_connection_->GetError();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000944 }
945 return sent;
946}
947
948bool P2PTransportChannel::GetStats(ConnectionInfos *infos) {
949 ASSERT(worker_thread_ == rtc::Thread::Current());
950 // Gather connection infos.
951 infos->clear();
952
Honghai Zhang2b342bf2015-09-30 09:51:58 -0700953 for (Connection* connection : connections_) {
zhihuang5ecf16c2016-06-01 17:09:15 -0700954 ConnectionInfo info = connection->stats();
Honghai Zhang572b0942016-06-23 12:26:57 -0700955 info.best_connection = (selected_connection_ == connection);
Peter Thatcher04ac81f2015-09-21 11:48:28 -0700956 info.receiving = connection->receiving();
zhihuang5ecf16c2016-06-01 17:09:15 -0700957 info.writable = (connection->write_state() == Connection::STATE_WRITABLE);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000958 info.timeout =
959 (connection->write_state() == Connection::STATE_WRITE_TIMEOUT);
960 info.new_connection = !connection->reported();
961 connection->set_reported(true);
962 info.rtt = connection->rtt();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000963 info.local_candidate = connection->local_candidate();
964 info.remote_candidate = connection->remote_candidate();
965 info.key = connection;
966 infos->push_back(info);
967 }
968
969 return true;
970}
971
972rtc::DiffServCodePoint P2PTransportChannel::DefaultDscpValue() const {
973 OptionMap::const_iterator it = options_.find(rtc::Socket::OPT_DSCP);
974 if (it == options_.end()) {
975 return rtc::DSCP_NO_CHANGE;
976 }
977 return static_cast<rtc::DiffServCodePoint> (it->second);
978}
979
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000980// Monitor connection states.
981void P2PTransportChannel::UpdateConnectionStates() {
nisse1bffc1d2016-05-02 08:18:55 -0700982 int64_t now = rtc::TimeMillis();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000983
984 // We need to copy the list of connections since some may delete themselves
985 // when we call UpdateState.
Taylor Brandstetterb825aee2016-06-29 13:07:16 -0700986 for (Connection* c : connections_) {
987 c->UpdateState(now);
988 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000989}
990
991// Prepare for best candidate sorting.
Taylor Brandstetterb825aee2016-06-29 13:07:16 -0700992void P2PTransportChannel::RequestSortAndStateUpdate() {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000993 if (!sort_dirty_) {
Taylor Brandstetterb825aee2016-06-29 13:07:16 -0700994 worker_thread_->Post(RTC_FROM_HERE, this, MSG_SORT_AND_UPDATE_STATE);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000995 sort_dirty_ = true;
996 }
997}
998
Taylor Brandstetterb825aee2016-06-29 13:07:16 -0700999void P2PTransportChannel::MaybeStartPinging() {
1000 if (started_pinging_) {
1001 return;
1002 }
1003
1004 int64_t now = rtc::TimeMillis();
1005 if (std::any_of(
1006 connections_.begin(), connections_.end(),
1007 [this, now](const Connection* c) { return IsPingable(c, now); })) {
1008 LOG_J(LS_INFO, this) << "Have a pingable connection for the first time; "
1009 << "starting to ping.";
1010 thread()->Post(RTC_FROM_HERE, this, MSG_CHECK_AND_PING);
Honghai Zhang5622c5e2016-07-01 13:59:29 -07001011 thread()->PostDelayed(RTC_FROM_HERE,
1012 *config_.regather_on_failed_networks_interval, this,
1013 MSG_REGATHER_ON_FAILED_NETWORKS);
Taylor Brandstetterb825aee2016-06-29 13:07:16 -07001014 started_pinging_ = true;
1015 }
1016}
1017
deadbeef14f97f52016-06-22 17:14:15 -07001018// Compare two connections based on their writing, receiving, and connected
1019// states.
honghaiz9ad0db52016-07-14 19:30:28 -07001020int P2PTransportChannel::CompareConnectionStates(
1021 const Connection* a,
1022 const Connection* b,
1023 rtc::Optional<int64_t> receiving_unchanged_threshold,
1024 bool* missed_receiving_unchanged_threshold) const {
deadbeef14f97f52016-06-22 17:14:15 -07001025 // First, prefer a connection that's writable or presumed writable over
1026 // one that's not writable.
1027 bool a_writable = a->writable() || PresumedWritable(a);
1028 bool b_writable = b->writable() || PresumedWritable(b);
1029 if (a_writable && !b_writable) {
1030 return a_is_better;
1031 }
1032 if (!a_writable && b_writable) {
1033 return b_is_better;
1034 }
1035
1036 // Sort based on write-state. Better states have lower values.
1037 if (a->write_state() < b->write_state()) {
1038 return a_is_better;
1039 }
1040 if (b->write_state() < a->write_state()) {
1041 return b_is_better;
1042 }
1043
1044 // We prefer a receiving connection to a non-receiving, higher-priority
1045 // connection when sorting connections and choosing which connection to
1046 // switch to.
1047 if (a->receiving() && !b->receiving()) {
1048 return a_is_better;
1049 }
1050 if (!a->receiving() && b->receiving()) {
honghaiz9ad0db52016-07-14 19:30:28 -07001051 if (!receiving_unchanged_threshold ||
1052 (a->receiving_unchanged_since() <= *receiving_unchanged_threshold &&
1053 b->receiving_unchanged_since() <= *receiving_unchanged_threshold)) {
1054 return b_is_better;
1055 }
1056 *missed_receiving_unchanged_threshold = true;
deadbeef14f97f52016-06-22 17:14:15 -07001057 }
1058
1059 // WARNING: Some complexity here about TCP reconnecting.
1060 // When a TCP connection fails because of a TCP socket disconnecting, the
1061 // active side of the connection will attempt to reconnect for 5 seconds while
1062 // pretending to be writable (the connection is not set to the unwritable
1063 // state). On the passive side, the connection also remains writable even
1064 // though it is disconnected, and a new connection is created when the active
1065 // side connects. At that point, there are two TCP connections on the passive
1066 // side: 1. the old, disconnected one that is pretending to be writable, and
1067 // 2. the new, connected one that is maybe not yet writable. For purposes of
Honghai Zhang572b0942016-06-23 12:26:57 -07001068 // pruning, pinging, and selecting the selected connection, we want to treat
1069 // the new connection as "better" than the old one. We could add a method
1070 // called something like Connection::ImReallyBadEvenThoughImWritable, but that
1071 // is equivalent to the existing Connection::connected(), which we already
1072 // have. So, in code throughout this file, we'll check whether the connection
1073 // is connected() or not, and if it is not, treat it as "worse" than a
1074 // connected one, even though it's writable. In the code below, we're doing
1075 // so to make sure we treat a new writable connection as better than an old
1076 // disconnected connection.
deadbeef14f97f52016-06-22 17:14:15 -07001077
1078 // In the case where we reconnect TCP connections, the original best
1079 // connection is disconnected without changing to WRITE_TIMEOUT. In this case,
1080 // the new connection, when it becomes writable, should have higher priority.
1081 if (a->write_state() == Connection::STATE_WRITABLE &&
1082 b->write_state() == Connection::STATE_WRITABLE) {
1083 if (a->connected() && !b->connected()) {
1084 return a_is_better;
1085 }
1086 if (!a->connected() && b->connected()) {
1087 return b_is_better;
1088 }
1089 }
1090 return 0;
1091}
1092
1093// Compares two connections based only on the candidate and network information.
1094// Returns positive if |a| is better than |b|.
1095int P2PTransportChannel::CompareConnectionCandidates(
1096 const Connection* a,
1097 const Connection* b) const {
1098 // Prefer lower network cost.
1099 uint32_t a_cost = a->ComputeNetworkCost();
1100 uint32_t b_cost = b->ComputeNetworkCost();
1101 // Smaller cost is better.
1102 if (a_cost < b_cost) {
Honghai Zhang572b0942016-06-23 12:26:57 -07001103 return a_is_better;
deadbeef14f97f52016-06-22 17:14:15 -07001104 }
1105 if (a_cost > b_cost) {
Honghai Zhang572b0942016-06-23 12:26:57 -07001106 return b_is_better;
deadbeef14f97f52016-06-22 17:14:15 -07001107 }
1108
1109 // Compare connection priority. Lower values get sorted last.
1110 if (a->priority() > b->priority()) {
Honghai Zhang572b0942016-06-23 12:26:57 -07001111 return a_is_better;
deadbeef14f97f52016-06-22 17:14:15 -07001112 }
1113 if (a->priority() < b->priority()) {
Honghai Zhang572b0942016-06-23 12:26:57 -07001114 return b_is_better;
deadbeef14f97f52016-06-22 17:14:15 -07001115 }
1116
1117 // If we're still tied at this point, prefer a younger generation.
1118 // (Younger generation means a larger generation number).
1119 return (a->remote_candidate().generation() + a->port()->generation()) -
1120 (b->remote_candidate().generation() + b->port()->generation());
1121}
1122
honghaiz9ad0db52016-07-14 19:30:28 -07001123int P2PTransportChannel::CompareConnections(
1124 const Connection* a,
1125 const Connection* b,
1126 rtc::Optional<int64_t> receiving_unchanged_threshold,
1127 bool* missed_receiving_unchanged_threshold) const {
Honghai Zhang572b0942016-06-23 12:26:57 -07001128 RTC_CHECK(a != nullptr);
1129 RTC_CHECK(b != nullptr);
1130
1131 // We prefer to switch to a writable and receiving connection over a
1132 // non-writable or non-receiving connection, even if the latter has
1133 // been nominated by the controlling side.
honghaiz9ad0db52016-07-14 19:30:28 -07001134 int state_cmp = CompareConnectionStates(a, b, receiving_unchanged_threshold,
1135 missed_receiving_unchanged_threshold);
deadbeef14f97f52016-06-22 17:14:15 -07001136 if (state_cmp != 0) {
1137 return state_cmp;
1138 }
deadbeef14f97f52016-06-22 17:14:15 -07001139
Honghai Zhang572b0942016-06-23 12:26:57 -07001140 if (ice_role_ == ICEROLE_CONTROLLED) {
1141 // Compare the connections based on the nomination states and the last data
1142 // received time if this is on the controlled side.
1143 if (a->nominated() && !b->nominated()) {
1144 return a_is_better;
1145 }
1146 if (!a->nominated() && b->nominated()) {
1147 return b_is_better;
1148 }
1149
1150 if (a->last_data_received() > b->last_data_received()) {
1151 return a_is_better;
1152 }
1153 if (a->last_data_received() < b->last_data_received()) {
1154 return b_is_better;
1155 }
1156 }
1157
1158 // Compare the network cost and priority.
1159 return CompareConnectionCandidates(a, b);
deadbeef14f97f52016-06-22 17:14:15 -07001160}
1161
Honghai Zhang572b0942016-06-23 12:26:57 -07001162bool P2PTransportChannel::PresumedWritable(const Connection* conn) const {
deadbeef14f97f52016-06-22 17:14:15 -07001163 return (conn->write_state() == Connection::STATE_WRITE_INIT &&
1164 config_.presume_writable_when_fully_relayed &&
1165 conn->local_candidate().type() == RELAY_PORT_TYPE &&
1166 (conn->remote_candidate().type() == RELAY_PORT_TYPE ||
1167 conn->remote_candidate().type() == PRFLX_PORT_TYPE));
1168}
1169
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001170// Sort the available connections to find the best one. We also monitor
1171// the number of available connections and the current state.
Taylor Brandstetterb825aee2016-06-29 13:07:16 -07001172void P2PTransportChannel::SortConnectionsAndUpdateState() {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001173 ASSERT(worker_thread_ == rtc::Thread::Current());
1174
1175 // Make sure the connection states are up-to-date since this affects how they
1176 // will be sorted.
1177 UpdateConnectionStates();
1178
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001179 // Any changes after this point will require a re-sort.
1180 sort_dirty_ = false;
1181
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001182 // Find the best alternative connection by sorting. It is important to note
1183 // that amongst equal preference, writable connections, this will choose the
1184 // one whose estimated latency is lowest. So it is the only one that we
1185 // need to consider switching to.
deadbeef14f97f52016-06-22 17:14:15 -07001186 std::stable_sort(connections_.begin(), connections_.end(),
1187 [this](const Connection* a, const Connection* b) {
honghaiz9ad0db52016-07-14 19:30:28 -07001188 int cmp = CompareConnections(
1189 a, b, rtc::Optional<int64_t>(), nullptr);
Honghai Zhang572b0942016-06-23 12:26:57 -07001190 if (cmp != 0) {
1191 return cmp > 0;
1192 }
Honghai Zhang572b0942016-06-23 12:26:57 -07001193 // Otherwise, sort based on latency estimate.
1194 return a->rtt() < b->rtt();
deadbeef14f97f52016-06-22 17:14:15 -07001195 });
Honghai Zhang572b0942016-06-23 12:26:57 -07001196
honghaiza58ea782015-09-24 08:13:36 -07001197 LOG(LS_VERBOSE) << "Sorting " << connections_.size()
1198 << " available connections:";
Peter Boström0c4e06b2015-10-07 12:23:21 +02001199 for (size_t i = 0; i < connections_.size(); ++i) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001200 LOG(LS_VERBOSE) << connections_[i]->ToString();
1201 }
1202
honghaiz5a3acd82015-08-20 15:53:17 -07001203 Connection* top_connection =
1204 (connections_.size() > 0) ? connections_[0] : nullptr;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001205
Honghai Zhang572b0942016-06-23 12:26:57 -07001206 // If necessary, switch to the new choice. Note that |top_connection| doesn't
1207 // have to be writable to become the selected connection although it will
1208 // have higher priority if it is writable.
honghaiz9ad0db52016-07-14 19:30:28 -07001209 MaybeSwitchSelectedConnection(top_connection, "sorting");
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001210
Honghai Zhang572b0942016-06-23 12:26:57 -07001211 // The controlled side can prune only if the selected connection has been
1212 // nominated because otherwise it may prune the connection that will be
1213 // selected by the controlling side.
1214 // TODO(honghaiz): This is not enough to prevent a connection from being
1215 // pruned too early because with aggressive nomination, the controlling side
1216 // will nominate every connection until it becomes writable.
1217 if (ice_role_ == ICEROLE_CONTROLLING ||
1218 (selected_connection_ && selected_connection_->nominated())) {
honghaiz5a3acd82015-08-20 15:53:17 -07001219 PruneConnections();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001220 }
1221
1222 // Check if all connections are timedout.
1223 bool all_connections_timedout = true;
Peter Boström0c4e06b2015-10-07 12:23:21 +02001224 for (size_t i = 0; i < connections_.size(); ++i) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001225 if (connections_[i]->write_state() != Connection::STATE_WRITE_TIMEOUT) {
1226 all_connections_timedout = false;
1227 break;
1228 }
1229 }
1230
1231 // Now update the writable state of the channel with the information we have
1232 // so far.
honghaiza8e9f5e2015-11-11 16:15:07 -08001233 if (all_connections_timedout) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001234 HandleAllTimedOut();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001235 }
1236
Taylor Brandstetterb825aee2016-06-29 13:07:16 -07001237 // Update the state of this channel.
Honghai Zhang381b4212015-12-04 12:24:03 -08001238 UpdateState();
Taylor Brandstetterb825aee2016-06-29 13:07:16 -07001239
1240 // Also possibly start pinging.
1241 // We could start pinging if:
1242 // * The first connection was created.
1243 // * ICE credentials were provided.
1244 // * A TCP connection became connected.
1245 MaybeStartPinging();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001246}
1247
honghaiz5a3acd82015-08-20 15:53:17 -07001248void P2PTransportChannel::PruneConnections() {
1249 // We can prune any connection for which there is a connected, writable
1250 // connection on the same network with better or equal priority. We leave
1251 // those with better priority just in case they become writable later (at
Honghai Zhang572b0942016-06-23 12:26:57 -07001252 // which point, we would prune out the current selected connection). We leave
honghaiz5a3acd82015-08-20 15:53:17 -07001253 // connections on other networks because they may not be using the same
1254 // resources and they may represent very distinct paths over which we can
honghaiz89374372015-09-24 13:14:47 -07001255 // switch. If the |premier| connection is not connected, we may be
honghaiz5a3acd82015-08-20 15:53:17 -07001256 // reconnecting a TCP connection and temporarily do not prune connections in
Honghai Zhang572b0942016-06-23 12:26:57 -07001257 // this network. See the big comment in CompareConnectionStates.
honghaiz5a3acd82015-08-20 15:53:17 -07001258
1259 // Get a list of the networks that we are using.
1260 std::set<rtc::Network*> networks;
1261 for (const Connection* conn : connections_) {
1262 networks.insert(conn->port()->Network());
1263 }
1264 for (rtc::Network* network : networks) {
honghaiz89374372015-09-24 13:14:47 -07001265 Connection* premier = GetBestConnectionOnNetwork(network);
Honghai Zhang572b0942016-06-23 12:26:57 -07001266 // Do not prune connections if the current selected connection is weak on
1267 // this network. Otherwise, it may delete connections prematurely.
Honghai Zhang2b342bf2015-09-30 09:51:58 -07001268 if (!premier || premier->weak()) {
honghaiz5a3acd82015-08-20 15:53:17 -07001269 continue;
1270 }
1271
1272 for (Connection* conn : connections_) {
honghaiz89374372015-09-24 13:14:47 -07001273 if ((conn != premier) && (conn->port()->Network() == network) &&
1274 (CompareConnectionCandidates(premier, conn) >= 0)) {
honghaiz5a3acd82015-08-20 15:53:17 -07001275 conn->Prune();
1276 }
1277 }
1278 }
1279}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001280
Honghai Zhang572b0942016-06-23 12:26:57 -07001281// Change the selected connection, and let listeners know.
1282void P2PTransportChannel::SwitchSelectedConnection(Connection* conn) {
1283 // Note: if conn is NULL, the previous |selected_connection_| has been
1284 // destroyed, so don't use it.
1285 Connection* old_selected_connection = selected_connection_;
1286 selected_connection_ = conn;
1287 if (selected_connection_) {
1288 if (old_selected_connection) {
1289 LOG_J(LS_INFO, this) << "Previous selected connection: "
1290 << old_selected_connection->ToString();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001291 }
Honghai Zhang572b0942016-06-23 12:26:57 -07001292 LOG_J(LS_INFO, this) << "New selected connection: "
1293 << selected_connection_->ToString();
1294 SignalRouteChange(this, selected_connection_->remote_candidate());
Honghai Zhang82f132c2016-03-30 12:55:14 -07001295 // This is a temporary, but safe fix to webrtc issue 5705.
skvladc309e0e2016-07-28 17:15:20 -07001296 // TODO(honghaiz): Make all ENOTCONN error routed through the transport
Honghai Zhang82f132c2016-03-30 12:55:14 -07001297 // channel so that it knows whether the media channel is allowed to
1298 // send; then it will only signal ready-to-send if the media channel
1299 // has been disallowed to send.
Honghai Zhang572b0942016-06-23 12:26:57 -07001300 if (selected_connection_->writable() ||
1301 PresumedWritable(selected_connection_)) {
Honghai Zhang82f132c2016-03-30 12:55:14 -07001302 SignalReadyToSend(this);
1303 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001304 } else {
Honghai Zhang572b0942016-06-23 12:26:57 -07001305 LOG_J(LS_INFO, this) << "No selected connection";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001306 }
Honghai Zhang572b0942016-06-23 12:26:57 -07001307 SignalSelectedCandidatePairChanged(this, selected_connection_,
Taylor Brandstetter6bb1ef22016-06-27 18:09:03 -07001308 last_sent_packet_id_, ReadyToSend());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001309}
1310
Honghai Zhang381b4212015-12-04 12:24:03 -08001311// Warning: UpdateState should eventually be called whenever a connection
1312// is added, deleted, or the write state of any connection changes so that the
1313// transport controller will get the up-to-date channel state. However it
1314// should not be called too often; in the case that multiple connection states
1315// change, it should be called after all the connection states have changed. For
Taylor Brandstetterb825aee2016-06-29 13:07:16 -07001316// example, we call this at the end of SortConnectionsAndUpdateState.
Honghai Zhang381b4212015-12-04 12:24:03 -08001317void P2PTransportChannel::UpdateState() {
Honghai Zhang1590c392016-05-24 13:15:02 -07001318 TransportChannelState state = ComputeState();
1319 if (state_ != state) {
1320 LOG_J(LS_INFO, this) << "Transport channel state changed from " << state_
1321 << " to " << state;
Taylor Brandstetter6aefc632016-05-26 16:08:23 -07001322 // Check that the requested transition is allowed. Note that
1323 // P2PTransportChannel does not (yet) implement a direct mapping of the ICE
1324 // states from the standard; the difference is covered by
1325 // TransportController and PeerConnection.
1326 switch (state_) {
1327 case STATE_INIT:
1328 // TODO(deadbeef): Once we implement end-of-candidates signaling,
1329 // we shouldn't go from INIT to COMPLETED.
1330 RTC_DCHECK(state == STATE_CONNECTING || state == STATE_COMPLETED);
1331 break;
1332 case STATE_CONNECTING:
1333 RTC_DCHECK(state == STATE_COMPLETED || state == STATE_FAILED);
1334 break;
1335 case STATE_COMPLETED:
1336 // TODO(deadbeef): Once we implement end-of-candidates signaling,
1337 // we shouldn't go from COMPLETED to CONNECTING.
1338 // Though we *can* go from COMPlETED to FAILED, if consent expires.
1339 RTC_DCHECK(state == STATE_CONNECTING || state == STATE_FAILED);
1340 break;
1341 case STATE_FAILED:
1342 // TODO(deadbeef): Once we implement end-of-candidates signaling,
1343 // we shouldn't go from FAILED to CONNECTING or COMPLETED.
1344 RTC_DCHECK(state == STATE_CONNECTING || state == STATE_COMPLETED);
1345 break;
1346 default:
1347 RTC_DCHECK(false);
1348 break;
1349 }
Honghai Zhang1590c392016-05-24 13:15:02 -07001350 state_ = state;
1351 SignalStateChanged(this);
1352 }
Honghai Zhang381b4212015-12-04 12:24:03 -08001353
Honghai Zhang572b0942016-06-23 12:26:57 -07001354 // If our selected connection is "presumed writable" (TURN-TURN with no
deadbeef14f97f52016-06-22 17:14:15 -07001355 // CreatePermission required), act like we're already writable to the upper
1356 // layers, so they can start media quicker.
Honghai Zhang572b0942016-06-23 12:26:57 -07001357 bool writable =
1358 selected_connection_ && (selected_connection_->writable() ||
1359 PresumedWritable(selected_connection_));
1360 set_writable(writable);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001361
honghaiza58ea782015-09-24 08:13:36 -07001362 bool receiving = false;
1363 for (const Connection* connection : connections_) {
1364 if (connection->receiving()) {
1365 receiving = true;
1366 break;
1367 }
1368 }
1369 set_receiving(receiving);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001370}
1371
honghaiz9b669572015-11-04 12:07:44 -08001372void P2PTransportChannel::MaybeStopPortAllocatorSessions() {
1373 if (!IsGettingPorts()) {
honghaiz98db68f2015-09-29 07:58:17 -07001374 return;
1375 }
1376
Taylor Brandstettera1c30352016-05-13 08:15:11 -07001377 for (const auto& session : allocator_sessions_) {
Honghai Zhang5622c5e2016-07-01 13:59:29 -07001378 if (session->IsStopped()) {
honghaiz98db68f2015-09-29 07:58:17 -07001379 continue;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001380 }
Honghai Zhang5622c5e2016-07-01 13:59:29 -07001381 // If gathering continually, keep the last session running so that
1382 // it can gather candidates if the networks change.
1383 if (config_.gather_continually() && session == allocator_sessions_.back()) {
honghaiz98db68f2015-09-29 07:58:17 -07001384 session->ClearGettingPorts();
Honghai Zhang5622c5e2016-07-01 13:59:29 -07001385 } else {
1386 session->StopGettingPorts();
honghaiz98db68f2015-09-29 07:58:17 -07001387 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001388 }
honghaiz9b669572015-11-04 12:07:44 -08001389}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001390
honghaiz77d0d6e2015-10-27 11:34:45 -07001391// If all connections timed out, delete them all.
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001392void P2PTransportChannel::HandleAllTimedOut() {
honghaiz77d0d6e2015-10-27 11:34:45 -07001393 for (Connection* connection : connections_) {
1394 connection->Destroy();
1395 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001396}
1397
Honghai Zhang2b342bf2015-09-30 09:51:58 -07001398bool P2PTransportChannel::weak() const {
Honghai Zhang572b0942016-06-23 12:26:57 -07001399 return !selected_connection_ || selected_connection_->weak();
honghaiza58ea782015-09-24 08:13:36 -07001400}
1401
Taylor Brandstetter6bb1ef22016-06-27 18:09:03 -07001402bool P2PTransportChannel::ReadyToSend() const {
1403 // Note that we allow sending on an unreliable connection, because it's
1404 // possible that it became unreliable simply due to bad chance.
1405 // So this shouldn't prevent attempting to send media.
1406 return selected_connection_ != nullptr &&
1407 (selected_connection_->writable() ||
1408 PresumedWritable(selected_connection_) ||
1409 selected_connection_->write_state() ==
1410 Connection::STATE_WRITE_UNRELIABLE);
1411}
1412
Honghai Zhang572b0942016-06-23 12:26:57 -07001413// If we have a selected connection, return it, otherwise return top one in the
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001414// list (later we will mark it best).
1415Connection* P2PTransportChannel::GetBestConnectionOnNetwork(
guoweis@webrtc.org8c9ff202014-12-04 07:56:02 +00001416 rtc::Network* network) const {
Honghai Zhang572b0942016-06-23 12:26:57 -07001417 // If the selected connection is on this network, then it wins.
1418 if (selected_connection_ &&
1419 (selected_connection_->port()->Network() == network)) {
1420 return selected_connection_;
1421 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001422
1423 // Otherwise, we return the top-most in sorted order.
Peter Boström0c4e06b2015-10-07 12:23:21 +02001424 for (size_t i = 0; i < connections_.size(); ++i) {
Honghai Zhang572b0942016-06-23 12:26:57 -07001425 if (connections_[i]->port()->Network() == network) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001426 return connections_[i];
Honghai Zhang572b0942016-06-23 12:26:57 -07001427 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001428 }
1429
1430 return NULL;
1431}
1432
1433// Handle any queued up requests
1434void P2PTransportChannel::OnMessage(rtc::Message *pmsg) {
1435 switch (pmsg->message_id) {
Taylor Brandstetterb825aee2016-06-29 13:07:16 -07001436 case MSG_SORT_AND_UPDATE_STATE:
1437 SortConnectionsAndUpdateState();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001438 break;
honghaiza58ea782015-09-24 08:13:36 -07001439 case MSG_CHECK_AND_PING:
1440 OnCheckAndPing();
Peter Thatcher54360512015-07-08 11:08:35 -07001441 break;
Honghai Zhang5622c5e2016-07-01 13:59:29 -07001442 case MSG_REGATHER_ON_FAILED_NETWORKS:
1443 OnRegatherOnFailedNetworks();
1444 break;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001445 default:
1446 ASSERT(false);
1447 break;
1448 }
1449}
1450
honghaiza58ea782015-09-24 08:13:36 -07001451// Handle queued up check-and-ping request
1452void P2PTransportChannel::OnCheckAndPing() {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001453 // Make sure the states of the connections are up-to-date (since this affects
1454 // which ones are pingable).
1455 UpdateConnectionStates();
Honghai Zhang572b0942016-06-23 12:26:57 -07001456 // When the selected connection is not receiving or not writable, or any
1457 // active connection has not been pinged enough times, use the weak ping
1458 // interval.
honghaiz524ecc22016-05-25 12:48:31 -07001459 bool need_more_pings_at_weak_interval = std::any_of(
1460 connections_.begin(), connections_.end(), [](Connection* conn) {
1461 return conn->active() &&
1462 conn->num_pings_sent() < MIN_PINGS_AT_WEAK_PING_INTERVAL;
1463 });
1464 int ping_interval = (weak() || need_more_pings_at_weak_interval)
1465 ? weak_ping_interval_
1466 : STRONG_PING_INTERVAL;
nisse1bffc1d2016-05-02 08:18:55 -07001467 if (rtc::TimeMillis() >= last_ping_sent_ms_ + ping_interval) {
honghaiza58ea782015-09-24 08:13:36 -07001468 Connection* conn = FindNextPingableConnection();
1469 if (conn) {
1470 PingConnection(conn);
guoweis36f01372016-03-02 18:02:40 -08001471 MarkConnectionPinged(conn);
honghaiza58ea782015-09-24 08:13:36 -07001472 }
Peter Thatcher54360512015-07-08 11:08:35 -07001473 }
Honghai Zhang049fbb12016-03-07 11:13:07 -08001474 int delay = std::min(ping_interval, check_receiving_interval_);
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -07001475 thread()->PostDelayed(RTC_FROM_HERE, delay, this, MSG_CHECK_AND_PING);
Peter Thatcher54360512015-07-08 11:08:35 -07001476}
1477
Honghai Zhang381b4212015-12-04 12:24:03 -08001478// A connection is considered a backup connection if the channel state
Honghai Zhang572b0942016-06-23 12:26:57 -07001479// is completed, the connection is not the selected connection and it is active.
Taylor Brandstetterb825aee2016-06-29 13:07:16 -07001480bool P2PTransportChannel::IsBackupConnection(const Connection* conn) const {
Honghai Zhang572b0942016-06-23 12:26:57 -07001481 return state_ == STATE_COMPLETED && conn != selected_connection_ &&
Honghai Zhang381b4212015-12-04 12:24:03 -08001482 conn->active();
1483}
1484
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001485// Is the connection in a state for us to even consider pinging the other side?
Guo-wei Shiehbe508a12015-04-06 12:48:47 -07001486// We consider a connection pingable even if it's not connected because that's
1487// how a TCP connection is kicked into reconnecting on the active side.
Taylor Brandstetterb825aee2016-06-29 13:07:16 -07001488bool P2PTransportChannel::IsPingable(const Connection* conn,
1489 int64_t now) const {
Peter Thatcher7351f462015-04-02 16:39:16 -07001490 const Candidate& remote = conn->remote_candidate();
1491 // We should never get this far with an empty remote ufrag.
1492 ASSERT(!remote.username().empty());
1493 if (remote.username().empty() || remote.password().empty()) {
1494 // If we don't have an ICE ufrag and pwd, there's no way we can ping.
1495 return false;
1496 }
1497
honghaiz079a7a12016-06-22 16:26:29 -07001498 // A failed connection will not be pinged.
1499 if (conn->state() == Connection::STATE_FAILED) {
1500 return false;
1501 }
1502
Guo-wei Shiehbe508a12015-04-06 12:48:47 -07001503 // An never connected connection cannot be written to at all, so pinging is
1504 // out of the question. However, if it has become WRITABLE, it is in the
1505 // reconnecting state so ping is needed.
Peter Thatcher04ac81f2015-09-21 11:48:28 -07001506 if (!conn->connected() && !conn->writable()) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001507 return false;
Guo-wei Shiehbe508a12015-04-06 12:48:47 -07001508 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001509
Honghai Zhang381b4212015-12-04 12:24:03 -08001510 // If the channel is weakly connected, ping all connections.
1511 if (weak()) {
1512 return true;
1513 }
1514
1515 // Always ping active connections regardless whether the channel is completed
1516 // or not, but backup connections are pinged at a slower rate.
1517 if (IsBackupConnection(conn)) {
1518 return (now >= conn->last_ping_response_received() +
guoweis36f01372016-03-02 18:02:40 -08001519 config_.backup_connection_ping_interval);
Honghai Zhang381b4212015-12-04 12:24:03 -08001520 }
zhihuang435264a2016-06-21 11:28:38 -07001521 // Don't ping inactive non-backup connections.
1522 if (!conn->active()) {
1523 return false;
1524 }
1525
1526 // Do ping unwritable, active connections.
1527 if (!conn->writable()) {
1528 return true;
1529 }
1530
1531 // Ping writable, active connections if it's been long enough since the last
1532 // ping.
1533 int ping_interval = CalculateActiveWritablePingInterval(conn, now);
1534 return (now >= conn->last_ping_sent() + ping_interval);
1535}
1536
Honghai Zhang572b0942016-06-23 12:26:57 -07001537bool P2PTransportChannel::IsSelectedConnectionPingable(int64_t now) {
1538 if (!selected_connection_ || !selected_connection_->connected() ||
1539 !selected_connection_->writable()) {
zhihuang435264a2016-06-21 11:28:38 -07001540 return false;
1541 }
1542
Honghai Zhang572b0942016-06-23 12:26:57 -07001543 int interval = CalculateActiveWritablePingInterval(selected_connection_, now);
1544 return selected_connection_->last_ping_sent() + interval <= now;
zhihuang435264a2016-06-21 11:28:38 -07001545}
1546
Taylor Brandstetterb825aee2016-06-29 13:07:16 -07001547int P2PTransportChannel::CalculateActiveWritablePingInterval(
1548 const Connection* conn,
1549 int64_t now) const {
zhihuang435264a2016-06-21 11:28:38 -07001550 // Ping each connection at a higher rate at least
1551 // MIN_PINGS_AT_WEAK_PING_INTERVAL times.
1552 if (conn->num_pings_sent() < MIN_PINGS_AT_WEAK_PING_INTERVAL) {
1553 return weak_ping_interval_;
1554 }
1555
1556 int stable_interval = config_.stable_writable_connection_ping_interval;
1557 int stablizing_interval =
1558 std::min(stable_interval, STABILIZING_WRITABLE_CONNECTION_PING_INTERVAL);
1559
1560 return conn->stable(now) ? stable_interval : stablizing_interval;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001561}
1562
1563// Returns the next pingable connection to ping. This will be the oldest
Guo-wei Shiehbe508a12015-04-06 12:48:47 -07001564// pingable connection unless we have a connected, writable connection that is
zhihuang435264a2016-06-21 11:28:38 -07001565// past the writable ping interval. When reconnecting a TCP
Honghai Zhang572b0942016-06-23 12:26:57 -07001566// connection, the selected connection is disconnected, although still WRITABLE
Honghai Zhang049fbb12016-03-07 11:13:07 -08001567// while reconnecting. The newly created connection should be selected as the
1568// ping target to become writable instead. See the big comment in
Honghai Zhang572b0942016-06-23 12:26:57 -07001569// CompareConnectionStates.
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001570Connection* P2PTransportChannel::FindNextPingableConnection() {
nisse1bffc1d2016-05-02 08:18:55 -07001571 int64_t now = rtc::TimeMillis();
guoweis36f01372016-03-02 18:02:40 -08001572 Connection* conn_to_ping = nullptr;
Honghai Zhang572b0942016-06-23 12:26:57 -07001573 if (IsSelectedConnectionPingable(now)) {
1574 conn_to_ping = selected_connection_;
guoweis36f01372016-03-02 18:02:40 -08001575 } else {
1576 conn_to_ping = FindConnectionToPing(now);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001577 }
guoweis36f01372016-03-02 18:02:40 -08001578 return conn_to_ping;
1579}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001580
guoweis36f01372016-03-02 18:02:40 -08001581void P2PTransportChannel::MarkConnectionPinged(Connection* conn) {
1582 if (conn && pinged_connections_.insert(conn).second) {
1583 unpinged_connections_.erase(conn);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001584 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001585}
1586
1587// Apart from sending ping from |conn| this method also updates
1588// |use_candidate_attr| flag. The criteria to update this flag is
1589// explained below.
1590// Set USE-CANDIDATE if doing ICE AND this channel is in CONTROLLING AND
1591// a) Channel is in FULL ICE AND
Honghai Zhang572b0942016-06-23 12:26:57 -07001592// a.1) |conn| is the selected connection OR
1593// a.2) there is no selected connection OR
1594// a.3) the selected connection is unwritable OR
1595// a.4) |conn| has higher priority than selected_connection.
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001596// b) we're doing LITE ICE AND
Honghai Zhang572b0942016-06-23 12:26:57 -07001597// b.1) |conn| is the selected_connection AND
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001598// b.2) |conn| is writable.
1599void P2PTransportChannel::PingConnection(Connection* conn) {
1600 bool use_candidate = false;
Peter Thatcher7cbd1882015-09-17 18:54:52 -07001601 if (remote_ice_mode_ == ICEMODE_FULL && ice_role_ == ICEROLE_CONTROLLING) {
Honghai Zhang572b0942016-06-23 12:26:57 -07001602 use_candidate =
1603 (conn == selected_connection_) || (selected_connection_ == NULL) ||
1604 (!selected_connection_->writable()) ||
1605 (CompareConnectionCandidates(selected_connection_, conn) < 0);
1606 } else if (remote_ice_mode_ == ICEMODE_LITE && conn == selected_connection_) {
1607 use_candidate = selected_connection_->writable();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001608 }
1609 conn->set_use_candidate_attr(use_candidate);
nisse1bffc1d2016-05-02 08:18:55 -07001610 last_ping_sent_ms_ = rtc::TimeMillis();
honghaiza58ea782015-09-24 08:13:36 -07001611 conn->Ping(last_ping_sent_ms_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001612}
1613
1614// When a connection's state changes, we need to figure out who to use as
Honghai Zhang572b0942016-06-23 12:26:57 -07001615// the selected connection again. It could have become usable, or become
1616// unusable.
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001617void P2PTransportChannel::OnConnectionStateChange(Connection* connection) {
1618 ASSERT(worker_thread_ == rtc::Thread::Current());
1619
honghaiz9b669572015-11-04 12:07:44 -08001620 // May stop the allocator session when at least one connection becomes
Honghai Zhang5a246372016-05-02 17:28:35 -07001621 // strongly connected after starting to get ports and the local candidate of
1622 // the connection is at the latest generation. It is not enough to check
honghaiz9b669572015-11-04 12:07:44 -08001623 // that the connection becomes weakly connected because the connection may be
1624 // changing from (writable, receiving) to (writable, not receiving).
Honghai Zhang5a246372016-05-02 17:28:35 -07001625 bool strongly_connected = !connection->weak();
1626 bool latest_generation = connection->local_candidate().generation() >=
1627 allocator_session()->generation();
1628 if (strongly_connected && latest_generation) {
honghaiz9b669572015-11-04 12:07:44 -08001629 MaybeStopPortAllocatorSessions();
1630 }
1631
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001632 // We have to unroll the stack before doing this because we may be changing
1633 // the state of connections while sorting.
Taylor Brandstetterb825aee2016-06-29 13:07:16 -07001634 RequestSortAndStateUpdate();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001635}
1636
1637// When a connection is removed, edit it out, and then update our best
1638// connection.
1639void P2PTransportChannel::OnConnectionDestroyed(Connection* connection) {
1640 ASSERT(worker_thread_ == rtc::Thread::Current());
1641
Honghai Zhang572b0942016-06-23 12:26:57 -07001642 // Note: the previous selected_connection_ may be destroyed by now, so don't
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001643 // use it.
1644
1645 // Remove this connection from the list.
1646 std::vector<Connection*>::iterator iter =
1647 std::find(connections_.begin(), connections_.end(), connection);
1648 ASSERT(iter != connections_.end());
guoweis36f01372016-03-02 18:02:40 -08001649 pinged_connections_.erase(*iter);
1650 unpinged_connections_.erase(*iter);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001651 connections_.erase(iter);
1652
1653 LOG_J(LS_INFO, this) << "Removed connection ("
1654 << static_cast<int>(connections_.size()) << " remaining)";
1655
Honghai Zhang572b0942016-06-23 12:26:57 -07001656 // If this is currently the selected connection, then we need to pick a new
Taylor Brandstetterb825aee2016-06-29 13:07:16 -07001657 // one. The call to SortConnectionsAndUpdateState will pick a new one. It
1658 // looks at the current selected connection in order to avoid switching
1659 // between fairly similar ones. Since this connection is no longer an option,
1660 // we can just set selected to nullptr and re-choose a best assuming that
1661 // there was no selected connection.
Honghai Zhang572b0942016-06-23 12:26:57 -07001662 if (selected_connection_ == connection) {
honghaiz9ad0db52016-07-14 19:30:28 -07001663 LOG(LS_INFO) << "Selected connection destroyed. Will choose a new one.";
Honghai Zhang572b0942016-06-23 12:26:57 -07001664 SwitchSelectedConnection(nullptr);
Taylor Brandstetterb825aee2016-06-29 13:07:16 -07001665 RequestSortAndStateUpdate();
1666 } else {
1667 // If a non-selected connection was destroyed, we don't need to re-sort but
1668 // we do need to update state, because we could be switching to "failed" or
1669 // "completed".
1670 UpdateState();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001671 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001672}
1673
Honghai Zhang5622c5e2016-07-01 13:59:29 -07001674// When a port is destroyed, remove it from our list of ports to use for
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001675// connection attempts.
1676void P2PTransportChannel::OnPortDestroyed(PortInterface* port) {
1677 ASSERT(worker_thread_ == rtc::Thread::Current());
1678
deadbeefdfc42442016-06-21 14:19:48 -07001679 ports_.erase(std::remove(ports_.begin(), ports_.end(), port), ports_.end());
Honghai Zhang8eeecab2016-07-28 13:20:15 -07001680 pruned_ports_.erase(
1681 std::remove(pruned_ports_.begin(), pruned_ports_.end(), port),
1682 pruned_ports_.end());
Honghai Zhang5622c5e2016-07-01 13:59:29 -07001683 LOG(INFO) << "Removed port because it is destroyed: " << ports_.size()
1684 << " remaining";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001685}
1686
Honghai Zhang8eeecab2016-07-28 13:20:15 -07001687void P2PTransportChannel::OnPortsPruned(
Honghai Zhang5622c5e2016-07-01 13:59:29 -07001688 PortAllocatorSession* session,
1689 const std::vector<PortInterface*>& ports) {
1690 ASSERT(worker_thread_ == rtc::Thread::Current());
Honghai Zhang5622c5e2016-07-01 13:59:29 -07001691 for (PortInterface* port : ports) {
Honghai Zhanga74363c2016-07-28 18:06:15 -07001692 if (PrunePort(port)) {
Honghai Zhang5622c5e2016-07-01 13:59:29 -07001693 LOG(INFO) << "Removed port: " << port->ToString() << " " << ports_.size()
1694 << " remaining";
1695 }
1696 }
1697}
1698
1699void P2PTransportChannel::OnCandidatesRemoved(
1700 PortAllocatorSession* session,
1701 const std::vector<Candidate>& candidates) {
1702 ASSERT(worker_thread_ == rtc::Thread::Current());
1703 // Do not signal candidate removals if continual gathering is not enabled, or
1704 // if this is not the last session because an ICE restart would have signaled
1705 // the remote side to remove all candidates in previous sessions.
1706 if (!config_.gather_continually() || session != allocator_session()) {
honghaize3c6c822016-02-17 13:00:28 -08001707 return;
1708 }
Honghai Zhang5622c5e2016-07-01 13:59:29 -07001709
1710 std::vector<Candidate> candidates_to_remove;
1711 for (Candidate candidate : candidates) {
Honghai Zhang7fb69db2016-03-14 11:59:18 -07001712 candidate.set_transport_name(transport_name());
Honghai Zhang5622c5e2016-07-01 13:59:29 -07001713 candidates_to_remove.push_back(candidate);
Honghai Zhang7fb69db2016-03-14 11:59:18 -07001714 }
Honghai Zhang5622c5e2016-07-01 13:59:29 -07001715 SignalCandidatesRemoved(this, candidates_to_remove);
1716}
1717
1718void P2PTransportChannel::OnRegatherOnFailedNetworks() {
1719 // Only re-gather when the current session is in the CLEARED state (i.e., not
1720 // running or stopped). It is only possible to enter this state when we gather
1721 // continually, so there is an implicit check on continual gathering here.
1722 if (!allocator_sessions_.empty() && allocator_session()->IsCleared()) {
1723 allocator_session()->RegatherOnFailedNetworks();
1724 }
1725
1726 thread()->PostDelayed(RTC_FROM_HERE,
1727 *config_.regather_on_failed_networks_interval, this,
1728 MSG_REGATHER_ON_FAILED_NETWORKS);
honghaize3c6c822016-02-17 13:00:28 -08001729}
1730
Honghai Zhanga74363c2016-07-28 18:06:15 -07001731void P2PTransportChannel::PruneAllPorts() {
1732 pruned_ports_.insert(pruned_ports_.end(), ports_.begin(), ports_.end());
1733 ports_.clear();
1734}
1735
1736bool P2PTransportChannel::PrunePort(PortInterface* port) {
Honghai Zhangb9e7b4a2016-06-30 20:52:02 -07001737 auto it = std::find(ports_.begin(), ports_.end(), port);
1738 // Don't need to do anything if the port has been deleted from the port list.
1739 if (it == ports_.end()) {
1740 return false;
1741 }
1742 ports_.erase(it);
Honghai Zhang8eeecab2016-07-28 13:20:15 -07001743 pruned_ports_.push_back(port);
Honghai Zhangb9e7b4a2016-06-30 20:52:02 -07001744 return true;
1745}
1746
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001747// We data is available, let listeners know
deadbeefcbecd352015-09-23 11:50:27 -07001748void P2PTransportChannel::OnReadPacket(Connection* connection,
1749 const char* data,
1750 size_t len,
1751 const rtc::PacketTime& packet_time) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001752 ASSERT(worker_thread_ == rtc::Thread::Current());
1753
1754 // Do not deliver, if packet doesn't belong to the correct transport channel.
1755 if (!FindConnection(connection))
1756 return;
1757
1758 // Let the client know of an incoming packet
1759 SignalReadPacket(this, data, len, packet_time, 0);
honghaiz5a3acd82015-08-20 15:53:17 -07001760
1761 // May need to switch the sending connection based on the receiving media path
1762 // if this is the controlled side.
honghaiz9ad0db52016-07-14 19:30:28 -07001763 if (ice_role_ == ICEROLE_CONTROLLED) {
1764 MaybeSwitchSelectedConnection(connection, "data received");
honghaiz5a3acd82015-08-20 15:53:17 -07001765 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001766}
1767
Stefan Holmer55674ff2016-01-14 15:49:16 +01001768void P2PTransportChannel::OnSentPacket(const rtc::SentPacket& sent_packet) {
stefanc1aeaf02015-10-15 07:26:07 -07001769 ASSERT(worker_thread_ == rtc::Thread::Current());
1770
1771 SignalSentPacket(this, sent_packet);
1772}
1773
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001774void P2PTransportChannel::OnReadyToSend(Connection* connection) {
Honghai Zhang572b0942016-06-23 12:26:57 -07001775 if (connection == selected_connection_ && writable()) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001776 SignalReadyToSend(this);
1777 }
1778}
1779
guoweis36f01372016-03-02 18:02:40 -08001780// Find "triggered checks". We ping first those connections that have
1781// received a ping but have not sent a ping since receiving it
1782// (last_received_ping > last_sent_ping). But we shouldn't do
1783// triggered checks if the connection is already writable.
1784Connection* P2PTransportChannel::FindOldestConnectionNeedingTriggeredCheck(
honghaiz34b11eb2016-03-16 08:55:44 -07001785 int64_t now) {
guoweis36f01372016-03-02 18:02:40 -08001786 Connection* oldest_needing_triggered_check = nullptr;
1787 for (auto conn : connections_) {
1788 if (!IsPingable(conn, now)) {
1789 continue;
1790 }
1791 bool needs_triggered_check =
1792 (!conn->writable() &&
1793 conn->last_ping_received() > conn->last_ping_sent());
1794 if (needs_triggered_check &&
1795 (!oldest_needing_triggered_check ||
1796 (conn->last_ping_received() <
1797 oldest_needing_triggered_check->last_ping_received()))) {
1798 oldest_needing_triggered_check = conn;
1799 }
1800 }
1801
1802 if (oldest_needing_triggered_check) {
1803 LOG(LS_INFO) << "Selecting connection for triggered check: "
1804 << oldest_needing_triggered_check->ToString();
1805 }
1806 return oldest_needing_triggered_check;
1807}
1808
honghaiz34b11eb2016-03-16 08:55:44 -07001809Connection* P2PTransportChannel::FindConnectionToPing(int64_t now) {
guoweis36f01372016-03-02 18:02:40 -08001810 RTC_CHECK(connections_.size() ==
1811 pinged_connections_.size() + unpinged_connections_.size());
1812
1813 // If there is nothing pingable in the |unpinged_connections_|, copy
1814 // over from |pinged_connections_|. We do this here such that the
1815 // new connection will take precedence.
1816 if (std::find_if(unpinged_connections_.begin(), unpinged_connections_.end(),
1817 [this, now](Connection* conn) {
1818 return this->IsPingable(conn, now);
1819 }) == unpinged_connections_.end()) {
1820 unpinged_connections_.insert(pinged_connections_.begin(),
1821 pinged_connections_.end());
1822 pinged_connections_.clear();
1823 }
1824
1825 Connection* conn_to_ping = FindOldestConnectionNeedingTriggeredCheck(now);
1826 if (conn_to_ping) {
1827 return conn_to_ping;
1828 }
1829
1830 for (Connection* conn : unpinged_connections_) {
1831 if (!IsPingable(conn, now)) {
1832 continue;
1833 }
1834 if (!conn_to_ping ||
1835 SelectMostPingableConnection(conn_to_ping, conn) == conn) {
1836 conn_to_ping = conn;
1837 }
1838 }
1839 return conn_to_ping;
1840}
1841
1842Connection* P2PTransportChannel::MostLikelyToWork(Connection* conn1,
1843 Connection* conn2) {
1844 bool rr1 = IsRelayRelay(conn1);
1845 bool rr2 = IsRelayRelay(conn2);
1846 if (rr1 && !rr2) {
1847 return conn1;
1848 } else if (rr2 && !rr1) {
1849 return conn2;
1850 } else if (rr1 && rr2) {
1851 bool udp1 = IsUdp(conn1);
1852 bool udp2 = IsUdp(conn2);
1853 if (udp1 && !udp2) {
1854 return conn1;
1855 } else if (udp2 && udp1) {
1856 return conn2;
1857 }
1858 }
1859 return nullptr;
1860}
1861
1862Connection* P2PTransportChannel::LeastRecentlyPinged(Connection* conn1,
1863 Connection* conn2) {
1864 if (conn1->last_ping_sent() < conn2->last_ping_sent()) {
1865 return conn1;
1866 }
1867 if (conn1->last_ping_sent() > conn2->last_ping_sent()) {
1868 return conn2;
1869 }
1870 return nullptr;
1871}
1872
1873Connection* P2PTransportChannel::SelectMostPingableConnection(
1874 Connection* conn1,
1875 Connection* conn2) {
1876 RTC_DCHECK(conn1 != conn2);
1877 if (config_.prioritize_most_likely_candidate_pairs) {
1878 Connection* most_likely_to_work_conn = MostLikelyToWork(conn1, conn2);
1879 if (most_likely_to_work_conn) {
1880 return most_likely_to_work_conn;
1881 }
1882 }
1883
1884 Connection* least_recently_pinged_conn = LeastRecentlyPinged(conn1, conn2);
1885 if (least_recently_pinged_conn) {
1886 return least_recently_pinged_conn;
1887 }
1888
1889 // During the initial state when nothing has been pinged yet, return the first
1890 // one in the ordered |connections_|.
1891 return *(std::find_if(connections_.begin(), connections_.end(),
1892 [conn1, conn2](Connection* conn) {
1893 return conn == conn1 || conn == conn2;
1894 }));
1895}
1896
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001897} // namespace cricket