1 /*
2 * Copyright 2004 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "webrtc/p2p/base/p2ptransportchannel.h"
12
13 #include <algorithm>
14 #include <set>
15 #include "webrtc/p2p/base/common.h"
16 #include "webrtc/p2p/base/relayport.h" // For RELAY_PORT_TYPE.
17 #include "webrtc/p2p/base/stunport.h" // For STUN_PORT_TYPE.
18 #include "webrtc/base/common.h"
19 #include "webrtc/base/crc32.h"
20 #include "webrtc/base/logging.h"
21 #include "webrtc/base/stringencode.h"
22 #include "webrtc/system_wrappers/include/field_trial.h"
23
24 namespace {
25
26 // messages for queuing up work for ourselves
27 enum { MSG_SORT = 1, MSG_CHECK_AND_PING };
28
29 // The minimum improvement in RTT that justifies a switch.
30 static const double kMinImprovement = 10;
31
GetOrigin(cricket::PortInterface * port,cricket::PortInterface * origin_port)32 cricket::PortInterface::CandidateOrigin GetOrigin(cricket::PortInterface* port,
33 cricket::PortInterface* origin_port) {
34 if (!origin_port)
35 return cricket::PortInterface::ORIGIN_MESSAGE;
36 else if (port == origin_port)
37 return cricket::PortInterface::ORIGIN_THIS_PORT;
38 else
39 return cricket::PortInterface::ORIGIN_OTHER_PORT;
40 }
41
42 // Compares two connections based only on static information about them.
CompareConnectionCandidates(cricket::Connection * a,cricket::Connection * b)43 int CompareConnectionCandidates(cricket::Connection* a,
44 cricket::Connection* b) {
45 // Compare connection priority. Lower values get sorted last.
46 if (a->priority() > b->priority())
47 return 1;
48 if (a->priority() < b->priority())
49 return -1;
50
51 // If we're still tied at this point, prefer a younger generation.
52 return (a->remote_candidate().generation() + a->port()->generation()) -
53 (b->remote_candidate().generation() + b->port()->generation());
54 }
55
56 // Compare two connections based on their writing, receiving, and connected
57 // states.
CompareConnectionStates(cricket::Connection * a,cricket::Connection * b)58 int CompareConnectionStates(cricket::Connection* a, cricket::Connection* b) {
59 // Sort based on write-state. Better states have lower values.
60 if (a->write_state() < b->write_state())
61 return 1;
62 if (a->write_state() > b->write_state())
63 return -1;
64
65 // We prefer a receiving connection to a non-receiving, higher-priority
66 // connection when sorting connections and choosing which connection to
67 // switch to.
68 if (a->receiving() && !b->receiving())
69 return 1;
70 if (!a->receiving() && b->receiving())
71 return -1;
72
73 // WARNING: Some complexity here about TCP reconnecting.
74 // When a TCP connection fails because of a TCP socket disconnecting, the
75 // active side of the connection will attempt to reconnect for 5 seconds while
76 // pretending to be writable (the connection is not set to the unwritable
77 // state). On the passive side, the connection also remains writable even
78 // though it is disconnected, and a new connection is created when the active
79 // side connects. At that point, there are two TCP connections on the passive
80 // side: 1. the old, disconnected one that is pretending to be writable, and
81 // 2. the new, connected one that is maybe not yet writable. For purposes of
82 // pruning, pinging, and selecting the best connection, we want to treat the
83 // new connection as "better" than the old one. We could add a method called
84 // something like Connection::ImReallyBadEvenThoughImWritable, but that is
85 // equivalent to the existing Connection::connected(), which we already have.
86 // So, in code throughout this file, we'll check whether the connection is
87 // connected() or not, and if it is not, treat it as "worse" than a connected
88 // one, even though it's writable. In the code below, we're doing so to make
89 // sure we treat a new writable connection as better than an old disconnected
90 // connection.
91
92 // In the case where we reconnect TCP connections, the original best
93 // connection is disconnected without changing to WRITE_TIMEOUT. In this case,
94 // the new connection, when it becomes writable, should have higher priority.
95 if (a->write_state() == cricket::Connection::STATE_WRITABLE &&
96 b->write_state() == cricket::Connection::STATE_WRITABLE) {
97 if (a->connected() && !b->connected()) {
98 return 1;
99 }
100 if (!a->connected() && b->connected()) {
101 return -1;
102 }
103 }
104 return 0;
105 }
106
CompareConnections(cricket::Connection * a,cricket::Connection * b)107 int CompareConnections(cricket::Connection* a, cricket::Connection* b) {
108 int state_cmp = CompareConnectionStates(a, b);
109 if (state_cmp != 0) {
110 return state_cmp;
111 }
112 // Compare the candidate information.
113 return CompareConnectionCandidates(a, b);
114 }
115
116 // Wraps the comparison connection into a less than operator that puts higher
117 // priority writable connections first.
118 class ConnectionCompare {
119 public:
operator ()(const cricket::Connection * ca,const cricket::Connection * cb)120 bool operator()(const cricket::Connection *ca,
121 const cricket::Connection *cb) {
122 cricket::Connection* a = const_cast<cricket::Connection*>(ca);
123 cricket::Connection* b = const_cast<cricket::Connection*>(cb);
124
125 // Compare first on writability and static preferences.
126 int cmp = CompareConnections(a, b);
127 if (cmp > 0)
128 return true;
129 if (cmp < 0)
130 return false;
131
132 // Otherwise, sort based on latency estimate.
133 return a->rtt() < b->rtt();
134
135 // Should we bother checking for the last connection that last received
136 // data? It would help rendezvous on the connection that is also receiving
137 // packets.
138 //
139 // TODO: Yes we should definitely do this. The TCP protocol gains
140 // efficiency by being used bidirectionally, as opposed to two separate
141 // unidirectional streams. This test should probably occur before
142 // comparison of local prefs (assuming combined prefs are the same). We
143 // need to be careful though, not to bounce back and forth with both sides
144 // trying to rendevous with the other.
145 }
146 };
147
148 // Determines whether we should switch between two connections, based first on
149 // connection states, static preferences, and then (if those are equal) on
150 // latency estimates.
ShouldSwitch(cricket::Connection * a_conn,cricket::Connection * b_conn,cricket::IceRole ice_role)151 bool ShouldSwitch(cricket::Connection* a_conn,
152 cricket::Connection* b_conn,
153 cricket::IceRole ice_role) {
154 if (a_conn == b_conn)
155 return false;
156
157 if (!a_conn || !b_conn) // don't think the latter should happen
158 return true;
159
160 // We prefer to switch to a writable and receiving connection over a
161 // non-writable or non-receiving connection, even if the latter has
162 // been nominated by the controlling side.
163 int state_cmp = CompareConnectionStates(a_conn, b_conn);
164 if (state_cmp != 0) {
165 return state_cmp < 0;
166 }
167 if (ice_role == cricket::ICEROLE_CONTROLLED && a_conn->nominated()) {
168 LOG(LS_VERBOSE) << "Controlled side did not switch due to nominated status";
169 return false;
170 }
171
172 int prefs_cmp = CompareConnectionCandidates(a_conn, b_conn);
173 if (prefs_cmp != 0) {
174 return prefs_cmp < 0;
175 }
176
177 return b_conn->rtt() <= a_conn->rtt() + kMinImprovement;
178 }
179
180 } // unnamed namespace
181
182 namespace cricket {
183
184 // When the socket is unwritable, we will use 10 Kbps (ignoring IP+UDP headers)
185 // for pinging. When the socket is writable, we will use only 1 Kbps because
186 // we don't want to degrade the quality on a modem. These numbers should work
187 // well on a 28.8K modem, which is the slowest connection on which the voice
188 // quality is reasonable at all.
189 static const uint32_t PING_PACKET_SIZE = 60 * 8;
190 // TODO(honghaiz): Change the word DELAY to INTERVAL whenever appropriate.
191 // STRONG_PING_DELAY (480ms) is applied when the best connection is both
192 // writable and receiving.
193 static const uint32_t STRONG_PING_DELAY = 1000 * PING_PACKET_SIZE / 1000;
194 // WEAK_PING_DELAY (48ms) is applied when the best connection is either not
195 // writable or not receiving.
196 const uint32_t WEAK_PING_DELAY = 1000 * PING_PACKET_SIZE / 10000;
197
198 // If the current best connection is both writable and receiving, then we will
199 // also try hard to make sure it is pinged at this rate (a little less than
200 // 2 * STRONG_PING_DELAY).
201 static const uint32_t MAX_CURRENT_STRONG_DELAY = 900;
202
203 static const int MIN_CHECK_RECEIVING_DELAY = 50; // ms
204
P2PTransportChannel(const std::string & transport_name,int component,P2PTransport * transport,PortAllocator * allocator)205 P2PTransportChannel::P2PTransportChannel(const std::string& transport_name,
206 int component,
207 P2PTransport* transport,
208 PortAllocator* allocator)
209 : TransportChannelImpl(transport_name, component),
210 transport_(transport),
211 allocator_(allocator),
212 worker_thread_(rtc::Thread::Current()),
213 incoming_only_(false),
214 error_(0),
215 best_connection_(NULL),
216 pending_best_connection_(NULL),
217 sort_dirty_(false),
218 remote_ice_mode_(ICEMODE_FULL),
219 ice_role_(ICEROLE_UNKNOWN),
220 tiebreaker_(0),
221 gathering_state_(kIceGatheringNew),
222 check_receiving_delay_(MIN_CHECK_RECEIVING_DELAY * 5),
223 receiving_timeout_(MIN_CHECK_RECEIVING_DELAY * 50),
224 backup_connection_ping_interval_(0) {
225 uint32_t weak_ping_delay = ::strtoul(
226 webrtc::field_trial::FindFullName("WebRTC-StunInterPacketDelay").c_str(),
227 nullptr, 10);
228 if (weak_ping_delay) {
229 weak_ping_delay_ = weak_ping_delay;
230 }
231 }
232
~P2PTransportChannel()233 P2PTransportChannel::~P2PTransportChannel() {
234 ASSERT(worker_thread_ == rtc::Thread::Current());
235
236 for (size_t i = 0; i < allocator_sessions_.size(); ++i)
237 delete allocator_sessions_[i];
238 }
239
240 // Add the allocator session to our list so that we know which sessions
241 // are still active.
AddAllocatorSession(PortAllocatorSession * session)242 void P2PTransportChannel::AddAllocatorSession(PortAllocatorSession* session) {
243 ASSERT(worker_thread_ == rtc::Thread::Current());
244
245 session->set_generation(static_cast<uint32_t>(allocator_sessions_.size()));
246 allocator_sessions_.push_back(session);
247
248 // We now only want to apply new candidates that we receive to the ports
249 // created by this new session because these are replacing those of the
250 // previous sessions.
251 ports_.clear();
252
253 session->SignalPortReady.connect(this, &P2PTransportChannel::OnPortReady);
254 session->SignalCandidatesReady.connect(
255 this, &P2PTransportChannel::OnCandidatesReady);
256 session->SignalCandidatesAllocationDone.connect(
257 this, &P2PTransportChannel::OnCandidatesAllocationDone);
258 session->StartGettingPorts();
259 }
260
AddConnection(Connection * connection)261 void P2PTransportChannel::AddConnection(Connection* connection) {
262 connections_.push_back(connection);
263 connection->set_remote_ice_mode(remote_ice_mode_);
264 connection->set_receiving_timeout(receiving_timeout_);
265 connection->SignalReadPacket.connect(
266 this, &P2PTransportChannel::OnReadPacket);
267 connection->SignalReadyToSend.connect(
268 this, &P2PTransportChannel::OnReadyToSend);
269 connection->SignalStateChange.connect(
270 this, &P2PTransportChannel::OnConnectionStateChange);
271 connection->SignalDestroyed.connect(
272 this, &P2PTransportChannel::OnConnectionDestroyed);
273 connection->SignalNominated.connect(this, &P2PTransportChannel::OnNominated);
274 had_connection_ = true;
275 }
276
SetIceRole(IceRole ice_role)277 void P2PTransportChannel::SetIceRole(IceRole ice_role) {
278 ASSERT(worker_thread_ == rtc::Thread::Current());
279 if (ice_role_ != ice_role) {
280 ice_role_ = ice_role;
281 for (std::vector<PortInterface *>::iterator it = ports_.begin();
282 it != ports_.end(); ++it) {
283 (*it)->SetIceRole(ice_role);
284 }
285 }
286 }
287
SetIceTiebreaker(uint64_t tiebreaker)288 void P2PTransportChannel::SetIceTiebreaker(uint64_t tiebreaker) {
289 ASSERT(worker_thread_ == rtc::Thread::Current());
290 if (!ports_.empty()) {
291 LOG(LS_ERROR)
292 << "Attempt to change tiebreaker after Port has been allocated.";
293 return;
294 }
295
296 tiebreaker_ = tiebreaker;
297 }
298
GetState() const299 TransportChannelState P2PTransportChannel::GetState() const {
300 return state_;
301 }
302
303 // A channel is considered ICE completed once there is at most one active
304 // connection per network and at least one active connection.
ComputeState() const305 TransportChannelState P2PTransportChannel::ComputeState() const {
306 if (!had_connection_) {
307 return TransportChannelState::STATE_INIT;
308 }
309
310 std::vector<Connection*> active_connections;
311 for (Connection* connection : connections_) {
312 if (connection->active()) {
313 active_connections.push_back(connection);
314 }
315 }
316 if (active_connections.empty()) {
317 return TransportChannelState::STATE_FAILED;
318 }
319
320 std::set<rtc::Network*> networks;
321 for (Connection* connection : active_connections) {
322 rtc::Network* network = connection->port()->Network();
323 if (networks.find(network) == networks.end()) {
324 networks.insert(network);
325 } else {
326 LOG_J(LS_VERBOSE, this) << "Ice not completed yet for this channel as "
327 << network->ToString()
328 << " has more than 1 connection.";
329 return TransportChannelState::STATE_CONNECTING;
330 }
331 }
332
333 LOG_J(LS_VERBOSE, this) << "Ice is completed for this channel.";
334 return TransportChannelState::STATE_COMPLETED;
335 }
336
SetIceCredentials(const std::string & ice_ufrag,const std::string & ice_pwd)337 void P2PTransportChannel::SetIceCredentials(const std::string& ice_ufrag,
338 const std::string& ice_pwd) {
339 ASSERT(worker_thread_ == rtc::Thread::Current());
340 ice_ufrag_ = ice_ufrag;
341 ice_pwd_ = ice_pwd;
342 // Note: Candidate gathering will restart when MaybeStartGathering is next
343 // called.
344 }
345
SetRemoteIceCredentials(const std::string & ice_ufrag,const std::string & ice_pwd)346 void P2PTransportChannel::SetRemoteIceCredentials(const std::string& ice_ufrag,
347 const std::string& ice_pwd) {
348 ASSERT(worker_thread_ == rtc::Thread::Current());
349 IceParameters* current_ice = remote_ice();
350 IceParameters new_ice(ice_ufrag, ice_pwd);
351 if (!current_ice || *current_ice != new_ice) {
352 // Keep the ICE credentials so that newer connections
353 // are prioritized over the older ones.
354 remote_ice_parameters_.push_back(new_ice);
355 }
356
357 // Update the pwd of remote candidate if needed.
358 for (RemoteCandidate& candidate : remote_candidates_) {
359 if (candidate.username() == ice_ufrag && candidate.password().empty()) {
360 candidate.set_password(ice_pwd);
361 }
362 }
363 // We need to update the credentials for any peer reflexive candidates.
364 for (Connection* conn : connections_) {
365 conn->MaybeSetRemoteIceCredentials(ice_ufrag, ice_pwd);
366 }
367 }
368
SetRemoteIceMode(IceMode mode)369 void P2PTransportChannel::SetRemoteIceMode(IceMode mode) {
370 remote_ice_mode_ = mode;
371 }
372
SetIceConfig(const IceConfig & config)373 void P2PTransportChannel::SetIceConfig(const IceConfig& config) {
374 gather_continually_ = config.gather_continually;
375 LOG(LS_INFO) << "Set gather_continually to " << gather_continually_;
376
377 if (config.backup_connection_ping_interval >= 0 &&
378 backup_connection_ping_interval_ !=
379 config.backup_connection_ping_interval) {
380 backup_connection_ping_interval_ = config.backup_connection_ping_interval;
381 LOG(LS_INFO) << "Set backup connection ping interval to "
382 << backup_connection_ping_interval_ << " milliseconds.";
383 }
384
385 if (config.receiving_timeout_ms >= 0 &&
386 receiving_timeout_ != config.receiving_timeout_ms) {
387 receiving_timeout_ = config.receiving_timeout_ms;
388 check_receiving_delay_ =
389 std::max(MIN_CHECK_RECEIVING_DELAY, receiving_timeout_ / 10);
390
391 for (Connection* connection : connections_) {
392 connection->set_receiving_timeout(receiving_timeout_);
393 }
394 LOG(LS_INFO) << "Set ICE receiving timeout to " << receiving_timeout_
395 << " milliseconds";
396 }
397 }
398
399 // Go into the state of processing candidates, and running in general
Connect()400 void P2PTransportChannel::Connect() {
401 ASSERT(worker_thread_ == rtc::Thread::Current());
402 if (ice_ufrag_.empty() || ice_pwd_.empty()) {
403 ASSERT(false);
404 LOG(LS_ERROR) << "P2PTransportChannel::Connect: The ice_ufrag_ and the "
405 << "ice_pwd_ are not set.";
406 return;
407 }
408
409 // Start checking and pinging as the ports come in.
410 thread()->Post(this, MSG_CHECK_AND_PING);
411 }
412
MaybeStartGathering()413 void P2PTransportChannel::MaybeStartGathering() {
414 // Start gathering if we never started before, or if an ICE restart occurred.
415 if (allocator_sessions_.empty() ||
416 IceCredentialsChanged(allocator_sessions_.back()->ice_ufrag(),
417 allocator_sessions_.back()->ice_pwd(), ice_ufrag_,
418 ice_pwd_)) {
419 if (gathering_state_ != kIceGatheringGathering) {
420 gathering_state_ = kIceGatheringGathering;
421 SignalGatheringState(this);
422 }
423 // Time for a new allocator
424 AddAllocatorSession(allocator_->CreateSession(
425 SessionId(), transport_name(), component(), ice_ufrag_, ice_pwd_));
426 }
427 }
428
429 // A new port is available, attempt to make connections for it
OnPortReady(PortAllocatorSession * session,PortInterface * port)430 void P2PTransportChannel::OnPortReady(PortAllocatorSession *session,
431 PortInterface* port) {
432 ASSERT(worker_thread_ == rtc::Thread::Current());
433
434 // Set in-effect options on the new port
435 for (OptionMap::const_iterator it = options_.begin();
436 it != options_.end();
437 ++it) {
438 int val = port->SetOption(it->first, it->second);
439 if (val < 0) {
440 LOG_J(LS_WARNING, port) << "SetOption(" << it->first
441 << ", " << it->second
442 << ") failed: " << port->GetError();
443 }
444 }
445
446 // Remember the ports and candidates, and signal that candidates are ready.
447 // The session will handle this, and send an initiate/accept/modify message
448 // if one is pending.
449
450 port->SetIceRole(ice_role_);
451 port->SetIceTiebreaker(tiebreaker_);
452 ports_.push_back(port);
453 port->SignalUnknownAddress.connect(
454 this, &P2PTransportChannel::OnUnknownAddress);
455 port->SignalDestroyed.connect(this, &P2PTransportChannel::OnPortDestroyed);
456 port->SignalRoleConflict.connect(
457 this, &P2PTransportChannel::OnRoleConflict);
458 port->SignalSentPacket.connect(this, &P2PTransportChannel::OnSentPacket);
459
460 // Attempt to create a connection from this new port to all of the remote
461 // candidates that we were given so far.
462
463 std::vector<RemoteCandidate>::iterator iter;
464 for (iter = remote_candidates_.begin(); iter != remote_candidates_.end();
465 ++iter) {
466 CreateConnection(port, *iter, iter->origin_port());
467 }
468
469 SortConnections();
470 }
471
472 // A new candidate is available, let listeners know
OnCandidatesReady(PortAllocatorSession * session,const std::vector<Candidate> & candidates)473 void P2PTransportChannel::OnCandidatesReady(
474 PortAllocatorSession* session,
475 const std::vector<Candidate>& candidates) {
476 ASSERT(worker_thread_ == rtc::Thread::Current());
477 for (size_t i = 0; i < candidates.size(); ++i) {
478 SignalCandidateGathered(this, candidates[i]);
479 }
480 }
481
OnCandidatesAllocationDone(PortAllocatorSession * session)482 void P2PTransportChannel::OnCandidatesAllocationDone(
483 PortAllocatorSession* session) {
484 ASSERT(worker_thread_ == rtc::Thread::Current());
485 gathering_state_ = kIceGatheringComplete;
486 LOG(LS_INFO) << "P2PTransportChannel: " << transport_name() << ", component "
487 << component() << " gathering complete";
488 SignalGatheringState(this);
489 }
490
491 // Handle stun packets
OnUnknownAddress(PortInterface * port,const rtc::SocketAddress & address,ProtocolType proto,IceMessage * stun_msg,const std::string & remote_username,bool port_muxed)492 void P2PTransportChannel::OnUnknownAddress(
493 PortInterface* port,
494 const rtc::SocketAddress& address, ProtocolType proto,
495 IceMessage* stun_msg, const std::string &remote_username,
496 bool port_muxed) {
497 ASSERT(worker_thread_ == rtc::Thread::Current());
498
499 // Port has received a valid stun packet from an address that no Connection
500 // is currently available for. See if we already have a candidate with the
501 // address. If it isn't we need to create new candidate for it.
502
503 // Determine if the remote candidates use shared ufrag.
504 bool ufrag_per_port = false;
505 std::vector<RemoteCandidate>::iterator it;
506 if (remote_candidates_.size() > 0) {
507 it = remote_candidates_.begin();
508 std::string username = it->username();
509 for (; it != remote_candidates_.end(); ++it) {
510 if (it->username() != username) {
511 ufrag_per_port = true;
512 break;
513 }
514 }
515 }
516
517 const Candidate* candidate = NULL;
518 std::string remote_password;
519 for (it = remote_candidates_.begin(); it != remote_candidates_.end(); ++it) {
520 if (it->username() == remote_username) {
521 remote_password = it->password();
522 if (ufrag_per_port ||
523 (it->address() == address &&
524 it->protocol() == ProtoToString(proto))) {
525 candidate = &(*it);
526 break;
527 }
528 // We don't want to break here because we may find a match of the address
529 // later.
530 }
531 }
532
533 uint32_t remote_generation = 0;
534 // The STUN binding request may arrive after setRemoteDescription and before
535 // adding remote candidate, so we need to set the password to the shared
536 // password if the user name matches.
537 if (remote_password.empty()) {
538 const IceParameters* ice_param =
539 FindRemoteIceFromUfrag(remote_username, &remote_generation);
540 // Note: if not found, the remote_generation will still be 0.
541 if (ice_param != nullptr) {
542 remote_password = ice_param->pwd;
543 }
544 }
545
546 Candidate remote_candidate;
547 bool remote_candidate_is_new = (candidate == nullptr);
548 if (!remote_candidate_is_new) {
549 remote_candidate = *candidate;
550 if (ufrag_per_port) {
551 remote_candidate.set_address(address);
552 }
553 } else {
554 // Create a new candidate with this address.
555 int remote_candidate_priority;
556
557 // The priority of the candidate is set to the PRIORITY attribute
558 // from the request.
559 const StunUInt32Attribute* priority_attr =
560 stun_msg->GetUInt32(STUN_ATTR_PRIORITY);
561 if (!priority_attr) {
562 LOG(LS_WARNING) << "P2PTransportChannel::OnUnknownAddress - "
563 << "No STUN_ATTR_PRIORITY found in the "
564 << "stun request message";
565 port->SendBindingErrorResponse(stun_msg, address, STUN_ERROR_BAD_REQUEST,
566 STUN_ERROR_REASON_BAD_REQUEST);
567 return;
568 }
569 remote_candidate_priority = priority_attr->value();
570
571 // RFC 5245
572 // If the source transport address of the request does not match any
573 // existing remote candidates, it represents a new peer reflexive remote
574 // candidate.
575 remote_candidate = Candidate(component(), ProtoToString(proto), address, 0,
576 remote_username, remote_password,
577 PRFLX_PORT_TYPE, remote_generation, "");
578
579 // From RFC 5245, section-7.2.1.3:
580 // The foundation of the candidate is set to an arbitrary value, different
581 // from the foundation for all other remote candidates.
582 remote_candidate.set_foundation(
583 rtc::ToString<uint32_t>(rtc::ComputeCrc32(remote_candidate.id())));
584
585 remote_candidate.set_priority(remote_candidate_priority);
586 }
587
588 // RFC5245, the agent constructs a pair whose local candidate is equal to
589 // the transport address on which the STUN request was received, and a
590 // remote candidate equal to the source transport address where the
591 // request came from.
592
593 // There shouldn't be an existing connection with this remote address.
594 // When ports are muxed, this channel might get multiple unknown address
595 // signals. In that case if the connection is already exists, we should
596 // simply ignore the signal otherwise send server error.
597 if (port->GetConnection(remote_candidate.address())) {
598 if (port_muxed) {
599 LOG(LS_INFO) << "Connection already exists for peer reflexive "
600 << "candidate: " << remote_candidate.ToString();
601 return;
602 } else {
603 ASSERT(false);
604 port->SendBindingErrorResponse(stun_msg, address,
605 STUN_ERROR_SERVER_ERROR,
606 STUN_ERROR_REASON_SERVER_ERROR);
607 return;
608 }
609 }
610
611 Connection* connection = port->CreateConnection(
612 remote_candidate, cricket::PortInterface::ORIGIN_THIS_PORT);
613 if (!connection) {
614 ASSERT(false);
615 port->SendBindingErrorResponse(stun_msg, address, STUN_ERROR_SERVER_ERROR,
616 STUN_ERROR_REASON_SERVER_ERROR);
617 return;
618 }
619
620 LOG(LS_INFO) << "Adding connection from "
621 << (remote_candidate_is_new ? "peer reflexive" : "resurrected")
622 << " candidate: " << remote_candidate.ToString();
623 AddConnection(connection);
624 connection->HandleBindingRequest(stun_msg);
625
626 // Update the list of connections since we just added another. We do this
627 // after sending the response since it could (in principle) delete the
628 // connection in question.
629 SortConnections();
630 }
631
OnRoleConflict(PortInterface * port)632 void P2PTransportChannel::OnRoleConflict(PortInterface* port) {
633 SignalRoleConflict(this); // STUN ping will be sent when SetRole is called
634 // from Transport.
635 }
636
FindRemoteIceFromUfrag(const std::string & ufrag,uint32_t * generation)637 const IceParameters* P2PTransportChannel::FindRemoteIceFromUfrag(
638 const std::string& ufrag,
639 uint32_t* generation) {
640 const auto& params = remote_ice_parameters_;
641 auto it = std::find_if(
642 params.rbegin(), params.rend(),
643 [ufrag](const IceParameters& param) { return param.ufrag == ufrag; });
644 if (it == params.rend()) {
645 // Not found.
646 return nullptr;
647 }
648 *generation = params.rend() - it - 1;
649 return &(*it);
650 }
651
OnNominated(Connection * conn)652 void P2PTransportChannel::OnNominated(Connection* conn) {
653 ASSERT(worker_thread_ == rtc::Thread::Current());
654 ASSERT(ice_role_ == ICEROLE_CONTROLLED);
655
656 if (conn->write_state() == Connection::STATE_WRITABLE) {
657 if (best_connection_ != conn) {
658 pending_best_connection_ = NULL;
659 LOG(LS_INFO) << "Switching best connection on controlled side: "
660 << conn->ToString();
661 SwitchBestConnectionTo(conn);
662 // Now we have selected the best connection, time to prune other existing
663 // connections and update the read/write state of the channel.
664 RequestSort();
665 }
666 } else {
667 LOG(LS_INFO) << "Not switching the best connection on controlled side yet,"
668 << " because it's not writable: " << conn->ToString();
669 pending_best_connection_ = conn;
670 }
671 }
672
AddRemoteCandidate(const Candidate & candidate)673 void P2PTransportChannel::AddRemoteCandidate(const Candidate& candidate) {
674 ASSERT(worker_thread_ == rtc::Thread::Current());
675
676 uint32_t generation = GetRemoteCandidateGeneration(candidate);
677 // If a remote candidate with a previous generation arrives, drop it.
678 if (generation < remote_ice_generation()) {
679 LOG(LS_WARNING) << "Dropping a remote candidate because its ufrag "
680 << candidate.username()
681 << " indicates it was for a previous generation.";
682 return;
683 }
684
685 Candidate new_remote_candidate(candidate);
686 new_remote_candidate.set_generation(generation);
687 // ICE candidates don't need to have username and password set, but
688 // the code below this (specifically, ConnectionRequest::Prepare in
689 // port.cc) uses the remote candidates's username. So, we set it
690 // here.
691 if (remote_ice()) {
692 if (candidate.username().empty()) {
693 new_remote_candidate.set_username(remote_ice()->ufrag);
694 }
695 if (new_remote_candidate.username() == remote_ice()->ufrag) {
696 if (candidate.password().empty()) {
697 new_remote_candidate.set_password(remote_ice()->pwd);
698 }
699 } else {
700 // The candidate belongs to the next generation. Its pwd will be set
701 // when the new remote ICE credentials arrive.
702 LOG(LS_WARNING) << "A remote candidate arrives with an unknown ufrag: "
703 << candidate.username();
704 }
705 }
706
707 // Create connections to this remote candidate.
708 CreateConnections(new_remote_candidate, NULL);
709
710 // Resort the connections list, which may have new elements.
711 SortConnections();
712 }
713
714 // Creates connections from all of the ports that we care about to the given
715 // remote candidate. The return value is true if we created a connection from
716 // the origin port.
CreateConnections(const Candidate & remote_candidate,PortInterface * origin_port)717 bool P2PTransportChannel::CreateConnections(const Candidate& remote_candidate,
718 PortInterface* origin_port) {
719 ASSERT(worker_thread_ == rtc::Thread::Current());
720
721 // If we've already seen the new remote candidate (in the current candidate
722 // generation), then we shouldn't try creating connections for it.
723 // We either already have a connection for it, or we previously created one
724 // and then later pruned it. If we don't return, the channel will again
725 // re-create any connections that were previously pruned, which will then
726 // immediately be re-pruned, churning the network for no purpose.
727 // This only applies to candidates received over signaling (i.e. origin_port
728 // is NULL).
729 if (!origin_port && IsDuplicateRemoteCandidate(remote_candidate)) {
730 // return true to indicate success, without creating any new connections.
731 return true;
732 }
733
734 // Add a new connection for this candidate to every port that allows such a
735 // connection (i.e., if they have compatible protocols) and that does not
736 // already have a connection to an equivalent candidate. We must be careful
737 // to make sure that the origin port is included, even if it was pruned,
738 // since that may be the only port that can create this connection.
739 bool created = false;
740 std::vector<PortInterface *>::reverse_iterator it;
741 for (it = ports_.rbegin(); it != ports_.rend(); ++it) {
742 if (CreateConnection(*it, remote_candidate, origin_port)) {
743 if (*it == origin_port)
744 created = true;
745 }
746 }
747
748 if ((origin_port != NULL) &&
749 std::find(ports_.begin(), ports_.end(), origin_port) == ports_.end()) {
750 if (CreateConnection(origin_port, remote_candidate, origin_port))
751 created = true;
752 }
753
754 // Remember this remote candidate so that we can add it to future ports.
755 RememberRemoteCandidate(remote_candidate, origin_port);
756
757 return created;
758 }
759
760 // Setup a connection object for the local and remote candidate combination.
761 // And then listen to connection object for changes.
CreateConnection(PortInterface * port,const Candidate & remote_candidate,PortInterface * origin_port)762 bool P2PTransportChannel::CreateConnection(PortInterface* port,
763 const Candidate& remote_candidate,
764 PortInterface* origin_port) {
765 if (!port->SupportsProtocol(remote_candidate.protocol())) {
766 return false;
767 }
768 // Look for an existing connection with this remote address. If one is not
769 // found, then we can create a new connection for this address.
770 Connection* connection = port->GetConnection(remote_candidate.address());
771 if (connection != NULL) {
772 connection->MaybeUpdatePeerReflexiveCandidate(remote_candidate);
773
774 // It is not legal to try to change any of the parameters of an existing
775 // connection; however, the other side can send a duplicate candidate.
776 if (!remote_candidate.IsEquivalent(connection->remote_candidate())) {
777 LOG(INFO) << "Attempt to change a remote candidate."
778 << " Existing remote candidate: "
779 << connection->remote_candidate().ToString()
780 << "New remote candidate: "
781 << remote_candidate.ToString();
782 return false;
783 }
784 } else {
785 PortInterface::CandidateOrigin origin = GetOrigin(port, origin_port);
786
787 // Don't create connection if this is a candidate we received in a
788 // message and we are not allowed to make outgoing connections.
789 if (origin == cricket::PortInterface::ORIGIN_MESSAGE && incoming_only_)
790 return false;
791
792 connection = port->CreateConnection(remote_candidate, origin);
793 if (!connection)
794 return false;
795
796 AddConnection(connection);
797
798 LOG_J(LS_INFO, this) << "Created connection with origin=" << origin << ", ("
799 << connections_.size() << " total)";
800 }
801
802 return true;
803 }
804
FindConnection(cricket::Connection * connection) const805 bool P2PTransportChannel::FindConnection(
806 cricket::Connection* connection) const {
807 std::vector<Connection*>::const_iterator citer =
808 std::find(connections_.begin(), connections_.end(), connection);
809 return citer != connections_.end();
810 }
811
GetRemoteCandidateGeneration(const Candidate & candidate)812 uint32_t P2PTransportChannel::GetRemoteCandidateGeneration(
813 const Candidate& candidate) {
814 // If the candidate has a ufrag, use it to find the generation.
815 if (!candidate.username().empty()) {
816 uint32_t generation = 0;
817 if (!FindRemoteIceFromUfrag(candidate.username(), &generation)) {
818 // If the ufrag is not found, assume the next/future generation.
819 generation = static_cast<uint32_t>(remote_ice_parameters_.size());
820 }
821 return generation;
822 }
823 // If candidate generation is set, use that.
824 if (candidate.generation() > 0) {
825 return candidate.generation();
826 }
827 // Otherwise, assume the generation from remote ice parameters.
828 return remote_ice_generation();
829 }
830
831 // Check if remote candidate is already cached.
IsDuplicateRemoteCandidate(const Candidate & candidate)832 bool P2PTransportChannel::IsDuplicateRemoteCandidate(
833 const Candidate& candidate) {
834 for (size_t i = 0; i < remote_candidates_.size(); ++i) {
835 if (remote_candidates_[i].IsEquivalent(candidate)) {
836 return true;
837 }
838 }
839 return false;
840 }
841
842 // Maintain our remote candidate list, adding this new remote one.
RememberRemoteCandidate(const Candidate & remote_candidate,PortInterface * origin_port)843 void P2PTransportChannel::RememberRemoteCandidate(
844 const Candidate& remote_candidate, PortInterface* origin_port) {
845 // Remove any candidates whose generation is older than this one. The
846 // presence of a new generation indicates that the old ones are not useful.
847 size_t i = 0;
848 while (i < remote_candidates_.size()) {
849 if (remote_candidates_[i].generation() < remote_candidate.generation()) {
850 LOG(INFO) << "Pruning candidate from old generation: "
851 << remote_candidates_[i].address().ToSensitiveString();
852 remote_candidates_.erase(remote_candidates_.begin() + i);
853 } else {
854 i += 1;
855 }
856 }
857
858 // Make sure this candidate is not a duplicate.
859 if (IsDuplicateRemoteCandidate(remote_candidate)) {
860 LOG(INFO) << "Duplicate candidate: " << remote_candidate.ToString();
861 return;
862 }
863
864 // Try this candidate for all future ports.
865 remote_candidates_.push_back(RemoteCandidate(remote_candidate, origin_port));
866 }
867
868 // Set options on ourselves is simply setting options on all of our available
869 // port objects.
SetOption(rtc::Socket::Option opt,int value)870 int P2PTransportChannel::SetOption(rtc::Socket::Option opt, int value) {
871 ASSERT(worker_thread_ == rtc::Thread::Current());
872 OptionMap::iterator it = options_.find(opt);
873 if (it == options_.end()) {
874 options_.insert(std::make_pair(opt, value));
875 } else if (it->second == value) {
876 return 0;
877 } else {
878 it->second = value;
879 }
880
881 for (size_t i = 0; i < ports_.size(); ++i) {
882 int val = ports_[i]->SetOption(opt, value);
883 if (val < 0) {
884 // Because this also occurs deferred, probably no point in reporting an
885 // error
886 LOG(WARNING) << "SetOption(" << opt << ", " << value << ") failed: "
887 << ports_[i]->GetError();
888 }
889 }
890 return 0;
891 }
892
GetOption(rtc::Socket::Option opt,int * value)893 bool P2PTransportChannel::GetOption(rtc::Socket::Option opt, int* value) {
894 ASSERT(worker_thread_ == rtc::Thread::Current());
895
896 const auto& found = options_.find(opt);
897 if (found == options_.end()) {
898 return false;
899 }
900 *value = found->second;
901 return true;
902 }
903
904 // Send data to the other side, using our best connection.
SendPacket(const char * data,size_t len,const rtc::PacketOptions & options,int flags)905 int P2PTransportChannel::SendPacket(const char *data, size_t len,
906 const rtc::PacketOptions& options,
907 int flags) {
908 ASSERT(worker_thread_ == rtc::Thread::Current());
909 if (flags != 0) {
910 error_ = EINVAL;
911 return -1;
912 }
913 if (best_connection_ == NULL) {
914 error_ = EWOULDBLOCK;
915 return -1;
916 }
917
918 int sent = best_connection_->Send(data, len, options);
919 if (sent <= 0) {
920 ASSERT(sent < 0);
921 error_ = best_connection_->GetError();
922 }
923 return sent;
924 }
925
GetStats(ConnectionInfos * infos)926 bool P2PTransportChannel::GetStats(ConnectionInfos *infos) {
927 ASSERT(worker_thread_ == rtc::Thread::Current());
928 // Gather connection infos.
929 infos->clear();
930
931 std::vector<Connection *>::const_iterator it;
932 for (Connection* connection : connections_) {
933 ConnectionInfo info;
934 info.best_connection = (best_connection_ == connection);
935 info.receiving = connection->receiving();
936 info.writable =
937 (connection->write_state() == Connection::STATE_WRITABLE);
938 info.timeout =
939 (connection->write_state() == Connection::STATE_WRITE_TIMEOUT);
940 info.new_connection = !connection->reported();
941 connection->set_reported(true);
942 info.rtt = connection->rtt();
943 info.sent_total_bytes = connection->sent_total_bytes();
944 info.sent_bytes_second = connection->sent_bytes_second();
945 info.sent_discarded_packets = connection->sent_discarded_packets();
946 info.sent_total_packets = connection->sent_total_packets();
947 info.recv_total_bytes = connection->recv_total_bytes();
948 info.recv_bytes_second = connection->recv_bytes_second();
949 info.local_candidate = connection->local_candidate();
950 info.remote_candidate = connection->remote_candidate();
951 info.key = connection;
952 infos->push_back(info);
953 }
954
955 return true;
956 }
957
DefaultDscpValue() const958 rtc::DiffServCodePoint P2PTransportChannel::DefaultDscpValue() const {
959 OptionMap::const_iterator it = options_.find(rtc::Socket::OPT_DSCP);
960 if (it == options_.end()) {
961 return rtc::DSCP_NO_CHANGE;
962 }
963 return static_cast<rtc::DiffServCodePoint> (it->second);
964 }
965
966 // Monitor connection states.
UpdateConnectionStates()967 void P2PTransportChannel::UpdateConnectionStates() {
968 uint32_t now = rtc::Time();
969
970 // We need to copy the list of connections since some may delete themselves
971 // when we call UpdateState.
972 for (size_t i = 0; i < connections_.size(); ++i)
973 connections_[i]->UpdateState(now);
974 }
975
976 // Prepare for best candidate sorting.
RequestSort()977 void P2PTransportChannel::RequestSort() {
978 if (!sort_dirty_) {
979 worker_thread_->Post(this, MSG_SORT);
980 sort_dirty_ = true;
981 }
982 }
983
984 // Sort the available connections to find the best one. We also monitor
985 // the number of available connections and the current state.
SortConnections()986 void P2PTransportChannel::SortConnections() {
987 ASSERT(worker_thread_ == rtc::Thread::Current());
988
989 // Make sure the connection states are up-to-date since this affects how they
990 // will be sorted.
991 UpdateConnectionStates();
992
993 // Any changes after this point will require a re-sort.
994 sort_dirty_ = false;
995
996 // Find the best alternative connection by sorting. It is important to note
997 // that amongst equal preference, writable connections, this will choose the
998 // one whose estimated latency is lowest. So it is the only one that we
999 // need to consider switching to.
1000 ConnectionCompare cmp;
1001 std::stable_sort(connections_.begin(), connections_.end(), cmp);
1002 LOG(LS_VERBOSE) << "Sorting " << connections_.size()
1003 << " available connections:";
1004 for (size_t i = 0; i < connections_.size(); ++i) {
1005 LOG(LS_VERBOSE) << connections_[i]->ToString();
1006 }
1007
1008 Connection* top_connection =
1009 (connections_.size() > 0) ? connections_[0] : nullptr;
1010
1011 // If necessary, switch to the new choice.
1012 // Note that |top_connection| doesn't have to be writable to become the best
1013 // connection although it will have higher priority if it is writable.
1014 if (ShouldSwitch(best_connection_, top_connection, ice_role_)) {
1015 LOG(LS_INFO) << "Switching best connection: " << top_connection->ToString();
1016 SwitchBestConnectionTo(top_connection);
1017 }
1018
1019 // Controlled side can prune only if the best connection has been nominated.
1020 // because otherwise it may delete the connection that will be selected by
1021 // the controlling side.
1022 if (ice_role_ == ICEROLE_CONTROLLING || best_nominated_connection()) {
1023 PruneConnections();
1024 }
1025
1026 // Check if all connections are timedout.
1027 bool all_connections_timedout = true;
1028 for (size_t i = 0; i < connections_.size(); ++i) {
1029 if (connections_[i]->write_state() != Connection::STATE_WRITE_TIMEOUT) {
1030 all_connections_timedout = false;
1031 break;
1032 }
1033 }
1034
1035 // Now update the writable state of the channel with the information we have
1036 // so far.
1037 if (all_connections_timedout) {
1038 HandleAllTimedOut();
1039 }
1040
1041 // Update the state of this channel. This method is called whenever the
1042 // state of any connection changes, so this is a good place to do this.
1043 UpdateState();
1044 }
1045
best_nominated_connection() const1046 Connection* P2PTransportChannel::best_nominated_connection() const {
1047 return (best_connection_ && best_connection_->nominated()) ? best_connection_
1048 : nullptr;
1049 }
1050
PruneConnections()1051 void P2PTransportChannel::PruneConnections() {
1052 // We can prune any connection for which there is a connected, writable
1053 // connection on the same network with better or equal priority. We leave
1054 // those with better priority just in case they become writable later (at
1055 // which point, we would prune out the current best connection). We leave
1056 // connections on other networks because they may not be using the same
1057 // resources and they may represent very distinct paths over which we can
1058 // switch. If the |premier| connection is not connected, we may be
1059 // reconnecting a TCP connection and temporarily do not prune connections in
1060 // this network. See the big comment in CompareConnections.
1061
1062 // Get a list of the networks that we are using.
1063 std::set<rtc::Network*> networks;
1064 for (const Connection* conn : connections_) {
1065 networks.insert(conn->port()->Network());
1066 }
1067 for (rtc::Network* network : networks) {
1068 Connection* premier = GetBestConnectionOnNetwork(network);
1069 // Do not prune connections if the current best connection is weak on this
1070 // network. Otherwise, it may delete connections prematurely.
1071 if (!premier || premier->weak()) {
1072 continue;
1073 }
1074
1075 for (Connection* conn : connections_) {
1076 if ((conn != premier) && (conn->port()->Network() == network) &&
1077 (CompareConnectionCandidates(premier, conn) >= 0)) {
1078 conn->Prune();
1079 }
1080 }
1081 }
1082 }
1083
1084 // Track the best connection, and let listeners know
SwitchBestConnectionTo(Connection * conn)1085 void P2PTransportChannel::SwitchBestConnectionTo(Connection* conn) {
1086 // Note: if conn is NULL, the previous best_connection_ has been destroyed,
1087 // so don't use it.
1088 Connection* old_best_connection = best_connection_;
1089 best_connection_ = conn;
1090 if (best_connection_) {
1091 if (old_best_connection) {
1092 LOG_J(LS_INFO, this) << "Previous best connection: "
1093 << old_best_connection->ToString();
1094 }
1095 LOG_J(LS_INFO, this) << "New best connection: "
1096 << best_connection_->ToString();
1097 SignalRouteChange(this, best_connection_->remote_candidate());
1098 } else {
1099 LOG_J(LS_INFO, this) << "No best connection";
1100 }
1101 }
1102
1103 // Warning: UpdateState should eventually be called whenever a connection
1104 // is added, deleted, or the write state of any connection changes so that the
1105 // transport controller will get the up-to-date channel state. However it
1106 // should not be called too often; in the case that multiple connection states
1107 // change, it should be called after all the connection states have changed. For
1108 // example, we call this at the end of SortConnections.
UpdateState()1109 void P2PTransportChannel::UpdateState() {
1110 state_ = ComputeState();
1111
1112 bool writable = best_connection_ && best_connection_->writable();
1113 set_writable(writable);
1114
1115 bool receiving = false;
1116 for (const Connection* connection : connections_) {
1117 if (connection->receiving()) {
1118 receiving = true;
1119 break;
1120 }
1121 }
1122 set_receiving(receiving);
1123 }
1124
MaybeStopPortAllocatorSessions()1125 void P2PTransportChannel::MaybeStopPortAllocatorSessions() {
1126 if (!IsGettingPorts()) {
1127 return;
1128 }
1129
1130 for (PortAllocatorSession* session : allocator_sessions_) {
1131 if (!session->IsGettingPorts()) {
1132 continue;
1133 }
1134 // If gathering continually, keep the last session running so that it
1135 // will gather candidates if the networks change.
1136 if (gather_continually_ && session == allocator_sessions_.back()) {
1137 session->ClearGettingPorts();
1138 break;
1139 }
1140 session->StopGettingPorts();
1141 }
1142 }
1143
1144 // If all connections timed out, delete them all.
HandleAllTimedOut()1145 void P2PTransportChannel::HandleAllTimedOut() {
1146 for (Connection* connection : connections_) {
1147 connection->Destroy();
1148 }
1149 }
1150
weak() const1151 bool P2PTransportChannel::weak() const {
1152 return !best_connection_ || best_connection_->weak();
1153 }
1154
1155 // If we have a best connection, return it, otherwise return top one in the
1156 // list (later we will mark it best).
GetBestConnectionOnNetwork(rtc::Network * network) const1157 Connection* P2PTransportChannel::GetBestConnectionOnNetwork(
1158 rtc::Network* network) const {
1159 // If the best connection is on this network, then it wins.
1160 if (best_connection_ && (best_connection_->port()->Network() == network))
1161 return best_connection_;
1162
1163 // Otherwise, we return the top-most in sorted order.
1164 for (size_t i = 0; i < connections_.size(); ++i) {
1165 if (connections_[i]->port()->Network() == network)
1166 return connections_[i];
1167 }
1168
1169 return NULL;
1170 }
1171
1172 // Handle any queued up requests
OnMessage(rtc::Message * pmsg)1173 void P2PTransportChannel::OnMessage(rtc::Message *pmsg) {
1174 switch (pmsg->message_id) {
1175 case MSG_SORT:
1176 OnSort();
1177 break;
1178 case MSG_CHECK_AND_PING:
1179 OnCheckAndPing();
1180 break;
1181 default:
1182 ASSERT(false);
1183 break;
1184 }
1185 }
1186
1187 // Handle queued up sort request
OnSort()1188 void P2PTransportChannel::OnSort() {
1189 // Resort the connections based on the new statistics.
1190 SortConnections();
1191 }
1192
1193 // Handle queued up check-and-ping request
OnCheckAndPing()1194 void P2PTransportChannel::OnCheckAndPing() {
1195 // Make sure the states of the connections are up-to-date (since this affects
1196 // which ones are pingable).
1197 UpdateConnectionStates();
1198 // When the best connection is either not receiving or not writable,
1199 // switch to weak ping delay.
1200 int ping_delay = weak() ? weak_ping_delay_ : STRONG_PING_DELAY;
1201 if (rtc::Time() >= last_ping_sent_ms_ + ping_delay) {
1202 Connection* conn = FindNextPingableConnection();
1203 if (conn) {
1204 PingConnection(conn);
1205 }
1206 }
1207 int check_delay = std::min(ping_delay, check_receiving_delay_);
1208 thread()->PostDelayed(check_delay, this, MSG_CHECK_AND_PING);
1209 }
1210
1211 // A connection is considered a backup connection if the channel state
1212 // is completed, the connection is not the best connection and it is active.
IsBackupConnection(Connection * conn) const1213 bool P2PTransportChannel::IsBackupConnection(Connection* conn) const {
1214 return state_ == STATE_COMPLETED && conn != best_connection_ &&
1215 conn->active();
1216 }
1217
1218 // Is the connection in a state for us to even consider pinging the other side?
1219 // We consider a connection pingable even if it's not connected because that's
1220 // how a TCP connection is kicked into reconnecting on the active side.
IsPingable(Connection * conn,uint32_t now)1221 bool P2PTransportChannel::IsPingable(Connection* conn, uint32_t now) {
1222 const Candidate& remote = conn->remote_candidate();
1223 // We should never get this far with an empty remote ufrag.
1224 ASSERT(!remote.username().empty());
1225 if (remote.username().empty() || remote.password().empty()) {
1226 // If we don't have an ICE ufrag and pwd, there's no way we can ping.
1227 return false;
1228 }
1229
1230 // An never connected connection cannot be written to at all, so pinging is
1231 // out of the question. However, if it has become WRITABLE, it is in the
1232 // reconnecting state so ping is needed.
1233 if (!conn->connected() && !conn->writable()) {
1234 return false;
1235 }
1236
1237 // If the channel is weakly connected, ping all connections.
1238 if (weak()) {
1239 return true;
1240 }
1241
1242 // Always ping active connections regardless whether the channel is completed
1243 // or not, but backup connections are pinged at a slower rate.
1244 if (IsBackupConnection(conn)) {
1245 return (now >= conn->last_ping_response_received() +
1246 backup_connection_ping_interval_);
1247 }
1248 return conn->active();
1249 }
1250
1251 // Returns the next pingable connection to ping. This will be the oldest
1252 // pingable connection unless we have a connected, writable connection that is
1253 // past the maximum acceptable ping delay. When reconnecting a TCP connection,
1254 // the best connection is disconnected, although still WRITABLE while
1255 // reconnecting. The newly created connection should be selected as the ping
1256 // target to become writable instead. See the big comment in CompareConnections.
FindNextPingableConnection()1257 Connection* P2PTransportChannel::FindNextPingableConnection() {
1258 uint32_t now = rtc::Time();
1259 if (best_connection_ && best_connection_->connected() &&
1260 best_connection_->writable() &&
1261 (best_connection_->last_ping_sent() + MAX_CURRENT_STRONG_DELAY <= now)) {
1262 return best_connection_;
1263 }
1264
1265 // First, find "triggered checks". We ping first those connections
1266 // that have received a ping but have not sent a ping since receiving
1267 // it (last_received_ping > last_sent_ping). But we shouldn't do
1268 // triggered checks if the connection is already writable.
1269 Connection* oldest_needing_triggered_check = nullptr;
1270 Connection* oldest = nullptr;
1271 for (Connection* conn : connections_) {
1272 if (!IsPingable(conn, now)) {
1273 continue;
1274 }
1275 bool needs_triggered_check =
1276 (!conn->writable() &&
1277 conn->last_ping_received() > conn->last_ping_sent());
1278 if (needs_triggered_check &&
1279 (!oldest_needing_triggered_check ||
1280 (conn->last_ping_received() <
1281 oldest_needing_triggered_check->last_ping_received()))) {
1282 oldest_needing_triggered_check = conn;
1283 }
1284 if (!oldest || (conn->last_ping_sent() < oldest->last_ping_sent())) {
1285 oldest = conn;
1286 }
1287 }
1288
1289 if (oldest_needing_triggered_check) {
1290 LOG(LS_INFO) << "Selecting connection for triggered check: " <<
1291 oldest_needing_triggered_check->ToString();
1292 return oldest_needing_triggered_check;
1293 }
1294 return oldest;
1295 }
1296
1297 // Apart from sending ping from |conn| this method also updates
1298 // |use_candidate_attr| flag. The criteria to update this flag is
1299 // explained below.
1300 // Set USE-CANDIDATE if doing ICE AND this channel is in CONTROLLING AND
1301 // a) Channel is in FULL ICE AND
1302 // a.1) |conn| is the best connection OR
1303 // a.2) there is no best connection OR
1304 // a.3) the best connection is unwritable OR
1305 // a.4) |conn| has higher priority than best_connection.
1306 // b) we're doing LITE ICE AND
1307 // b.1) |conn| is the best_connection AND
1308 // b.2) |conn| is writable.
PingConnection(Connection * conn)1309 void P2PTransportChannel::PingConnection(Connection* conn) {
1310 bool use_candidate = false;
1311 if (remote_ice_mode_ == ICEMODE_FULL && ice_role_ == ICEROLE_CONTROLLING) {
1312 use_candidate = (conn == best_connection_) || (best_connection_ == NULL) ||
1313 (!best_connection_->writable()) ||
1314 (conn->priority() > best_connection_->priority());
1315 } else if (remote_ice_mode_ == ICEMODE_LITE && conn == best_connection_) {
1316 use_candidate = best_connection_->writable();
1317 }
1318 conn->set_use_candidate_attr(use_candidate);
1319 last_ping_sent_ms_ = rtc::Time();
1320 conn->Ping(last_ping_sent_ms_);
1321 }
1322
1323 // When a connection's state changes, we need to figure out who to use as
1324 // the best connection again. It could have become usable, or become unusable.
OnConnectionStateChange(Connection * connection)1325 void P2PTransportChannel::OnConnectionStateChange(Connection* connection) {
1326 ASSERT(worker_thread_ == rtc::Thread::Current());
1327
1328 // Update the best connection if the state change is from pending best
1329 // connection and role is controlled.
1330 if (ice_role_ == ICEROLE_CONTROLLED) {
1331 if (connection == pending_best_connection_ && connection->writable()) {
1332 pending_best_connection_ = NULL;
1333 LOG(LS_INFO) << "Switching best connection on controlled side"
1334 << " because it's now writable: " << connection->ToString();
1335 SwitchBestConnectionTo(connection);
1336 }
1337 }
1338
1339 // May stop the allocator session when at least one connection becomes
1340 // strongly connected after starting to get ports. It is not enough to check
1341 // that the connection becomes weakly connected because the connection may be
1342 // changing from (writable, receiving) to (writable, not receiving).
1343 if (!connection->weak()) {
1344 MaybeStopPortAllocatorSessions();
1345 }
1346
1347 // We have to unroll the stack before doing this because we may be changing
1348 // the state of connections while sorting.
1349 RequestSort();
1350 }
1351
1352 // When a connection is removed, edit it out, and then update our best
1353 // connection.
OnConnectionDestroyed(Connection * connection)1354 void P2PTransportChannel::OnConnectionDestroyed(Connection* connection) {
1355 ASSERT(worker_thread_ == rtc::Thread::Current());
1356
1357 // Note: the previous best_connection_ may be destroyed by now, so don't
1358 // use it.
1359
1360 // Remove this connection from the list.
1361 std::vector<Connection*>::iterator iter =
1362 std::find(connections_.begin(), connections_.end(), connection);
1363 ASSERT(iter != connections_.end());
1364 connections_.erase(iter);
1365
1366 LOG_J(LS_INFO, this) << "Removed connection ("
1367 << static_cast<int>(connections_.size()) << " remaining)";
1368
1369 if (pending_best_connection_ == connection) {
1370 pending_best_connection_ = NULL;
1371 }
1372
1373 // If this is currently the best connection, then we need to pick a new one.
1374 // The call to SortConnections will pick a new one. It looks at the current
1375 // best connection in order to avoid switching between fairly similar ones.
1376 // Since this connection is no longer an option, we can just set best to NULL
1377 // and re-choose a best assuming that there was no best connection.
1378 if (best_connection_ == connection) {
1379 LOG(LS_INFO) << "Best connection destroyed. Will choose a new one.";
1380 SwitchBestConnectionTo(NULL);
1381 RequestSort();
1382 }
1383
1384 UpdateState();
1385 // SignalConnectionRemoved should be called after the channel state is
1386 // updated because the receiver of the event may access the channel state.
1387 SignalConnectionRemoved(this);
1388 }
1389
1390 // When a port is destroyed remove it from our list of ports to use for
1391 // connection attempts.
OnPortDestroyed(PortInterface * port)1392 void P2PTransportChannel::OnPortDestroyed(PortInterface* port) {
1393 ASSERT(worker_thread_ == rtc::Thread::Current());
1394
1395 // Remove this port from the list (if we didn't drop it already).
1396 std::vector<PortInterface*>::iterator iter =
1397 std::find(ports_.begin(), ports_.end(), port);
1398 if (iter != ports_.end())
1399 ports_.erase(iter);
1400
1401 LOG(INFO) << "Removed port from p2p socket: "
1402 << static_cast<int>(ports_.size()) << " remaining";
1403 }
1404
1405 // We data is available, let listeners know
OnReadPacket(Connection * connection,const char * data,size_t len,const rtc::PacketTime & packet_time)1406 void P2PTransportChannel::OnReadPacket(Connection* connection,
1407 const char* data,
1408 size_t len,
1409 const rtc::PacketTime& packet_time) {
1410 ASSERT(worker_thread_ == rtc::Thread::Current());
1411
1412 // Do not deliver, if packet doesn't belong to the correct transport channel.
1413 if (!FindConnection(connection))
1414 return;
1415
1416 // Let the client know of an incoming packet
1417 SignalReadPacket(this, data, len, packet_time, 0);
1418
1419 // May need to switch the sending connection based on the receiving media path
1420 // if this is the controlled side.
1421 if (ice_role_ == ICEROLE_CONTROLLED && !best_nominated_connection() &&
1422 connection->writable() && best_connection_ != connection) {
1423 SwitchBestConnectionTo(connection);
1424 }
1425 }
1426
OnSentPacket(const rtc::SentPacket & sent_packet)1427 void P2PTransportChannel::OnSentPacket(const rtc::SentPacket& sent_packet) {
1428 ASSERT(worker_thread_ == rtc::Thread::Current());
1429
1430 SignalSentPacket(this, sent_packet);
1431 }
1432
OnReadyToSend(Connection * connection)1433 void P2PTransportChannel::OnReadyToSend(Connection* connection) {
1434 if (connection == best_connection_ && writable()) {
1435 SignalReadyToSend(this);
1436 }
1437 }
1438
1439 } // namespace cricket
1440