Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(356)

Side by Side Diff: webrtc/p2p/base/p2ptransportchannel.cc

Issue 1577233006: Implement Turn/Turn first logic for connection selection. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc@master
Patch Set: Fix test issues Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright 2004 The WebRTC Project Authors. All rights reserved. 2 * Copyright 2004 The WebRTC Project Authors. All rights reserved.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license 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 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 6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may 7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree. 8 * be found in the AUTHORS file in the root of the source tree.
9 */ 9 */
10 10
(...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after
191 // STRONG_PING_DELAY (480ms) is applied when the best connection is both 191 // STRONG_PING_DELAY (480ms) is applied when the best connection is both
192 // writable and receiving. 192 // writable and receiving.
193 static const uint32_t STRONG_PING_DELAY = 1000 * PING_PACKET_SIZE / 1000; 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 194 // WEAK_PING_DELAY (48ms) is applied when the best connection is either not
195 // writable or not receiving. 195 // writable or not receiving.
196 const uint32_t WEAK_PING_DELAY = 1000 * PING_PACKET_SIZE / 10000; 196 const uint32_t WEAK_PING_DELAY = 1000 * PING_PACKET_SIZE / 10000;
197 197
198 // If the current best connection is both writable and receiving, then we will 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 199 // also try hard to make sure it is pinged at this rate (a little less than
200 // 2 * STRONG_PING_DELAY). 200 // 2 * STRONG_PING_DELAY).
201 static const uint32_t MAX_CURRENT_STRONG_DELAY = 900; 201 const uint32_t MAX_CURRENT_STRONG_DELAY = 900;
202 202
203 static const int MIN_CHECK_RECEIVING_DELAY = 50; // ms 203 static const int MIN_CHECK_RECEIVING_DELAY = 50; // ms
204 204
205 P2PTransportChannel::P2PTransportChannel(const std::string& transport_name, 205 P2PTransportChannel::P2PTransportChannel(const std::string& transport_name,
206 int component, 206 int component,
207 P2PTransport* transport, 207 P2PTransport* transport,
208 PortAllocator* allocator) 208 PortAllocator* allocator)
209 : TransportChannelImpl(transport_name, component), 209 : TransportChannelImpl(transport_name, component),
210 transport_(transport), 210 transport_(transport),
211 allocator_(allocator), 211 allocator_(allocator),
212 worker_thread_(rtc::Thread::Current()), 212 worker_thread_(rtc::Thread::Current()),
213 incoming_only_(false), 213 incoming_only_(false),
214 error_(0), 214 error_(0),
215 connections_(this),
215 best_connection_(NULL), 216 best_connection_(NULL),
216 pending_best_connection_(NULL), 217 pending_best_connection_(NULL),
217 sort_dirty_(false), 218 sort_dirty_(false),
218 remote_ice_mode_(ICEMODE_FULL), 219 remote_ice_mode_(ICEMODE_FULL),
219 ice_role_(ICEROLE_UNKNOWN), 220 ice_role_(ICEROLE_UNKNOWN),
220 tiebreaker_(0), 221 tiebreaker_(0),
221 gathering_state_(kIceGatheringNew), 222 gathering_state_(kIceGatheringNew),
222 check_receiving_delay_(MIN_CHECK_RECEIVING_DELAY * 5), 223 check_receiving_delay_(MIN_CHECK_RECEIVING_DELAY * 5),
223 receiving_timeout_(MIN_CHECK_RECEIVING_DELAY * 50), 224 receiving_timeout_(MIN_CHECK_RECEIVING_DELAY * 50),
224 backup_connection_ping_interval_(0) { 225 backup_connection_ping_interval_(0) {
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after
387 receiving_timeout_ = config.receiving_timeout_ms; 388 receiving_timeout_ = config.receiving_timeout_ms;
388 check_receiving_delay_ = 389 check_receiving_delay_ =
389 std::max(MIN_CHECK_RECEIVING_DELAY, receiving_timeout_ / 10); 390 std::max(MIN_CHECK_RECEIVING_DELAY, receiving_timeout_ / 10);
390 391
391 for (Connection* connection : connections_) { 392 for (Connection* connection : connections_) {
392 connection->set_receiving_timeout(receiving_timeout_); 393 connection->set_receiving_timeout(receiving_timeout_);
393 } 394 }
394 LOG(LS_INFO) << "Set ICE receiving timeout to " << receiving_timeout_ 395 LOG(LS_INFO) << "Set ICE receiving timeout to " << receiving_timeout_
395 << " milliseconds"; 396 << " milliseconds";
396 } 397 }
398
399 connections_.enable_most_likely_first(
400 config.ping_most_likely_candidate_pair_first);
401 LOG(LS_INFO) << "Set ping most likely connection to "
402 << connections_.most_likely_first();
pthatcher1 2016/01/27 19:59:58 This might be better named prioritize_most_likely_
guoweis_webrtc 2016/02/29 18:03:00 Done.
403 }
404
405 IceConfig P2PTransportChannel::GetIceConfig() const {
406 IceConfig config;
407 config.gather_continually = gather_continually_;
408 config.receiving_timeout_ms = receiving_timeout_;
409 config.ping_most_likely_candidate_pair_first =
410 connections_.most_likely_first();
411 return config;
pthatcher1 2016/01/27 19:59:58 Instead of converting between the struct and the m
guoweis_webrtc 2016/02/29 18:03:00 Done.
397 } 412 }
398 413
399 // Go into the state of processing candidates, and running in general 414 // Go into the state of processing candidates, and running in general
400 void P2PTransportChannel::Connect() { 415 void P2PTransportChannel::Connect() {
401 ASSERT(worker_thread_ == rtc::Thread::Current()); 416 ASSERT(worker_thread_ == rtc::Thread::Current());
402 if (ice_ufrag_.empty() || ice_pwd_.empty()) { 417 if (ice_ufrag_.empty() || ice_pwd_.empty()) {
403 ASSERT(false); 418 ASSERT(false);
404 LOG(LS_ERROR) << "P2PTransportChannel::Connect: The ice_ufrag_ and the " 419 LOG(LS_ERROR) << "P2PTransportChannel::Connect: The ice_ufrag_ and the "
405 << "ice_pwd_ are not set."; 420 << "ice_pwd_ are not set.";
406 return; 421 return;
(...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after
601 return; 616 return;
602 } else { 617 } else {
603 ASSERT(false); 618 ASSERT(false);
604 port->SendBindingErrorResponse(stun_msg, address, 619 port->SendBindingErrorResponse(stun_msg, address,
605 STUN_ERROR_SERVER_ERROR, 620 STUN_ERROR_SERVER_ERROR,
606 STUN_ERROR_REASON_SERVER_ERROR); 621 STUN_ERROR_REASON_SERVER_ERROR);
607 return; 622 return;
608 } 623 }
609 } 624 }
610 625
611 Connection* connection = port->CreateConnection( 626 Connection* connection =
612 remote_candidate, cricket::PortInterface::ORIGIN_THIS_PORT); 627 port->CreateConnection(remote_candidate, PortInterface::ORIGIN_THIS_PORT);
613 if (!connection) { 628 if (!connection) {
614 ASSERT(false); 629 ASSERT(false);
615 port->SendBindingErrorResponse(stun_msg, address, STUN_ERROR_SERVER_ERROR, 630 port->SendBindingErrorResponse(stun_msg, address, STUN_ERROR_SERVER_ERROR,
616 STUN_ERROR_REASON_SERVER_ERROR); 631 STUN_ERROR_REASON_SERVER_ERROR);
617 return; 632 return;
618 } 633 }
619 634
620 LOG(LS_INFO) << "Adding connection from " 635 LOG(LS_INFO) << "Adding connection from "
621 << (remote_candidate_is_new ? "peer reflexive" : "resurrected") 636 << (remote_candidate_is_new ? "peer reflexive" : "resurrected")
622 << " candidate: " << remote_candidate.ToString(); 637 << " candidate: " << remote_candidate.ToString();
(...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after
779 << connection->remote_candidate().ToString() 794 << connection->remote_candidate().ToString()
780 << "New remote candidate: " 795 << "New remote candidate: "
781 << remote_candidate.ToString(); 796 << remote_candidate.ToString();
782 return false; 797 return false;
783 } 798 }
784 } else { 799 } else {
785 PortInterface::CandidateOrigin origin = GetOrigin(port, origin_port); 800 PortInterface::CandidateOrigin origin = GetOrigin(port, origin_port);
786 801
787 // Don't create connection if this is a candidate we received in a 802 // Don't create connection if this is a candidate we received in a
788 // message and we are not allowed to make outgoing connections. 803 // message and we are not allowed to make outgoing connections.
789 if (origin == cricket::PortInterface::ORIGIN_MESSAGE && incoming_only_) 804 if (origin == PortInterface::ORIGIN_MESSAGE && incoming_only_)
790 return false; 805 return false;
791 806
792 connection = port->CreateConnection(remote_candidate, origin); 807 connection = port->CreateConnection(remote_candidate, origin);
793 if (!connection) 808 if (!connection)
794 return false; 809 return false;
795 810
796 AddConnection(connection); 811 AddConnection(connection);
797 812
798 LOG_J(LS_INFO, this) << "Created connection with origin=" << origin << ", (" 813 LOG_J(LS_INFO, this) << "Created connection with origin=" << origin << ", ("
799 << connections_.size() << " total)"; 814 << connections_.size() << " total)";
800 } 815 }
801 816
802 return true; 817 return true;
803 } 818 }
804 819
805 bool P2PTransportChannel::FindConnection( 820 bool P2PTransportChannel::FindConnection(Connection* connection) const {
806 cricket::Connection* connection) const {
807 std::vector<Connection*>::const_iterator citer = 821 std::vector<Connection*>::const_iterator citer =
808 std::find(connections_.begin(), connections_.end(), connection); 822 std::find(connections_.begin(), connections_.end(), connection);
809 return citer != connections_.end(); 823 return citer != connections_.end();
810 } 824 }
811 825
812 uint32_t P2PTransportChannel::GetRemoteCandidateGeneration( 826 uint32_t P2PTransportChannel::GetRemoteCandidateGeneration(
813 const Candidate& candidate) { 827 const Candidate& candidate) {
814 // If the candidate has a ufrag, use it to find the generation. 828 // If the candidate has a ufrag, use it to find the generation.
815 if (!candidate.username().empty()) { 829 if (!candidate.username().empty()) {
816 uint32_t generation = 0; 830 uint32_t generation = 0;
(...skipping 431 matching lines...) Expand 10 before | Expand all | Expand 10 after
1248 return conn->active(); 1262 return conn->active();
1249 } 1263 }
1250 1264
1251 // Returns the next pingable connection to ping. This will be the oldest 1265 // Returns the next pingable connection to ping. This will be the oldest
1252 // pingable connection unless we have a connected, writable connection that is 1266 // pingable connection unless we have a connected, writable connection that is
1253 // past the maximum acceptable ping delay. When reconnecting a TCP connection, 1267 // past the maximum acceptable ping delay. When reconnecting a TCP connection,
1254 // the best connection is disconnected, although still WRITABLE while 1268 // the best connection is disconnected, although still WRITABLE while
1255 // reconnecting. The newly created connection should be selected as the ping 1269 // reconnecting. The newly created connection should be selected as the ping
1256 // target to become writable instead. See the big comment in CompareConnections. 1270 // target to become writable instead. See the big comment in CompareConnections.
1257 Connection* P2PTransportChannel::FindNextPingableConnection() { 1271 Connection* P2PTransportChannel::FindNextPingableConnection() {
1272 if (connections_.empty()) {
1273 return nullptr;
1274 }
pthatcher1 2016/01/27 19:59:58 Why is this needed? Can't connection_ just handle
guoweis_webrtc 2016/02/29 18:03:00 Done.
1275
1258 uint32_t now = rtc::Time(); 1276 uint32_t now = rtc::Time();
1259 if (best_connection_ && best_connection_->connected() && 1277 if (best_connection_ && best_connection_->connected() &&
1260 best_connection_->writable() && 1278 best_connection_->writable() &&
1261 (best_connection_->last_ping_sent() + MAX_CURRENT_STRONG_DELAY <= now)) { 1279 (best_connection_->last_ping_sent() + MAX_CURRENT_STRONG_DELAY <= now)) {
1280 connections_.MarkConnectionPinged(best_connection_);
pthatcher1 2016/01/27 19:59:58 I don't think FindNextPingableConnection should do
guoweis_webrtc 2016/02/29 18:03:00 Removed this function.
1262 return best_connection_; 1281 return best_connection_;
1263 } 1282 }
1264 1283
1265 // First, find "triggered checks". We ping first those connections 1284 return connections_.FindNextPingableConnection(now);
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 } 1285 }
1296 1286
1297 // Apart from sending ping from |conn| this method also updates 1287 // Apart from sending ping from |conn| this method also updates
1298 // |use_candidate_attr| flag. The criteria to update this flag is 1288 // |use_candidate_attr| flag. The criteria to update this flag is
1299 // explained below. 1289 // explained below.
1300 // Set USE-CANDIDATE if doing ICE AND this channel is in CONTROLLING AND 1290 // Set USE-CANDIDATE if doing ICE AND this channel is in CONTROLLING AND
1301 // a) Channel is in FULL ICE AND 1291 // a) Channel is in FULL ICE AND
1302 // a.1) |conn| is the best connection OR 1292 // a.1) |conn| is the best connection OR
1303 // a.2) there is no best connection OR 1293 // a.2) there is no best connection OR
1304 // a.3) the best connection is unwritable OR 1294 // a.3) the best connection is unwritable OR
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after
1430 1420
1431 SignalSentPacket(this, sent_packet); 1421 SignalSentPacket(this, sent_packet);
1432 } 1422 }
1433 1423
1434 void P2PTransportChannel::OnReadyToSend(Connection* connection) { 1424 void P2PTransportChannel::OnReadyToSend(Connection* connection) {
1435 if (connection == best_connection_ && writable()) { 1425 if (connection == best_connection_ && writable()) {
1436 SignalReadyToSend(this); 1426 SignalReadyToSend(this);
1437 } 1427 }
1438 } 1428 }
1439 1429
1430 P2PTransportChannel::Connections::Connections(P2PTransportChannel* channel)
1431 : channel_(channel) {}
pthatcher1 2016/01/27 19:59:58 I don't like how the Connections class depends on
guoweis_webrtc 2016/02/29 18:03:00 Agree. Removed Connections and move these 2 to TC.
1432
1433 void P2PTransportChannel::Connections::enable_most_likely_first(bool enable) {
1434 ping_most_likely_first_ = enable;
1435 }
1436
1437 P2PTransportChannel::Connections::iterator
1438 P2PTransportChannel::Connections::erase(
1439 P2PTransportChannel::Connections::iterator pos) {
1440 pinged_connections_.erase(*pos);
1441 unpinged_connections_.erase(*pos);
1442 return Base::erase(pos);
1443 }
1444
1445 void P2PTransportChannel::Connections::push_back(Connection*& connection) {
1446 Base::push_back(connection);
1447 unpinged_connections_.insert(connection);
1448 }
1449
1450 Connection* P2PTransportChannel::Connections::FindNextPingableConnection(
1451 uint32_t now) {
1452 RTC_CHECK(size() ==
1453 pinged_connections_.size() + unpinged_connections_.size());
1454
1455 // If there is nothing pingable in the |unpinged_connections_|, copy over from
1456 // |pinged_connections_|.
1457 if (std::find_if(unpinged_connections_.begin(), unpinged_connections_.end(),
1458 [this, now](Connection* conn) {
1459 return channel_->IsPingable(conn, now);
1460 }) == unpinged_connections_.end()) {
1461 unpinged_connections_.insert(pinged_connections_.begin(),
1462 pinged_connections_.end());
1463 pinged_connections_.clear();
pthatcher1 2016/01/27 19:59:58 Shouldn't this happen after MarkConnectionPinged r
guoweis_webrtc 2016/02/29 18:03:00 If the unpinged_connections has only unpingable co
1464 }
1465
1466 // First, find "triggered checks". We ping first those connections
1467 // that have received a ping but have not sent a ping since receiving
1468 // it (last_received_ping > last_sent_ping). But we shouldn't do
1469 // triggered checks if the connection is already writable.
1470 Connection* oldest_needing_triggered_check = nullptr;
1471 for (auto conn : *this) {
1472 if (!channel_->IsPingable(conn, now)) {
1473 continue;
1474 }
1475 bool needs_triggered_check =
1476 (!conn->writable() &&
1477 conn->last_ping_received() > conn->last_ping_sent());
1478 if (needs_triggered_check &&
1479 (!oldest_needing_triggered_check ||
1480 (conn->last_ping_received() <
1481 oldest_needing_triggered_check->last_ping_received()))) {
1482 oldest_needing_triggered_check = conn;
1483 }
1484 }
pthatcher1 2016/01/27 19:59:58 I think having a separate FindOldestConnectionNeed
guoweis_webrtc 2016/02/29 18:03:00 Done.
1485
1486 if (oldest_needing_triggered_check) {
1487 LOG(LS_INFO) << "Selecting connection for triggered check: "
1488 << oldest_needing_triggered_check->ToString();
1489 MarkConnectionPinged(oldest_needing_triggered_check);
pthatcher1 2016/01/27 19:59:58 Again, I don't like that just finding it marks it
guoweis_webrtc 2016/02/29 18:03:00 Removed.
1490 return oldest_needing_triggered_check;
1491 }
1492
1493 Connection* conn_to_ping = nullptr;
1494 for (Connection* conn : unpinged_connections_) {
1495 if (!channel_->IsPingable(conn, now)) {
1496 continue;
1497 }
1498 if (!conn_to_ping || Compare(conn_to_ping, conn) == conn) {
1499 conn_to_ping = conn;
1500 }
1501 }
1502
1503 if (conn_to_ping) {
1504 MarkConnectionPinged(conn_to_ping);
1505 }
1506
1507 return conn_to_ping;
1508 }
1509
1510 void P2PTransportChannel::Connections::MarkConnectionPinged(
1511 Connection* connection) {
1512 if (pinged_connections_.insert(connection).second) {
1513 unpinged_connections_.erase(connection);
1514 }
1515 }
1516
1517 Connection* P2PTransportChannel::Connections::Compare(Connection* conn1,
1518 Connection* conn2) {
1519 RTC_DCHECK(conn1 != conn2);
1520 if (ping_most_likely_first_) {
1521 bool conn1_turn_turn = IsTurnTurn(conn1);
pthatcher1 2016/01/27 19:59:58 rr1 would be nicer, shorter name.
guoweis_webrtc 2016/02/29 18:03:00 Done.
1522 bool conn2_turn_turn = IsTurnTurn(conn2);
1523 if (conn1_turn_turn ^ conn2_turn_turn) {
1524 return conn1_turn_turn ? conn1 : conn2;
1525 }
1526 if (conn1_turn_turn && conn2_turn_turn) {
pthatcher1 2016/01/27 19:59:58 This would be more readable as: bool rr1 == IsRel
guoweis_webrtc 2016/02/29 18:03:00 Done.
1527 bool conn1_udp_relay =
1528 conn1->local_candidate().relay_protocol() == UDP_PROTOCOL_NAME;
1529 bool conn2_udp_relay =
1530 conn2->local_candidate().relay_protocol() == UDP_PROTOCOL_NAME;
1531 if (conn1_udp_relay ^ conn2_udp_relay) {
1532 return conn1_udp_relay ? conn1 : conn2;
1533 }
1534 }
1535 }
1536
1537 if (conn1->last_ping_sent() < conn2->last_ping_sent()) {
1538 return conn1;
1539 }
1540 if (conn1->last_ping_sent() > conn2->last_ping_sent()) {
1541 return conn2;
1542 }
pthatcher1 2016/01/27 19:59:58 And similarly, we could make a method for LeastRec
guoweis_webrtc 2016/02/29 18:03:00 Done.
1543
1544 // During the initial state when nothing has been pinged yet, return the first
1545 // one in the ordered |connections_|.
1546 return *(std::find_if(Base::begin(), Base::end(),
1547 [conn1, conn2](Connection* conn) {
1548 return conn == conn1 || conn == conn2;
1549 }));
1550 }
1551
1552 bool P2PTransportChannel::Connections::IsTurnTurn(Connection* conn) {
pthatcher1 2016/01/27 19:59:58 IsRelayToRelay would be a more accurate name.
guoweis_webrtc 2016/02/29 18:03:00 Done.
1553 return conn->local_candidate().type() == RELAY_PORT_TYPE &&
1554 conn->remote_candidate().type() == RELAY_PORT_TYPE;
1555 }
1556
1440 } // namespace cricket 1557 } // namespace cricket
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698