Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 14 matching lines...) Expand all Loading... | |
| 25 #include "webrtc/system_wrappers/include/field_trial.h" | 25 #include "webrtc/system_wrappers/include/field_trial.h" |
| 26 | 26 |
| 27 namespace { | 27 namespace { |
| 28 | 28 |
| 29 // messages for queuing up work for ourselves | 29 // messages for queuing up work for ourselves |
| 30 enum { MSG_SORT = 1, MSG_CHECK_AND_PING }; | 30 enum { MSG_SORT = 1, MSG_CHECK_AND_PING }; |
| 31 | 31 |
| 32 // The minimum improvement in RTT that justifies a switch. | 32 // The minimum improvement in RTT that justifies a switch. |
| 33 static const double kMinImprovement = 10; | 33 static const double kMinImprovement = 10; |
| 34 | 34 |
| 35 bool IsRelayRelay(cricket::Connection* conn) { | 35 bool IsRelayRelay(const cricket::Connection* conn) { |
| 36 return conn->local_candidate().type() == cricket::RELAY_PORT_TYPE && | 36 return conn->local_candidate().type() == cricket::RELAY_PORT_TYPE && |
| 37 conn->remote_candidate().type() == cricket::RELAY_PORT_TYPE; | 37 conn->remote_candidate().type() == cricket::RELAY_PORT_TYPE; |
| 38 } | 38 } |
| 39 | 39 |
| 40 bool IsUdp(cricket::Connection* conn) { | 40 bool IsUdp(cricket::Connection* conn) { |
| 41 return conn->local_candidate().relay_protocol() == cricket::UDP_PROTOCOL_NAME; | 41 return conn->local_candidate().relay_protocol() == cricket::UDP_PROTOCOL_NAME; |
| 42 } | 42 } |
| 43 | 43 |
| 44 cricket::PortInterface::CandidateOrigin GetOrigin(cricket::PortInterface* port, | 44 cricket::PortInterface::CandidateOrigin GetOrigin(cricket::PortInterface* port, |
| 45 cricket::PortInterface* origin_port) { | 45 cricket::PortInterface* origin_port) { |
| 46 if (!origin_port) | 46 if (!origin_port) |
| 47 return cricket::PortInterface::ORIGIN_MESSAGE; | 47 return cricket::PortInterface::ORIGIN_MESSAGE; |
| 48 else if (port == origin_port) | 48 else if (port == origin_port) |
| 49 return cricket::PortInterface::ORIGIN_THIS_PORT; | 49 return cricket::PortInterface::ORIGIN_THIS_PORT; |
| 50 else | 50 else |
| 51 return cricket::PortInterface::ORIGIN_OTHER_PORT; | 51 return cricket::PortInterface::ORIGIN_OTHER_PORT; |
| 52 } | 52 } |
| 53 | 53 |
| 54 // Compares two connections based only on the candidate and network information. | |
| 55 // Returns positive if |a| is better than |b|. | |
| 56 int CompareConnectionCandidates(cricket::Connection* a, | |
| 57 cricket::Connection* b) { | |
| 58 uint32_t a_cost = a->ComputeNetworkCost(); | |
| 59 uint32_t b_cost = b->ComputeNetworkCost(); | |
| 60 // Smaller cost is better. | |
| 61 if (a_cost < b_cost) { | |
| 62 return 1; | |
| 63 } | |
| 64 if (a_cost > b_cost) { | |
| 65 return -1; | |
| 66 } | |
| 67 | |
| 68 // Compare connection priority. Lower values get sorted last. | |
| 69 if (a->priority() > b->priority()) | |
| 70 return 1; | |
| 71 if (a->priority() < b->priority()) | |
| 72 return -1; | |
| 73 | |
| 74 // If we're still tied at this point, prefer a younger generation. | |
| 75 return (a->remote_candidate().generation() + a->port()->generation()) - | |
| 76 (b->remote_candidate().generation() + b->port()->generation()); | |
| 77 } | |
| 78 | |
| 79 // Compare two connections based on their writing, receiving, and connected | |
| 80 // states. | |
| 81 int CompareConnectionStates(cricket::Connection* a, cricket::Connection* b) { | |
| 82 // Sort based on write-state. Better states have lower values. | |
| 83 if (a->write_state() < b->write_state()) | |
| 84 return 1; | |
| 85 if (a->write_state() > b->write_state()) | |
| 86 return -1; | |
| 87 | |
| 88 // We prefer a receiving connection to a non-receiving, higher-priority | |
| 89 // connection when sorting connections and choosing which connection to | |
| 90 // switch to. | |
| 91 if (a->receiving() && !b->receiving()) | |
| 92 return 1; | |
| 93 if (!a->receiving() && b->receiving()) | |
| 94 return -1; | |
| 95 | |
| 96 // WARNING: Some complexity here about TCP reconnecting. | |
| 97 // When a TCP connection fails because of a TCP socket disconnecting, the | |
| 98 // active side of the connection will attempt to reconnect for 5 seconds while | |
| 99 // pretending to be writable (the connection is not set to the unwritable | |
| 100 // state). On the passive side, the connection also remains writable even | |
| 101 // though it is disconnected, and a new connection is created when the active | |
| 102 // side connects. At that point, there are two TCP connections on the passive | |
| 103 // side: 1. the old, disconnected one that is pretending to be writable, and | |
| 104 // 2. the new, connected one that is maybe not yet writable. For purposes of | |
| 105 // pruning, pinging, and selecting the best connection, we want to treat the | |
| 106 // new connection as "better" than the old one. We could add a method called | |
| 107 // something like Connection::ImReallyBadEvenThoughImWritable, but that is | |
| 108 // equivalent to the existing Connection::connected(), which we already have. | |
| 109 // So, in code throughout this file, we'll check whether the connection is | |
| 110 // connected() or not, and if it is not, treat it as "worse" than a connected | |
| 111 // one, even though it's writable. In the code below, we're doing so to make | |
| 112 // sure we treat a new writable connection as better than an old disconnected | |
| 113 // connection. | |
| 114 | |
| 115 // In the case where we reconnect TCP connections, the original best | |
| 116 // connection is disconnected without changing to WRITE_TIMEOUT. In this case, | |
| 117 // the new connection, when it becomes writable, should have higher priority. | |
| 118 if (a->write_state() == cricket::Connection::STATE_WRITABLE && | |
| 119 b->write_state() == cricket::Connection::STATE_WRITABLE) { | |
| 120 if (a->connected() && !b->connected()) { | |
| 121 return 1; | |
| 122 } | |
| 123 if (!a->connected() && b->connected()) { | |
| 124 return -1; | |
| 125 } | |
| 126 } | |
| 127 return 0; | |
| 128 } | |
| 129 | |
| 130 int CompareConnections(cricket::Connection* a, cricket::Connection* b) { | |
| 131 int state_cmp = CompareConnectionStates(a, b); | |
| 132 if (state_cmp != 0) { | |
| 133 return state_cmp; | |
| 134 } | |
| 135 // Compare the candidate information. | |
| 136 return CompareConnectionCandidates(a, b); | |
| 137 } | |
| 138 | |
| 139 // Wraps the comparison connection into a less than operator that puts higher | |
| 140 // priority writable connections first. | |
| 141 class ConnectionCompare { | |
| 142 public: | |
| 143 bool operator()(const cricket::Connection *ca, | |
| 144 const cricket::Connection *cb) { | |
| 145 cricket::Connection* a = const_cast<cricket::Connection*>(ca); | |
| 146 cricket::Connection* b = const_cast<cricket::Connection*>(cb); | |
| 147 | |
| 148 // Compare first on writability and static preferences. | |
| 149 int cmp = CompareConnections(a, b); | |
| 150 if (cmp > 0) | |
| 151 return true; | |
| 152 if (cmp < 0) | |
| 153 return false; | |
| 154 | |
| 155 // Otherwise, sort based on latency estimate. | |
| 156 return a->rtt() < b->rtt(); | |
| 157 | |
| 158 // Should we bother checking for the last connection that last received | |
| 159 // data? It would help rendezvous on the connection that is also receiving | |
| 160 // packets. | |
| 161 // | |
| 162 // TODO: Yes we should definitely do this. The TCP protocol gains | |
| 163 // efficiency by being used bidirectionally, as opposed to two separate | |
| 164 // unidirectional streams. This test should probably occur before | |
| 165 // comparison of local prefs (assuming combined prefs are the same). We | |
| 166 // need to be careful though, not to bounce back and forth with both sides | |
| 167 // trying to rendevous with the other. | |
| 168 } | |
| 169 }; | |
|
honghaiz3
2016/06/17 16:28:16
I think you don't need to put anything above this
Taylor Brandstetter
2016/06/20 17:15:45
I no longer need to, but it doesn't hurt, and it m
honghaiz3
2016/06/20 22:31:03
I don't see a reason of needing the transportchann
pthatcher1
2016/06/21 06:20:50
I think we should make these all member methods or
| |
| 170 | |
| 171 // Determines whether we should switch between two connections, based first on | |
| 172 // connection states, static preferences, and then (if those are equal) on | |
| 173 // latency estimates. | |
| 174 bool ShouldSwitch(cricket::Connection* a_conn, | |
| 175 cricket::Connection* b_conn, | |
| 176 cricket::IceRole ice_role) { | |
| 177 if (a_conn == b_conn) | |
| 178 return false; | |
| 179 | |
| 180 if (!a_conn || !b_conn) // don't think the latter should happen | |
| 181 return true; | |
| 182 | |
| 183 // We prefer to switch to a writable and receiving connection over a | |
| 184 // non-writable or non-receiving connection, even if the latter has | |
| 185 // been nominated by the controlling side. | |
| 186 int state_cmp = CompareConnectionStates(a_conn, b_conn); | |
| 187 if (state_cmp != 0) { | |
| 188 return state_cmp < 0; | |
| 189 } | |
| 190 if (ice_role == cricket::ICEROLE_CONTROLLED && a_conn->nominated()) { | |
| 191 LOG(LS_VERBOSE) << "Controlled side did not switch due to nominated status"; | |
| 192 return false; | |
| 193 } | |
| 194 | |
| 195 int prefs_cmp = CompareConnectionCandidates(a_conn, b_conn); | |
| 196 if (prefs_cmp != 0) { | |
| 197 return prefs_cmp < 0; | |
| 198 } | |
| 199 | |
| 200 return b_conn->rtt() <= a_conn->rtt() + kMinImprovement; | |
| 201 } | |
| 202 | |
| 203 } // unnamed namespace | 54 } // unnamed namespace |
| 204 | 55 |
| 205 namespace cricket { | 56 namespace cricket { |
| 206 | 57 |
| 207 // When the socket is unwritable, we will use 10 Kbps (ignoring IP+UDP headers) | 58 // When the socket is unwritable, we will use 10 Kbps (ignoring IP+UDP headers) |
| 208 // for pinging. When the socket is writable, we will use only 1 Kbps because | 59 // for pinging. When the socket is writable, we will use only 1 Kbps because |
| 209 // we don't want to degrade the quality on a modem. These numbers should work | 60 // we don't want to degrade the quality on a modem. These numbers should work |
| 210 // well on a 28.8K modem, which is the slowest connection on which the voice | 61 // well on a 28.8K modem, which is the slowest connection on which the voice |
| 211 // quality is reasonable at all. | 62 // quality is reasonable at all. |
| 212 static const int PING_PACKET_SIZE = 60 * 8; | 63 static const int PING_PACKET_SIZE = 60 * 8; |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 243 sort_dirty_(false), | 94 sort_dirty_(false), |
| 244 remote_ice_mode_(ICEMODE_FULL), | 95 remote_ice_mode_(ICEMODE_FULL), |
| 245 ice_role_(ICEROLE_UNKNOWN), | 96 ice_role_(ICEROLE_UNKNOWN), |
| 246 tiebreaker_(0), | 97 tiebreaker_(0), |
| 247 gathering_state_(kIceGatheringNew), | 98 gathering_state_(kIceGatheringNew), |
| 248 check_receiving_interval_(MIN_CHECK_RECEIVING_INTERVAL * 5), | 99 check_receiving_interval_(MIN_CHECK_RECEIVING_INTERVAL * 5), |
| 249 config_(MIN_CHECK_RECEIVING_INTERVAL * 50 /* receiving_timeout */, | 100 config_(MIN_CHECK_RECEIVING_INTERVAL * 50 /* receiving_timeout */, |
| 250 0 /* backup_connection_ping_interval */, | 101 0 /* backup_connection_ping_interval */, |
| 251 false /* gather_continually */, | 102 false /* gather_continually */, |
| 252 false /* prioritize_most_likely_candidate_pairs */, | 103 false /* prioritize_most_likely_candidate_pairs */, |
| 253 MAX_CURRENT_STRONG_INTERVAL /* max_strong_interval */) { | 104 MAX_CURRENT_STRONG_INTERVAL /* max_strong_interval */, |
| 105 true /* fully_relayed_createpermission_needed */) { | |
| 254 uint32_t weak_ping_interval = ::strtoul( | 106 uint32_t weak_ping_interval = ::strtoul( |
| 255 webrtc::field_trial::FindFullName("WebRTC-StunInterPacketDelay").c_str(), | 107 webrtc::field_trial::FindFullName("WebRTC-StunInterPacketDelay").c_str(), |
| 256 nullptr, 10); | 108 nullptr, 10); |
| 257 if (weak_ping_interval) { | 109 if (weak_ping_interval) { |
| 258 weak_ping_interval_ = static_cast<int>(weak_ping_interval); | 110 weak_ping_interval_ = static_cast<int>(weak_ping_interval); |
| 259 } | 111 } |
| 260 } | 112 } |
| 261 | 113 |
| 262 P2PTransportChannel::~P2PTransportChannel() { | 114 P2PTransportChannel::~P2PTransportChannel() { |
| 263 ASSERT(worker_thread_ == rtc::Thread::Current()); | 115 ASSERT(worker_thread_ == rtc::Thread::Current()); |
| (...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 431 config.prioritize_most_likely_candidate_pairs; | 283 config.prioritize_most_likely_candidate_pairs; |
| 432 LOG(LS_INFO) << "Set ping most likely connection to " | 284 LOG(LS_INFO) << "Set ping most likely connection to " |
| 433 << config_.prioritize_most_likely_candidate_pairs; | 285 << config_.prioritize_most_likely_candidate_pairs; |
| 434 | 286 |
| 435 if (config.max_strong_interval >= 0 && | 287 if (config.max_strong_interval >= 0 && |
| 436 config_.max_strong_interval != config.max_strong_interval) { | 288 config_.max_strong_interval != config.max_strong_interval) { |
| 437 config_.max_strong_interval = config.max_strong_interval; | 289 config_.max_strong_interval = config.max_strong_interval; |
| 438 LOG(LS_INFO) << "Set max strong interval to " | 290 LOG(LS_INFO) << "Set max strong interval to " |
| 439 << config_.max_strong_interval; | 291 << config_.max_strong_interval; |
| 440 } | 292 } |
| 293 | |
| 294 if (config.fully_relayed_createpermission_needed != | |
| 295 config_.fully_relayed_createpermission_needed) { | |
| 296 if (!connections_.empty()) { | |
| 297 LOG(LS_ERROR) << "Trying to change TURN-TURN CreatePermission needed " | |
| 298 << "while connections already exist!"; | |
| 299 } else { | |
| 300 config_.fully_relayed_createpermission_needed = | |
| 301 config.fully_relayed_createpermission_needed; | |
| 302 LOG(LS_INFO) << "Set fully-relayed CreatePermission needed to " | |
| 303 << config_.fully_relayed_createpermission_needed; | |
| 304 } | |
| 305 } | |
| 441 } | 306 } |
| 442 | 307 |
| 443 const IceConfig& P2PTransportChannel::config() const { | 308 const IceConfig& P2PTransportChannel::config() const { |
| 444 return config_; | 309 return config_; |
| 445 } | 310 } |
| 446 | 311 |
| 447 // Go into the state of processing candidates, and running in general | 312 // Go into the state of processing candidates, and running in general |
| 448 void P2PTransportChannel::Connect() { | 313 void P2PTransportChannel::Connect() { |
| 449 ASSERT(worker_thread_ == rtc::Thread::Current()); | 314 ASSERT(worker_thread_ == rtc::Thread::Current()); |
| 450 if (ice_ufrag_.empty() || ice_pwd_.empty()) { | 315 if (ice_ufrag_.empty() || ice_pwd_.empty()) { |
| (...skipping 226 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 677 return; | 542 return; |
| 678 } else { | 543 } else { |
| 679 ASSERT(false); | 544 ASSERT(false); |
| 680 port->SendBindingErrorResponse(stun_msg, address, | 545 port->SendBindingErrorResponse(stun_msg, address, |
| 681 STUN_ERROR_SERVER_ERROR, | 546 STUN_ERROR_SERVER_ERROR, |
| 682 STUN_ERROR_REASON_SERVER_ERROR); | 547 STUN_ERROR_REASON_SERVER_ERROR); |
| 683 return; | 548 return; |
| 684 } | 549 } |
| 685 } | 550 } |
| 686 | 551 |
| 687 Connection* connection = | 552 Connection* connection = port->CreateConnection( |
| 688 port->CreateConnection(remote_candidate, PortInterface::ORIGIN_THIS_PORT); | 553 remote_candidate, PortInterface::ORIGIN_THIS_PORT, config_); |
| 689 if (!connection) { | 554 if (!connection) { |
| 690 ASSERT(false); | 555 ASSERT(false); |
| 691 port->SendBindingErrorResponse(stun_msg, address, STUN_ERROR_SERVER_ERROR, | 556 port->SendBindingErrorResponse(stun_msg, address, STUN_ERROR_SERVER_ERROR, |
| 692 STUN_ERROR_REASON_SERVER_ERROR); | 557 STUN_ERROR_REASON_SERVER_ERROR); |
| 693 return; | 558 return; |
| 694 } | 559 } |
| 695 | 560 |
| 696 LOG(LS_INFO) << "Adding connection from " | 561 LOG(LS_INFO) << "Adding connection from " |
| 697 << (remote_candidate_is_new ? "peer reflexive" : "resurrected") | 562 << (remote_candidate_is_new ? "peer reflexive" : "resurrected") |
| 698 << " candidate: " << remote_candidate.ToString(); | 563 << " candidate: " << remote_candidate.ToString(); |
| (...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 860 Connection* connection = port->GetConnection(remote_candidate.address()); | 725 Connection* connection = port->GetConnection(remote_candidate.address()); |
| 861 if (connection == nullptr || | 726 if (connection == nullptr || |
| 862 connection->remote_candidate().generation() < | 727 connection->remote_candidate().generation() < |
| 863 remote_candidate.generation()) { | 728 remote_candidate.generation()) { |
| 864 // Don't create a connection if this is a candidate we received in a | 729 // Don't create a connection if this is a candidate we received in a |
| 865 // message and we are not allowed to make outgoing connections. | 730 // message and we are not allowed to make outgoing connections. |
| 866 PortInterface::CandidateOrigin origin = GetOrigin(port, origin_port); | 731 PortInterface::CandidateOrigin origin = GetOrigin(port, origin_port); |
| 867 if (origin == PortInterface::ORIGIN_MESSAGE && incoming_only_) { | 732 if (origin == PortInterface::ORIGIN_MESSAGE && incoming_only_) { |
| 868 return false; | 733 return false; |
| 869 } | 734 } |
| 870 Connection* connection = port->CreateConnection(remote_candidate, origin); | 735 Connection* connection = |
| 736 port->CreateConnection(remote_candidate, origin, config_); | |
| 871 if (!connection) { | 737 if (!connection) { |
| 872 return false; | 738 return false; |
| 873 } | 739 } |
| 874 AddConnection(connection); | 740 AddConnection(connection); |
| 875 LOG_J(LS_INFO, this) << "Created connection with origin=" << origin << ", (" | 741 LOG_J(LS_INFO, this) << "Created connection with origin=" << origin << ", (" |
| 876 << connections_.size() << " total)"; | 742 << connections_.size() << " total)"; |
| 877 return true; | 743 return true; |
| 878 } | 744 } |
| 879 | 745 |
| 880 // No new connection was created. | 746 // No new connection was created. |
| (...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1056 } | 922 } |
| 1057 | 923 |
| 1058 // Prepare for best candidate sorting. | 924 // Prepare for best candidate sorting. |
| 1059 void P2PTransportChannel::RequestSort() { | 925 void P2PTransportChannel::RequestSort() { |
| 1060 if (!sort_dirty_) { | 926 if (!sort_dirty_) { |
| 1061 worker_thread_->Post(RTC_FROM_HERE, this, MSG_SORT); | 927 worker_thread_->Post(RTC_FROM_HERE, this, MSG_SORT); |
| 1062 sort_dirty_ = true; | 928 sort_dirty_ = true; |
| 1063 } | 929 } |
| 1064 } | 930 } |
| 1065 | 931 |
| 932 // Compare two connections based on their writing, receiving, and connected | |
| 933 // states. | |
| 934 int P2PTransportChannel::CompareConnectionStates(const Connection* a, | |
| 935 const Connection* b) const { | |
| 936 // Sort based on write-state. Better states have lower values. | |
| 937 int write_state_cmp = | |
| 938 static_cast<int>(b->write_state()) - static_cast<int>(a->write_state()); | |
| 939 if (write_state_cmp != 0) { | |
| 940 return write_state_cmp; | |
| 941 } | |
| 942 | |
| 943 // We prefer a receiving connection to a non-receiving, higher-priority | |
| 944 // connection when sorting connections and choosing which connection to | |
| 945 // switch to. | |
| 946 if (a->receiving() && !b->receiving()) { | |
| 947 return 1; | |
| 948 } | |
| 949 if (!a->receiving() && b->receiving()) { | |
| 950 return -1; | |
| 951 } | |
| 952 | |
| 953 // WARNING: Some complexity here about TCP reconnecting. | |
| 954 // When a TCP connection fails because of a TCP socket disconnecting, the | |
| 955 // active side of the connection will attempt to reconnect for 5 seconds while | |
| 956 // pretending to be writable (the connection is not set to the unwritable | |
| 957 // state). On the passive side, the connection also remains writable even | |
| 958 // though it is disconnected, and a new connection is created when the active | |
| 959 // side connects. At that point, there are two TCP connections on the passive | |
| 960 // side: 1. the old, disconnected one that is pretending to be writable, and | |
| 961 // 2. the new, connected one that is maybe not yet writable. For purposes of | |
| 962 // pruning, pinging, and selecting the best connection, we want to treat the | |
| 963 // new connection as "better" than the old one. We could add a method called | |
| 964 // something like Connection::ImReallyBadEvenThoughImWritable, but that is | |
| 965 // equivalent to the existing Connection::connected(), which we already have. | |
| 966 // So, in code throughout this file, we'll check whether the connection is | |
| 967 // connected() or not, and if it is not, treat it as "worse" than a connected | |
| 968 // one, even though it's writable. In the code below, we're doing so to make | |
| 969 // sure we treat a new writable connection as better than an old disconnected | |
| 970 // connection. | |
| 971 | |
| 972 // In the case where we reconnect TCP connections, the original best | |
| 973 // connection is disconnected without changing to WRITE_TIMEOUT. In this case, | |
| 974 // the new connection, when it becomes writable, should have higher priority. | |
| 975 if (a->write_state() == Connection::STATE_WRITABLE && | |
| 976 b->write_state() == Connection::STATE_WRITABLE) { | |
| 977 if (a->connected() && !b->connected()) { | |
| 978 return 1; | |
| 979 } | |
| 980 if (!a->connected() && b->connected()) { | |
| 981 return -1; | |
| 982 } | |
| 983 } | |
| 984 return 0; | |
| 985 } | |
| 986 | |
| 987 // Compares two connections based only on the candidate and network information. | |
| 988 // Returns positive if |a| is better than |b|. | |
| 989 int P2PTransportChannel::CompareConnectionCandidates( | |
| 990 const Connection* a, | |
| 991 const Connection* b) const { | |
| 992 // Prefer lower network cost. | |
| 993 uint32_t a_cost = a->ComputeNetworkCost(); | |
| 994 uint32_t b_cost = b->ComputeNetworkCost(); | |
| 995 // Smaller cost is better. | |
| 996 if (a_cost < b_cost) { | |
| 997 return 1; | |
| 998 } | |
| 999 if (a_cost > b_cost) { | |
| 1000 return -1; | |
| 1001 } | |
| 1002 | |
| 1003 // Compare connection priority. Lower values get sorted last. | |
| 1004 if (a->priority() > b->priority()) { | |
| 1005 return 1; | |
| 1006 } | |
| 1007 if (a->priority() < b->priority()) { | |
| 1008 return -1; | |
| 1009 } | |
| 1010 | |
| 1011 // If we're still tied at this point, prefer a younger generation. | |
| 1012 // (Younger generation means a larger generation number). | |
| 1013 return (a->remote_candidate().generation() + a->port()->generation()) - | |
| 1014 (b->remote_candidate().generation() + b->port()->generation()); | |
| 1015 } | |
| 1016 | |
| 1017 int P2PTransportChannel::CompareConnections(const Connection* a, | |
| 1018 const Connection* b) const { | |
| 1019 // Compare first on writability and static preferences. | |
| 1020 int state_cmp = CompareConnectionStates(a, b); | |
| 1021 if (state_cmp != 0) { | |
| 1022 return state_cmp; | |
| 1023 } | |
| 1024 // Then compare the candidate information. | |
| 1025 int candidates_cmp = CompareConnectionCandidates(a, b); | |
| 1026 if (candidates_cmp != 0) { | |
| 1027 return candidates_cmp; | |
| 1028 } | |
| 1029 // Otherwise, compare based on latency estimate. | |
| 1030 return b->rtt() - a->rtt(); | |
| 1031 | |
| 1032 // Should we bother checking for the last connection that last received | |
| 1033 // data? It would help rendezvous on the connection that is also receiving | |
| 1034 // packets. | |
| 1035 // | |
| 1036 // TODO(deadbeef): Yes we should definitely do this. The TCP protocol gains | |
| 1037 // efficiency by being used bidirectionally, as opposed to two separate | |
| 1038 // unidirectional streams. This test should probably occur before | |
| 1039 // comparison of local prefs (assuming combined prefs are the same). We | |
| 1040 // need to be careful though, not to bounce back and forth with both sides | |
| 1041 // trying to rendevous with the other. | |
| 1042 } | |
| 1043 | |
| 1044 // Determines whether we should switch between two connections, based first on | |
| 1045 // connection states, static preferences, and then (if those are equal) on | |
| 1046 // latency estimates. | |
| 1047 bool P2PTransportChannel::ShouldSwitchSelectedConnection( | |
| 1048 const Connection* selected, | |
| 1049 const Connection* conn) const { | |
| 1050 if (selected == conn) { | |
| 1051 return false; | |
| 1052 } | |
| 1053 | |
| 1054 if (!selected || !conn) { // don't think the latter should happen | |
| 1055 return true; | |
| 1056 } | |
| 1057 | |
| 1058 // We prefer to switch to a writable and receiving connection over a | |
| 1059 // non-writable or non-receiving connection, even if the latter has | |
| 1060 // been nominated by the controlling side. | |
| 1061 int state_cmp = CompareConnectionStates(selected, conn); | |
| 1062 if (state_cmp != 0) { | |
| 1063 return state_cmp < 0; | |
| 1064 } | |
| 1065 if (ice_role_ == ICEROLE_CONTROLLED && selected->nominated()) { | |
| 1066 LOG(LS_VERBOSE) << "Controlled side did not switch due to nominated status"; | |
| 1067 return false; | |
| 1068 } | |
| 1069 | |
| 1070 int prefs_cmp = CompareConnectionCandidates(selected, conn); | |
| 1071 if (prefs_cmp != 0) { | |
| 1072 return prefs_cmp < 0; | |
| 1073 } | |
| 1074 | |
| 1075 return selected->rtt() - conn->rtt() >= kMinImprovement; | |
| 1076 } | |
| 1077 | |
| 1066 // Sort the available connections to find the best one. We also monitor | 1078 // Sort the available connections to find the best one. We also monitor |
| 1067 // the number of available connections and the current state. | 1079 // the number of available connections and the current state. |
| 1068 void P2PTransportChannel::SortConnections() { | 1080 void P2PTransportChannel::SortConnections() { |
| 1069 ASSERT(worker_thread_ == rtc::Thread::Current()); | 1081 ASSERT(worker_thread_ == rtc::Thread::Current()); |
| 1070 | 1082 |
| 1071 // Make sure the connection states are up-to-date since this affects how they | 1083 // Make sure the connection states are up-to-date since this affects how they |
| 1072 // will be sorted. | 1084 // will be sorted. |
| 1073 UpdateConnectionStates(); | 1085 UpdateConnectionStates(); |
| 1074 | 1086 |
| 1075 // Any changes after this point will require a re-sort. | 1087 // Any changes after this point will require a re-sort. |
| 1076 sort_dirty_ = false; | 1088 sort_dirty_ = false; |
| 1077 | 1089 |
| 1078 // Find the best alternative connection by sorting. It is important to note | 1090 // Find the best alternative connection by sorting. It is important to note |
| 1079 // that amongst equal preference, writable connections, this will choose the | 1091 // that amongst equal preference, writable connections, this will choose the |
| 1080 // one whose estimated latency is lowest. So it is the only one that we | 1092 // one whose estimated latency is lowest. So it is the only one that we |
| 1081 // need to consider switching to. | 1093 // need to consider switching to. |
| 1082 ConnectionCompare cmp; | 1094 std::stable_sort(connections_.begin(), connections_.end(), |
| 1083 std::stable_sort(connections_.begin(), connections_.end(), cmp); | 1095 [this](const Connection* a, const Connection* b) { |
| 1096 return CompareConnections(a, b) > 0; | |
| 1097 }); | |
| 1084 LOG(LS_VERBOSE) << "Sorting " << connections_.size() | 1098 LOG(LS_VERBOSE) << "Sorting " << connections_.size() |
| 1085 << " available connections:"; | 1099 << " available connections:"; |
| 1086 for (size_t i = 0; i < connections_.size(); ++i) { | 1100 for (size_t i = 0; i < connections_.size(); ++i) { |
| 1087 LOG(LS_VERBOSE) << connections_[i]->ToString(); | 1101 LOG(LS_VERBOSE) << connections_[i]->ToString(); |
| 1088 } | 1102 } |
| 1089 | 1103 |
| 1090 Connection* top_connection = | 1104 Connection* top_connection = |
| 1091 (connections_.size() > 0) ? connections_[0] : nullptr; | 1105 (connections_.size() > 0) ? connections_[0] : nullptr; |
| 1092 | 1106 |
| 1093 // If necessary, switch to the new choice. | 1107 // If necessary, switch to the new choice. |
| 1094 // Note that |top_connection| doesn't have to be writable to become the best | 1108 // Note that |top_connection| doesn't have to be writable to become the best |
| 1095 // connection although it will have higher priority if it is writable. | 1109 // connection although it will have higher priority if it is writable. |
| 1096 if (ShouldSwitch(best_connection_, top_connection, ice_role_)) { | 1110 if (ShouldSwitchSelectedConnection(best_connection_, top_connection)) { |
| 1097 LOG(LS_INFO) << "Switching best connection: " << top_connection->ToString(); | 1111 LOG(LS_INFO) << "Switching best connection: " << top_connection->ToString(); |
| 1098 SwitchBestConnectionTo(top_connection); | 1112 SwitchBestConnectionTo(top_connection); |
| 1099 } | 1113 } |
| 1100 | 1114 |
| 1101 // Controlled side can prune only if the best connection has been nominated. | 1115 // Controlled side can prune only if the best connection has been nominated. |
| 1102 // because otherwise it may delete the connection that will be selected by | 1116 // because otherwise it may delete the connection that will be selected by |
| 1103 // the controlling side. | 1117 // the controlling side. |
| 1104 if (ice_role_ == ICEROLE_CONTROLLING || best_nominated_connection()) { | 1118 if (ice_role_ == ICEROLE_CONTROLLING || best_nominated_connection()) { |
| 1105 PruneConnections(); | 1119 PruneConnections(); |
| 1106 } | 1120 } |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1175 << old_best_connection->ToString(); | 1189 << old_best_connection->ToString(); |
| 1176 } | 1190 } |
| 1177 LOG_J(LS_INFO, this) << "New best connection: " | 1191 LOG_J(LS_INFO, this) << "New best connection: " |
| 1178 << best_connection_->ToString(); | 1192 << best_connection_->ToString(); |
| 1179 SignalRouteChange(this, best_connection_->remote_candidate()); | 1193 SignalRouteChange(this, best_connection_->remote_candidate()); |
| 1180 // This is a temporary, but safe fix to webrtc issue 5705. | 1194 // This is a temporary, but safe fix to webrtc issue 5705. |
| 1181 // TODO(honghaiz): Make all EWOULDBLOCK error routed through the transport | 1195 // TODO(honghaiz): Make all EWOULDBLOCK error routed through the transport |
| 1182 // channel so that it knows whether the media channel is allowed to | 1196 // channel so that it knows whether the media channel is allowed to |
| 1183 // send; then it will only signal ready-to-send if the media channel | 1197 // send; then it will only signal ready-to-send if the media channel |
| 1184 // has been disallowed to send. | 1198 // has been disallowed to send. |
| 1185 if (best_connection_->writable()) { | 1199 if (best_connection_->presumed_writable()) { |
| 1186 SignalReadyToSend(this); | 1200 SignalReadyToSend(this); |
| 1187 } | 1201 } |
| 1188 } else { | 1202 } else { |
| 1189 LOG_J(LS_INFO, this) << "No best connection"; | 1203 LOG_J(LS_INFO, this) << "No best connection"; |
| 1190 } | 1204 } |
| 1191 // TODO(honghaiz): rename best_connection_ with selected_connection_ or | 1205 // TODO(honghaiz): rename best_connection_ with selected_connection_ or |
| 1192 // selected_candidate pair_. | 1206 // selected_candidate pair_. |
| 1193 SignalSelectedCandidatePairChanged(this, best_connection_, | 1207 SignalSelectedCandidatePairChanged(this, best_connection_, |
| 1194 last_sent_packet_id_); | 1208 last_sent_packet_id_); |
| 1195 } | 1209 } |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1230 RTC_DCHECK(state == STATE_CONNECTING || state == STATE_COMPLETED); | 1244 RTC_DCHECK(state == STATE_CONNECTING || state == STATE_COMPLETED); |
| 1231 break; | 1245 break; |
| 1232 default: | 1246 default: |
| 1233 RTC_DCHECK(false); | 1247 RTC_DCHECK(false); |
| 1234 break; | 1248 break; |
| 1235 } | 1249 } |
| 1236 state_ = state; | 1250 state_ = state; |
| 1237 SignalStateChanged(this); | 1251 SignalStateChanged(this); |
| 1238 } | 1252 } |
| 1239 | 1253 |
| 1240 bool writable = best_connection_ && best_connection_->writable(); | 1254 // If our best connection is "presumed writable" (TURN-TURN with no |
| 1241 set_writable(writable); | 1255 // CreatePermission required), act like we're already writable to the upper |
| 1256 // layers, so they can start media quicker. | |
| 1257 set_writable(best_connection_ && best_connection_->presumed_writable()); | |
| 1242 | 1258 |
| 1243 bool receiving = false; | 1259 bool receiving = false; |
| 1244 for (const Connection* connection : connections_) { | 1260 for (const Connection* connection : connections_) { |
| 1245 if (connection->receiving()) { | 1261 if (connection->receiving()) { |
| 1246 receiving = true; | 1262 receiving = true; |
| 1247 break; | 1263 break; |
| 1248 } | 1264 } |
| 1249 } | 1265 } |
| 1250 set_receiving(receiving); | 1266 set_receiving(receiving); |
| 1251 } | 1267 } |
| (...skipping 436 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1688 | 1704 |
| 1689 // During the initial state when nothing has been pinged yet, return the first | 1705 // During the initial state when nothing has been pinged yet, return the first |
| 1690 // one in the ordered |connections_|. | 1706 // one in the ordered |connections_|. |
| 1691 return *(std::find_if(connections_.begin(), connections_.end(), | 1707 return *(std::find_if(connections_.begin(), connections_.end(), |
| 1692 [conn1, conn2](Connection* conn) { | 1708 [conn1, conn2](Connection* conn) { |
| 1693 return conn == conn1 || conn == conn2; | 1709 return conn == conn1 || conn == conn2; |
| 1694 })); | 1710 })); |
| 1695 } | 1711 } |
| 1696 | 1712 |
| 1697 } // namespace cricket | 1713 } // namespace cricket |
| OLD | NEW |