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 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 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 static constexpr int a_is_better = 1; | |
| 55 static constexpr int b_is_better = -1; | |
| 54 // Compares two connections based only on the candidate and network information. | 56 // Compares two connections based only on the candidate and network information. |
| 55 // Returns positive if |a| is better than |b|. | 57 // Returns positive if |a| is better than |b|. |
| 56 int CompareConnectionCandidates(cricket::Connection* a, | 58 int CompareConnectionCandidates(const cricket::Connection* a, |
| 57 cricket::Connection* b) { | 59 const cricket::Connection* b) { |
| 58 uint32_t a_cost = a->ComputeNetworkCost(); | 60 uint32_t a_cost = a->ComputeNetworkCost(); |
| 59 uint32_t b_cost = b->ComputeNetworkCost(); | 61 uint32_t b_cost = b->ComputeNetworkCost(); |
| 60 // Smaller cost is better. | 62 // Smaller cost is better. |
| 61 if (a_cost < b_cost) { | 63 if (a_cost < b_cost) { |
| 62 return 1; | 64 return a_is_better; |
| 63 } | 65 } |
| 64 if (a_cost > b_cost) { | 66 if (a_cost > b_cost) { |
| 65 return -1; | 67 return b_is_better; |
| 66 } | 68 } |
| 67 | 69 |
| 68 // Compare connection priority. Lower values get sorted last. | 70 // Compare connection priority. Lower values get sorted last. |
| 69 if (a->priority() > b->priority()) | 71 if (a->priority() > b->priority()) { |
| 70 return 1; | 72 return a_is_better; |
| 71 if (a->priority() < b->priority()) | 73 } |
| 72 return -1; | 74 if (a->priority() < b->priority()) { |
| 75 return b_is_better; | |
| 76 } | |
| 73 | 77 |
| 74 // If we're still tied at this point, prefer a younger generation. | 78 // If we're still tied at this point, prefer a younger generation. |
| 75 return (a->remote_candidate().generation() + a->port()->generation()) - | 79 return (a->remote_candidate().generation() + a->port()->generation()) - |
| 76 (b->remote_candidate().generation() + b->port()->generation()); | 80 (b->remote_candidate().generation() + b->port()->generation()); |
| 77 } | 81 } |
| 78 | 82 |
| 79 // Compare two connections based on their writing, receiving, and connected | 83 // Compare two connections based on their writing, receiving, and connected |
| 80 // states. | 84 // states. |
| 81 int CompareConnectionStates(cricket::Connection* a, cricket::Connection* b) { | 85 int CompareConnectionStates(const cricket::Connection* a, |
| 86 const cricket::Connection* b) { | |
| 82 // Sort based on write-state. Better states have lower values. | 87 // Sort based on write-state. Better states have lower values. |
| 83 if (a->write_state() < b->write_state()) | 88 if (a->write_state() < b->write_state()) |
| 84 return 1; | 89 return a_is_better; |
| 85 if (a->write_state() > b->write_state()) | 90 if (a->write_state() > b->write_state()) |
| 86 return -1; | 91 return b_is_better; |
| 87 | 92 |
| 88 // We prefer a receiving connection to a non-receiving, higher-priority | 93 // We prefer a receiving connection to a non-receiving, higher-priority |
| 89 // connection when sorting connections and choosing which connection to | 94 // connection when sorting connections and choosing which connection to |
| 90 // switch to. | 95 // switch to. |
| 91 if (a->receiving() && !b->receiving()) | 96 if (a->receiving() && !b->receiving()) |
| 92 return 1; | 97 return a_is_better; |
| 93 if (!a->receiving() && b->receiving()) | 98 if (!a->receiving() && b->receiving()) |
| 94 return -1; | 99 return b_is_better; |
| 95 | 100 |
| 96 // WARNING: Some complexity here about TCP reconnecting. | 101 // WARNING: Some complexity here about TCP reconnecting. |
| 97 // When a TCP connection fails because of a TCP socket disconnecting, the | 102 // 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 | 103 // 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 | 104 // pretending to be writable (the connection is not set to the unwritable |
| 100 // state). On the passive side, the connection also remains writable even | 105 // 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 | 106 // 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 | 107 // 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 | 108 // 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 | 109 // 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 | 110 // pruning, pinging, and selecting the connection to use, we want to treat the |
| 106 // new connection as "better" than the old one. We could add a method called | 111 // new connection as "better" than the old one. We could add a method called |
| 107 // something like Connection::ImReallyBadEvenThoughImWritable, but that is | 112 // something like Connection::ImReallyBadEvenThoughImWritable, but that is |
| 108 // equivalent to the existing Connection::connected(), which we already have. | 113 // equivalent to the existing Connection::connected(), which we already have. |
| 109 // So, in code throughout this file, we'll check whether the connection is | 114 // 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 | 115 // 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 | 116 // 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 | 117 // sure we treat a new writable connection as better than an old disconnected |
| 113 // connection. | 118 // connection. |
| 114 | 119 |
| 115 // In the case where we reconnect TCP connections, the original best | 120 // In the case where we reconnect TCP connections, the original best |
| 116 // connection is disconnected without changing to WRITE_TIMEOUT. In this case, | 121 // connection is disconnected without changing to WRITE_TIMEOUT. In this case, |
| 117 // the new connection, when it becomes writable, should have higher priority. | 122 // the new connection, when it becomes writable, should have higher priority. |
| 118 if (a->write_state() == cricket::Connection::STATE_WRITABLE && | 123 if (a->write_state() == cricket::Connection::STATE_WRITABLE && |
| 119 b->write_state() == cricket::Connection::STATE_WRITABLE) { | 124 b->write_state() == cricket::Connection::STATE_WRITABLE) { |
| 120 if (a->connected() && !b->connected()) { | 125 if (a->connected() && !b->connected()) { |
| 121 return 1; | 126 return a_is_better; |
| 122 } | 127 } |
| 123 if (!a->connected() && b->connected()) { | 128 if (!a->connected() && b->connected()) { |
| 124 return -1; | 129 return b_is_better; |
| 125 } | 130 } |
| 126 } | 131 } |
| 127 return 0; | 132 return 0; |
| 128 } | 133 } |
| 129 | 134 |
| 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 }; | |
| 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 | 135 } // unnamed namespace |
| 204 | 136 |
| 205 namespace cricket { | 137 namespace cricket { |
| 206 | 138 |
| 207 // When the socket is unwritable, we will use 10 Kbps (ignoring IP+UDP headers) | 139 // 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 | 140 // 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 | 141 // 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 | 142 // well on a 28.8K modem, which is the slowest connection on which the voice |
| 211 // quality is reasonable at all. | 143 // quality is reasonable at all. |
| 212 static const int PING_PACKET_SIZE = 60 * 8; | 144 static const int PING_PACKET_SIZE = 60 * 8; |
| 213 // STRONG_PING_INTERVAL (480ms) is applied when the best connection is both | 145 // STRONG_PING_INTERVAL (480ms) is applied when the selected connection is both |
| 214 // writable and receiving. | 146 // writable and receiving. |
| 215 static const int STRONG_PING_INTERVAL = 1000 * PING_PACKET_SIZE / 1000; | 147 static const int STRONG_PING_INTERVAL = 1000 * PING_PACKET_SIZE / 1000; |
| 216 // WEAK_PING_INTERVAL (48ms) is applied when the best connection is either not | 148 // WEAK_PING_INTERVAL (48ms) is applied when the selected connection is either |
| 217 // writable or not receiving. | 149 // not writable or not receiving. |
| 218 const int WEAK_PING_INTERVAL = 1000 * PING_PACKET_SIZE / 10000; | 150 const int WEAK_PING_INTERVAL = 1000 * PING_PACKET_SIZE / 10000; |
| 219 | 151 |
| 220 // Writable connections are pinged at a faster rate while stabilizing. | 152 // Writable connections are pinged at a faster rate while stabilizing. |
| 221 const int STABILIZING_WRITABLE_CONNECTION_PING_INTERVAL = 900; // ms | 153 const int STABILIZING_WRITABLE_CONNECTION_PING_INTERVAL = 900; // ms |
| 222 | 154 |
| 223 // Writable connections are pinged at a slower rate once stabilized. | 155 // Writable connections are pinged at a slower rate once stabilized. |
| 224 const int STABLE_WRITABLE_CONNECTION_PING_INTERVAL = 2500; // ms | 156 const int STABLE_WRITABLE_CONNECTION_PING_INTERVAL = 2500; // ms |
| 225 | 157 |
| 226 static const int MIN_CHECK_RECEIVING_INTERVAL = 50; // ms | 158 static const int MIN_CHECK_RECEIVING_INTERVAL = 50; // ms |
| 227 | 159 |
| 228 P2PTransportChannel::P2PTransportChannel(const std::string& transport_name, | 160 P2PTransportChannel::P2PTransportChannel(const std::string& transport_name, |
| 229 int component, | 161 int component, |
| 230 P2PTransport* transport, | 162 P2PTransport* transport, |
| 231 PortAllocator* allocator) | 163 PortAllocator* allocator) |
| 232 : P2PTransportChannel(transport_name, component, allocator) {} | 164 : P2PTransportChannel(transport_name, component, allocator) {} |
| 233 | 165 |
| 234 P2PTransportChannel::P2PTransportChannel(const std::string& transport_name, | 166 P2PTransportChannel::P2PTransportChannel(const std::string& transport_name, |
| 235 int component, | 167 int component, |
| 236 PortAllocator* allocator) | 168 PortAllocator* allocator) |
| 237 : TransportChannelImpl(transport_name, component), | 169 : TransportChannelImpl(transport_name, component), |
| 238 allocator_(allocator), | 170 allocator_(allocator), |
| 239 worker_thread_(rtc::Thread::Current()), | 171 worker_thread_(rtc::Thread::Current()), |
| 240 incoming_only_(false), | 172 incoming_only_(false), |
| 241 error_(0), | 173 error_(0), |
| 242 best_connection_(NULL), | |
| 243 pending_best_connection_(NULL), | |
| 244 sort_dirty_(false), | 174 sort_dirty_(false), |
| 245 remote_ice_mode_(ICEMODE_FULL), | 175 remote_ice_mode_(ICEMODE_FULL), |
| 246 ice_role_(ICEROLE_UNKNOWN), | 176 ice_role_(ICEROLE_UNKNOWN), |
| 247 tiebreaker_(0), | 177 tiebreaker_(0), |
| 248 gathering_state_(kIceGatheringNew), | 178 gathering_state_(kIceGatheringNew), |
| 249 check_receiving_interval_(MIN_CHECK_RECEIVING_INTERVAL * 5), | 179 check_receiving_interval_(MIN_CHECK_RECEIVING_INTERVAL * 5), |
| 250 config_(MIN_CHECK_RECEIVING_INTERVAL * 50 /* receiving_timeout */, | 180 config_(MIN_CHECK_RECEIVING_INTERVAL * 50 /* receiving_timeout */, |
| 251 0 /* backup_connection_ping_interval */, | 181 0 /* backup_connection_ping_interval */, |
| 252 false /* gather_continually */, | 182 false /* gather_continually */, |
| 253 false /* prioritize_most_likely_candidate_pairs */, | 183 false /* prioritize_most_likely_candidate_pairs */, |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 296 connection->SignalReadyToSend.connect( | 226 connection->SignalReadyToSend.connect( |
| 297 this, &P2PTransportChannel::OnReadyToSend); | 227 this, &P2PTransportChannel::OnReadyToSend); |
| 298 connection->SignalStateChange.connect( | 228 connection->SignalStateChange.connect( |
| 299 this, &P2PTransportChannel::OnConnectionStateChange); | 229 this, &P2PTransportChannel::OnConnectionStateChange); |
| 300 connection->SignalDestroyed.connect( | 230 connection->SignalDestroyed.connect( |
| 301 this, &P2PTransportChannel::OnConnectionDestroyed); | 231 this, &P2PTransportChannel::OnConnectionDestroyed); |
| 302 connection->SignalNominated.connect(this, &P2PTransportChannel::OnNominated); | 232 connection->SignalNominated.connect(this, &P2PTransportChannel::OnNominated); |
| 303 had_connection_ = true; | 233 had_connection_ = true; |
| 304 } | 234 } |
| 305 | 235 |
| 236 int P2PTransportChannel::CompareConnections( | |
| 237 const cricket::Connection* a, | |
| 238 const cricket::Connection* b) const { | |
| 239 RTC_CHECK(a != nullptr); | |
| 240 RTC_CHECK(b != nullptr); | |
| 241 | |
| 242 // We prefer to switch to a writable and receiving connection over a | |
| 243 // non-writable or non-receiving connection, even if the latter has | |
| 244 // been nominated by the controlling side. | |
| 245 int state_cmp = CompareConnectionStates(a, b); | |
| 246 if (state_cmp != 0) { | |
| 247 return state_cmp; | |
| 248 } | |
| 249 | |
| 250 if (ice_role_ == cricket::ICEROLE_CONTROLLED) { | |
| 251 // Compare the connections based on the nomination states and the last data | |
| 252 // received time if this is on the controlled side. | |
| 253 if (a->nominated() != b->nominated()) { | |
| 254 return b->nominated() ? -1 : 1; | |
| 255 } | |
| 256 | |
| 257 if (a->last_data_received() > b->last_data_received()) { | |
| 258 return 1; | |
| 259 } | |
| 260 if (a->last_data_received() < b->last_data_received()) { | |
| 261 return -1; | |
| 262 } | |
|
pthatcher1
2016/06/22 22:32:32
These could use the a_is_better, b_is_better.
honghaiz3
2016/06/23 18:29:22
Done.
| |
| 263 } | |
| 264 | |
| 265 // Compare the network cost and priority. | |
| 266 return CompareConnectionCandidates(a, b); | |
| 267 } | |
| 268 | |
| 269 // Determines whether we should switch the selected connection to | |
| 270 // |new_connection| based the writable/receiving state, the nomination state, | |
| 271 // and the last data received time. This prevents the controlled side from | |
| 272 // switching the selected connection too frequently when the controlling side | |
| 273 // is doing aggressive nominations. The precedence of the connection switching | |
| 274 // criteria is as follows: | |
| 275 // i) write/receiving/connected states | |
| 276 // ii) For controlled side, | |
| 277 // a) nomination state, | |
| 278 // b) last data received time. | |
| 279 // iii) Lower cost / higher priority. | |
| 280 // iv) rtt. | |
| 281 // TODO(honghaiz): Stop the aggressive nomination on the controlling side and | |
| 282 // implement the ice-renomination option. | |
| 283 bool P2PTransportChannel::ShouldSwitchSelectedConnection( | |
| 284 cricket::Connection* new_connection) const { | |
| 285 if (!new_connection || selected_connection_ == new_connection) { | |
| 286 return false; | |
| 287 } | |
| 288 | |
| 289 if (selected_connection_ == nullptr) { | |
| 290 return true; | |
| 291 } | |
| 292 | |
| 293 int cmp = CompareConnections(selected_connection_, new_connection); | |
| 294 if (cmp != 0) { | |
| 295 return cmp < 0; | |
| 296 } | |
| 297 | |
| 298 // If everything else is the same, switch only if rtt has improved by | |
| 299 // a margin. | |
| 300 return new_connection->rtt() <= selected_connection_->rtt() - kMinImprovement; | |
| 301 } | |
| 302 | |
| 306 void P2PTransportChannel::SetIceRole(IceRole ice_role) { | 303 void P2PTransportChannel::SetIceRole(IceRole ice_role) { |
| 307 ASSERT(worker_thread_ == rtc::Thread::Current()); | 304 ASSERT(worker_thread_ == rtc::Thread::Current()); |
| 308 if (ice_role_ != ice_role) { | 305 if (ice_role_ != ice_role) { |
| 309 ice_role_ = ice_role; | 306 ice_role_ = ice_role; |
| 310 for (PortInterface* port : ports_) { | 307 for (PortInterface* port : ports_) { |
| 311 port->SetIceRole(ice_role); | 308 port->SetIceRole(ice_role); |
| 312 } | 309 } |
| 313 // Update role on removed ports as well, because they may still have | 310 // Update role on removed ports as well, because they may still have |
| 314 // connections alive that should be using the correct role. | 311 // connections alive that should be using the correct role. |
| 315 for (PortInterface* port : removed_ports_) { | 312 for (PortInterface* port : removed_ports_) { |
| (...skipping 414 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 730 return nullptr; | 727 return nullptr; |
| 731 } | 728 } |
| 732 *generation = params.rend() - it - 1; | 729 *generation = params.rend() - it - 1; |
| 733 return &(*it); | 730 return &(*it); |
| 734 } | 731 } |
| 735 | 732 |
| 736 void P2PTransportChannel::OnNominated(Connection* conn) { | 733 void P2PTransportChannel::OnNominated(Connection* conn) { |
| 737 ASSERT(worker_thread_ == rtc::Thread::Current()); | 734 ASSERT(worker_thread_ == rtc::Thread::Current()); |
| 738 ASSERT(ice_role_ == ICEROLE_CONTROLLED); | 735 ASSERT(ice_role_ == ICEROLE_CONTROLLED); |
| 739 | 736 |
| 740 if (conn->write_state() == Connection::STATE_WRITABLE) { | 737 if (selected_connection_ == conn) { |
| 741 if (best_connection_ != conn) { | 738 return; |
| 742 pending_best_connection_ = NULL; | |
| 743 LOG(LS_INFO) << "Switching best connection on controlled side: " | |
| 744 << conn->ToString(); | |
| 745 SwitchBestConnectionTo(conn); | |
| 746 // Now we have selected the best connection, time to prune other existing | |
| 747 // connections and update the read/write state of the channel. | |
| 748 RequestSort(); | |
| 749 } | |
| 750 } else { | |
| 751 LOG(LS_INFO) << "Not switching the best connection on controlled side yet," | |
| 752 << " because it's not writable: " << conn->ToString(); | |
| 753 pending_best_connection_ = conn; | |
| 754 } | 739 } |
| 740 | |
| 741 if (!ShouldSwitchSelectedConnection(conn)) { | |
| 742 LOG(LS_INFO) | |
| 743 << "Not switching the selected connection on controlled side yet: " | |
| 744 << conn->ToString(); | |
| 745 return; | |
| 746 } | |
| 747 | |
| 748 LOG(LS_INFO) | |
| 749 << "Switching selected connection on controlled side due to nomination: " | |
| 750 << conn->ToString(); | |
| 751 SwitchSelectedConnection(conn); | |
| 752 // Now that we have selected a connection, it is time to prune other | |
| 753 // connections and update the read/write state of the channel. | |
| 754 RequestSort(); | |
| 755 } | 755 } |
| 756 | 756 |
| 757 void P2PTransportChannel::AddRemoteCandidate(const Candidate& candidate) { | 757 void P2PTransportChannel::AddRemoteCandidate(const Candidate& candidate) { |
| 758 ASSERT(worker_thread_ == rtc::Thread::Current()); | 758 ASSERT(worker_thread_ == rtc::Thread::Current()); |
| 759 | 759 |
| 760 uint32_t generation = GetRemoteCandidateGeneration(candidate); | 760 uint32_t generation = GetRemoteCandidateGeneration(candidate); |
| 761 // If a remote candidate with a previous generation arrives, drop it. | 761 // If a remote candidate with a previous generation arrives, drop it. |
| 762 if (generation < remote_ice_generation()) { | 762 if (generation < remote_ice_generation()) { |
| 763 LOG(LS_WARNING) << "Dropping a remote candidate because its ufrag " | 763 LOG(LS_WARNING) << "Dropping a remote candidate because its ufrag " |
| 764 << candidate.username() | 764 << candidate.username() |
| (...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 994 ASSERT(worker_thread_ == rtc::Thread::Current()); | 994 ASSERT(worker_thread_ == rtc::Thread::Current()); |
| 995 | 995 |
| 996 const auto& found = options_.find(opt); | 996 const auto& found = options_.find(opt); |
| 997 if (found == options_.end()) { | 997 if (found == options_.end()) { |
| 998 return false; | 998 return false; |
| 999 } | 999 } |
| 1000 *value = found->second; | 1000 *value = found->second; |
| 1001 return true; | 1001 return true; |
| 1002 } | 1002 } |
| 1003 | 1003 |
| 1004 // Send data to the other side, using our best connection. | 1004 // Send data to the other side, using our selected connection. |
| 1005 int P2PTransportChannel::SendPacket(const char *data, size_t len, | 1005 int P2PTransportChannel::SendPacket(const char *data, size_t len, |
| 1006 const rtc::PacketOptions& options, | 1006 const rtc::PacketOptions& options, |
| 1007 int flags) { | 1007 int flags) { |
| 1008 ASSERT(worker_thread_ == rtc::Thread::Current()); | 1008 ASSERT(worker_thread_ == rtc::Thread::Current()); |
| 1009 if (flags != 0) { | 1009 if (flags != 0) { |
| 1010 error_ = EINVAL; | 1010 error_ = EINVAL; |
| 1011 return -1; | 1011 return -1; |
| 1012 } | 1012 } |
| 1013 if (best_connection_ == NULL) { | 1013 if (selected_connection_ == NULL) { |
| 1014 error_ = EWOULDBLOCK; | 1014 error_ = EWOULDBLOCK; |
| 1015 return -1; | 1015 return -1; |
| 1016 } | 1016 } |
| 1017 | 1017 |
| 1018 last_sent_packet_id_ = options.packet_id; | 1018 last_sent_packet_id_ = options.packet_id; |
| 1019 int sent = best_connection_->Send(data, len, options); | 1019 int sent = selected_connection_->Send(data, len, options); |
| 1020 if (sent <= 0) { | 1020 if (sent <= 0) { |
| 1021 ASSERT(sent < 0); | 1021 ASSERT(sent < 0); |
| 1022 error_ = best_connection_->GetError(); | 1022 error_ = selected_connection_->GetError(); |
| 1023 } | 1023 } |
| 1024 return sent; | 1024 return sent; |
| 1025 } | 1025 } |
| 1026 | 1026 |
| 1027 bool P2PTransportChannel::GetStats(ConnectionInfos *infos) { | 1027 bool P2PTransportChannel::GetStats(ConnectionInfos *infos) { |
| 1028 ASSERT(worker_thread_ == rtc::Thread::Current()); | 1028 ASSERT(worker_thread_ == rtc::Thread::Current()); |
| 1029 // Gather connection infos. | 1029 // Gather connection infos. |
| 1030 infos->clear(); | 1030 infos->clear(); |
| 1031 | 1031 |
| 1032 for (Connection* connection : connections_) { | 1032 for (Connection* connection : connections_) { |
| 1033 ConnectionInfo info = connection->stats(); | 1033 ConnectionInfo info = connection->stats(); |
| 1034 info.best_connection = (best_connection_ == connection); | 1034 info.best_connection = (selected_connection_ == connection); |
| 1035 info.receiving = connection->receiving(); | 1035 info.receiving = connection->receiving(); |
| 1036 info.writable = (connection->write_state() == Connection::STATE_WRITABLE); | 1036 info.writable = (connection->write_state() == Connection::STATE_WRITABLE); |
| 1037 info.timeout = | 1037 info.timeout = |
| 1038 (connection->write_state() == Connection::STATE_WRITE_TIMEOUT); | 1038 (connection->write_state() == Connection::STATE_WRITE_TIMEOUT); |
| 1039 info.new_connection = !connection->reported(); | 1039 info.new_connection = !connection->reported(); |
| 1040 connection->set_reported(true); | 1040 connection->set_reported(true); |
| 1041 info.rtt = connection->rtt(); | 1041 info.rtt = connection->rtt(); |
| 1042 info.local_candidate = connection->local_candidate(); | 1042 info.local_candidate = connection->local_candidate(); |
| 1043 info.remote_candidate = connection->remote_candidate(); | 1043 info.remote_candidate = connection->remote_candidate(); |
| 1044 info.key = connection; | 1044 info.key = connection; |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1083 // will be sorted. | 1083 // will be sorted. |
| 1084 UpdateConnectionStates(); | 1084 UpdateConnectionStates(); |
| 1085 | 1085 |
| 1086 // Any changes after this point will require a re-sort. | 1086 // Any changes after this point will require a re-sort. |
| 1087 sort_dirty_ = false; | 1087 sort_dirty_ = false; |
| 1088 | 1088 |
| 1089 // Find the best alternative connection by sorting. It is important to note | 1089 // Find the best alternative connection by sorting. It is important to note |
| 1090 // that amongst equal preference, writable connections, this will choose the | 1090 // that amongst equal preference, writable connections, this will choose the |
| 1091 // one whose estimated latency is lowest. So it is the only one that we | 1091 // one whose estimated latency is lowest. So it is the only one that we |
| 1092 // need to consider switching to. | 1092 // need to consider switching to. |
| 1093 ConnectionCompare cmp; | 1093 std::stable_sort( |
| 1094 std::stable_sort(connections_.begin(), connections_.end(), cmp); | 1094 connections_.begin(), connections_.end(), |
| 1095 [this](const cricket::Connection* a, const cricket::Connection* b) { | |
| 1096 int cmp = CompareConnections(a, b); | |
| 1097 if (cmp != 0) { | |
| 1098 return cmp > 0; | |
| 1099 } | |
| 1100 | |
| 1101 // Otherwise, sort based on latency estimate. | |
| 1102 return a->rtt() < b->rtt(); | |
| 1103 }); | |
| 1095 LOG(LS_VERBOSE) << "Sorting " << connections_.size() | 1104 LOG(LS_VERBOSE) << "Sorting " << connections_.size() |
| 1096 << " available connections:"; | 1105 << " available connections:"; |
| 1097 for (size_t i = 0; i < connections_.size(); ++i) { | 1106 for (size_t i = 0; i < connections_.size(); ++i) { |
| 1098 LOG(LS_VERBOSE) << connections_[i]->ToString(); | 1107 LOG(LS_VERBOSE) << connections_[i]->ToString(); |
| 1099 } | 1108 } |
| 1100 | 1109 |
| 1101 Connection* top_connection = | 1110 Connection* top_connection = |
| 1102 (connections_.size() > 0) ? connections_[0] : nullptr; | 1111 (connections_.size() > 0) ? connections_[0] : nullptr; |
| 1103 | 1112 |
| 1104 // If necessary, switch to the new choice. | 1113 // If necessary, switch to the new choice. Note that |top_connection| doesn't |
| 1105 // Note that |top_connection| doesn't have to be writable to become the best | 1114 // have to be writable to become the selected connection although it will |
| 1106 // connection although it will have higher priority if it is writable. | 1115 // have higher priority if it is writable. |
| 1107 if (ShouldSwitch(best_connection_, top_connection, ice_role_)) { | 1116 if (ShouldSwitchSelectedConnection(top_connection)) { |
| 1108 LOG(LS_INFO) << "Switching best connection: " << top_connection->ToString(); | 1117 LOG(LS_INFO) << "Switching selected connection after sorting: " |
| 1109 SwitchBestConnectionTo(top_connection); | 1118 << top_connection->ToString(); |
| 1119 SwitchSelectedConnection(top_connection); | |
| 1110 } | 1120 } |
| 1111 | 1121 |
| 1112 // Controlled side can prune only if the best connection has been nominated. | 1122 // The controlled side can prune only if the selected connection has been |
| 1113 // because otherwise it may delete the connection that will be selected by | 1123 // nominated because otherwise it may prune the connection that will be |
| 1114 // the controlling side. | 1124 // selected by the controlling side. |
| 1115 if (ice_role_ == ICEROLE_CONTROLLING || best_nominated_connection()) { | 1125 // TODO(honghaiz): This is not enough to prevent a connection from being |
| 1126 // pruned too early because with aggressive nomination, the controlling side | |
| 1127 // will nominate every connection until it becomes writable. | |
| 1128 if (ice_role_ == ICEROLE_CONTROLLING || | |
| 1129 (selected_connection_ && selected_connection_->nominated())) { | |
| 1116 PruneConnections(); | 1130 PruneConnections(); |
| 1117 } | 1131 } |
| 1118 | 1132 |
| 1119 // Check if all connections are timedout. | 1133 // Check if all connections are timedout. |
| 1120 bool all_connections_timedout = true; | 1134 bool all_connections_timedout = true; |
| 1121 for (size_t i = 0; i < connections_.size(); ++i) { | 1135 for (size_t i = 0; i < connections_.size(); ++i) { |
| 1122 if (connections_[i]->write_state() != Connection::STATE_WRITE_TIMEOUT) { | 1136 if (connections_[i]->write_state() != Connection::STATE_WRITE_TIMEOUT) { |
| 1123 all_connections_timedout = false; | 1137 all_connections_timedout = false; |
| 1124 break; | 1138 break; |
| 1125 } | 1139 } |
| 1126 } | 1140 } |
| 1127 | 1141 |
| 1128 // Now update the writable state of the channel with the information we have | 1142 // Now update the writable state of the channel with the information we have |
| 1129 // so far. | 1143 // so far. |
| 1130 if (all_connections_timedout) { | 1144 if (all_connections_timedout) { |
| 1131 HandleAllTimedOut(); | 1145 HandleAllTimedOut(); |
| 1132 } | 1146 } |
| 1133 | 1147 |
| 1134 // Update the state of this channel. This method is called whenever the | 1148 // Update the state of this channel. This method is called whenever the |
| 1135 // state of any connection changes, so this is a good place to do this. | 1149 // state of any connection changes, so this is a good place to do this. |
| 1136 UpdateState(); | 1150 UpdateState(); |
| 1137 } | 1151 } |
| 1138 | 1152 |
| 1139 Connection* P2PTransportChannel::best_nominated_connection() const { | |
| 1140 return (best_connection_ && best_connection_->nominated()) ? best_connection_ | |
| 1141 : nullptr; | |
| 1142 } | |
| 1143 | |
| 1144 void P2PTransportChannel::PruneConnections() { | 1153 void P2PTransportChannel::PruneConnections() { |
| 1145 // We can prune any connection for which there is a connected, writable | 1154 // We can prune any connection for which there is a connected, writable |
| 1146 // connection on the same network with better or equal priority. We leave | 1155 // connection on the same network with better or equal priority. We leave |
| 1147 // those with better priority just in case they become writable later (at | 1156 // those with better priority just in case they become writable later (at |
| 1148 // which point, we would prune out the current best connection). We leave | 1157 // which point, we would prune out the current selected connection). We leave |
| 1149 // connections on other networks because they may not be using the same | 1158 // connections on other networks because they may not be using the same |
| 1150 // resources and they may represent very distinct paths over which we can | 1159 // resources and they may represent very distinct paths over which we can |
| 1151 // switch. If the |premier| connection is not connected, we may be | 1160 // switch. If the |premier| connection is not connected, we may be |
| 1152 // reconnecting a TCP connection and temporarily do not prune connections in | 1161 // reconnecting a TCP connection and temporarily do not prune connections in |
| 1153 // this network. See the big comment in CompareConnections. | 1162 // this network. See the big comment in CompareConnectionStates. |
| 1154 | 1163 |
| 1155 // Get a list of the networks that we are using. | 1164 // Get a list of the networks that we are using. |
| 1156 std::set<rtc::Network*> networks; | 1165 std::set<rtc::Network*> networks; |
| 1157 for (const Connection* conn : connections_) { | 1166 for (const Connection* conn : connections_) { |
| 1158 networks.insert(conn->port()->Network()); | 1167 networks.insert(conn->port()->Network()); |
| 1159 } | 1168 } |
| 1160 for (rtc::Network* network : networks) { | 1169 for (rtc::Network* network : networks) { |
| 1161 Connection* premier = GetBestConnectionOnNetwork(network); | 1170 Connection* premier = GetBestConnectionOnNetwork(network); |
| 1162 // Do not prune connections if the current best connection is weak on this | 1171 // Do not prune connections if the current selected connection is weak on |
| 1163 // network. Otherwise, it may delete connections prematurely. | 1172 // this network. Otherwise, it may delete connections prematurely. |
| 1164 if (!premier || premier->weak()) { | 1173 if (!premier || premier->weak()) { |
| 1165 continue; | 1174 continue; |
| 1166 } | 1175 } |
| 1167 | 1176 |
| 1168 for (Connection* conn : connections_) { | 1177 for (Connection* conn : connections_) { |
| 1169 if ((conn != premier) && (conn->port()->Network() == network) && | 1178 if ((conn != premier) && (conn->port()->Network() == network) && |
| 1170 (CompareConnectionCandidates(premier, conn) >= 0)) { | 1179 (CompareConnectionCandidates(premier, conn) >= 0)) { |
| 1171 conn->Prune(); | 1180 conn->Prune(); |
| 1172 } | 1181 } |
| 1173 } | 1182 } |
| 1174 } | 1183 } |
| 1175 } | 1184 } |
| 1176 | 1185 |
| 1177 // Track the best connection, and let listeners know | 1186 // Change the selected connection, and let listeners know. |
| 1178 void P2PTransportChannel::SwitchBestConnectionTo(Connection* conn) { | 1187 void P2PTransportChannel::SwitchSelectedConnection(Connection* conn) { |
| 1179 // Note: if conn is NULL, the previous best_connection_ has been destroyed, | 1188 // Note: if conn is NULL, the previous |selected_connection_| has been |
| 1180 // so don't use it. | 1189 // destroyed, so don't use it. |
| 1181 Connection* old_best_connection = best_connection_; | 1190 Connection* old_selected_connection = selected_connection_; |
| 1182 best_connection_ = conn; | 1191 selected_connection_ = conn; |
| 1183 if (best_connection_) { | 1192 if (selected_connection_) { |
| 1184 if (old_best_connection) { | 1193 if (old_selected_connection) { |
| 1185 LOG_J(LS_INFO, this) << "Previous best connection: " | 1194 LOG_J(LS_INFO, this) << "Previous selected connection: " |
| 1186 << old_best_connection->ToString(); | 1195 << old_selected_connection->ToString(); |
| 1187 } | 1196 } |
| 1188 LOG_J(LS_INFO, this) << "New best connection: " | 1197 LOG_J(LS_INFO, this) << "New selected connection: " |
| 1189 << best_connection_->ToString(); | 1198 << selected_connection_->ToString(); |
| 1190 SignalRouteChange(this, best_connection_->remote_candidate()); | 1199 SignalRouteChange(this, selected_connection_->remote_candidate()); |
| 1191 // This is a temporary, but safe fix to webrtc issue 5705. | 1200 // This is a temporary, but safe fix to webrtc issue 5705. |
| 1192 // TODO(honghaiz): Make all EWOULDBLOCK error routed through the transport | 1201 // TODO(honghaiz): Make all EWOULDBLOCK error routed through the transport |
| 1193 // channel so that it knows whether the media channel is allowed to | 1202 // channel so that it knows whether the media channel is allowed to |
| 1194 // send; then it will only signal ready-to-send if the media channel | 1203 // send; then it will only signal ready-to-send if the media channel |
| 1195 // has been disallowed to send. | 1204 // has been disallowed to send. |
| 1196 if (best_connection_->writable()) { | 1205 if (selected_connection_->writable()) { |
| 1197 SignalReadyToSend(this); | 1206 SignalReadyToSend(this); |
| 1198 } | 1207 } |
| 1199 } else { | 1208 } else { |
| 1200 LOG_J(LS_INFO, this) << "No best connection"; | 1209 LOG_J(LS_INFO, this) << "No selected connection"; |
| 1201 } | 1210 } |
| 1202 // TODO(honghaiz): rename best_connection_ with selected_connection_ or | 1211 SignalSelectedCandidatePairChanged(this, selected_connection_, |
| 1203 // selected_candidate pair_. | |
| 1204 SignalSelectedCandidatePairChanged(this, best_connection_, | |
| 1205 last_sent_packet_id_); | 1212 last_sent_packet_id_); |
| 1206 } | 1213 } |
| 1207 | 1214 |
| 1208 // Warning: UpdateState should eventually be called whenever a connection | 1215 // Warning: UpdateState should eventually be called whenever a connection |
| 1209 // is added, deleted, or the write state of any connection changes so that the | 1216 // is added, deleted, or the write state of any connection changes so that the |
| 1210 // transport controller will get the up-to-date channel state. However it | 1217 // transport controller will get the up-to-date channel state. However it |
| 1211 // should not be called too often; in the case that multiple connection states | 1218 // should not be called too often; in the case that multiple connection states |
| 1212 // change, it should be called after all the connection states have changed. For | 1219 // change, it should be called after all the connection states have changed. For |
| 1213 // example, we call this at the end of SortConnections. | 1220 // example, we call this at the end of SortConnections. |
| 1214 void P2PTransportChannel::UpdateState() { | 1221 void P2PTransportChannel::UpdateState() { |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 1241 RTC_DCHECK(state == STATE_CONNECTING || state == STATE_COMPLETED); | 1248 RTC_DCHECK(state == STATE_CONNECTING || state == STATE_COMPLETED); |
| 1242 break; | 1249 break; |
| 1243 default: | 1250 default: |
| 1244 RTC_DCHECK(false); | 1251 RTC_DCHECK(false); |
| 1245 break; | 1252 break; |
| 1246 } | 1253 } |
| 1247 state_ = state; | 1254 state_ = state; |
| 1248 SignalStateChanged(this); | 1255 SignalStateChanged(this); |
| 1249 } | 1256 } |
| 1250 | 1257 |
| 1251 bool writable = best_connection_ && best_connection_->writable(); | 1258 bool writable = selected_connection_ && selected_connection_->writable(); |
| 1252 set_writable(writable); | 1259 set_writable(writable); |
| 1253 | 1260 |
| 1254 bool receiving = false; | 1261 bool receiving = false; |
| 1255 for (const Connection* connection : connections_) { | 1262 for (const Connection* connection : connections_) { |
| 1256 if (connection->receiving()) { | 1263 if (connection->receiving()) { |
| 1257 receiving = true; | 1264 receiving = true; |
| 1258 break; | 1265 break; |
| 1259 } | 1266 } |
| 1260 } | 1267 } |
| 1261 set_receiving(receiving); | 1268 set_receiving(receiving); |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 1281 } | 1288 } |
| 1282 | 1289 |
| 1283 // If all connections timed out, delete them all. | 1290 // If all connections timed out, delete them all. |
| 1284 void P2PTransportChannel::HandleAllTimedOut() { | 1291 void P2PTransportChannel::HandleAllTimedOut() { |
| 1285 for (Connection* connection : connections_) { | 1292 for (Connection* connection : connections_) { |
| 1286 connection->Destroy(); | 1293 connection->Destroy(); |
| 1287 } | 1294 } |
| 1288 } | 1295 } |
| 1289 | 1296 |
| 1290 bool P2PTransportChannel::weak() const { | 1297 bool P2PTransportChannel::weak() const { |
| 1291 return !best_connection_ || best_connection_->weak(); | 1298 return !selected_connection_ || selected_connection_->weak(); |
| 1292 } | 1299 } |
| 1293 | 1300 |
| 1294 // If we have a best connection, return it, otherwise return top one in the | 1301 // If we have a selected connection, return it, otherwise return top one in the |
| 1295 // list (later we will mark it best). | 1302 // list (later we will mark it best). |
| 1296 Connection* P2PTransportChannel::GetBestConnectionOnNetwork( | 1303 Connection* P2PTransportChannel::GetBestConnectionOnNetwork( |
| 1297 rtc::Network* network) const { | 1304 rtc::Network* network) const { |
| 1298 // If the best connection is on this network, then it wins. | 1305 // If the selected connection is on this network, then it wins. |
| 1299 if (best_connection_ && (best_connection_->port()->Network() == network)) | 1306 if (selected_connection_ && |
| 1300 return best_connection_; | 1307 (selected_connection_->port()->Network() == network)) { |
| 1308 return selected_connection_; | |
| 1309 } | |
| 1301 | 1310 |
| 1302 // Otherwise, we return the top-most in sorted order. | 1311 // Otherwise, we return the top-most in sorted order. |
| 1303 for (size_t i = 0; i < connections_.size(); ++i) { | 1312 for (size_t i = 0; i < connections_.size(); ++i) { |
| 1304 if (connections_[i]->port()->Network() == network) | 1313 if (connections_[i]->port()->Network() == network) { |
| 1305 return connections_[i]; | 1314 return connections_[i]; |
| 1315 } | |
| 1306 } | 1316 } |
| 1307 | 1317 |
| 1308 return NULL; | 1318 return NULL; |
| 1309 } | 1319 } |
| 1310 | 1320 |
| 1311 // Handle any queued up requests | 1321 // Handle any queued up requests |
| 1312 void P2PTransportChannel::OnMessage(rtc::Message *pmsg) { | 1322 void P2PTransportChannel::OnMessage(rtc::Message *pmsg) { |
| 1313 switch (pmsg->message_id) { | 1323 switch (pmsg->message_id) { |
| 1314 case MSG_SORT: | 1324 case MSG_SORT: |
| 1315 OnSort(); | 1325 OnSort(); |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 1327 void P2PTransportChannel::OnSort() { | 1337 void P2PTransportChannel::OnSort() { |
| 1328 // Resort the connections based on the new statistics. | 1338 // Resort the connections based on the new statistics. |
| 1329 SortConnections(); | 1339 SortConnections(); |
| 1330 } | 1340 } |
| 1331 | 1341 |
| 1332 // Handle queued up check-and-ping request | 1342 // Handle queued up check-and-ping request |
| 1333 void P2PTransportChannel::OnCheckAndPing() { | 1343 void P2PTransportChannel::OnCheckAndPing() { |
| 1334 // Make sure the states of the connections are up-to-date (since this affects | 1344 // Make sure the states of the connections are up-to-date (since this affects |
| 1335 // which ones are pingable). | 1345 // which ones are pingable). |
| 1336 UpdateConnectionStates(); | 1346 UpdateConnectionStates(); |
| 1337 // When the best connection is not receiving or not writable, or any active | 1347 // When the selected connection is not receiving or not writable, or any |
| 1338 // connection has not been pinged enough times, use the weak ping interval. | 1348 // active connection has not been pinged enough times, use the weak ping |
| 1349 // interval. | |
| 1339 bool need_more_pings_at_weak_interval = std::any_of( | 1350 bool need_more_pings_at_weak_interval = std::any_of( |
| 1340 connections_.begin(), connections_.end(), [](Connection* conn) { | 1351 connections_.begin(), connections_.end(), [](Connection* conn) { |
| 1341 return conn->active() && | 1352 return conn->active() && |
| 1342 conn->num_pings_sent() < MIN_PINGS_AT_WEAK_PING_INTERVAL; | 1353 conn->num_pings_sent() < MIN_PINGS_AT_WEAK_PING_INTERVAL; |
| 1343 }); | 1354 }); |
| 1344 int ping_interval = (weak() || need_more_pings_at_weak_interval) | 1355 int ping_interval = (weak() || need_more_pings_at_weak_interval) |
| 1345 ? weak_ping_interval_ | 1356 ? weak_ping_interval_ |
| 1346 : STRONG_PING_INTERVAL; | 1357 : STRONG_PING_INTERVAL; |
| 1347 if (rtc::TimeMillis() >= last_ping_sent_ms_ + ping_interval) { | 1358 if (rtc::TimeMillis() >= last_ping_sent_ms_ + ping_interval) { |
| 1348 Connection* conn = FindNextPingableConnection(); | 1359 Connection* conn = FindNextPingableConnection(); |
| 1349 if (conn) { | 1360 if (conn) { |
| 1350 PingConnection(conn); | 1361 PingConnection(conn); |
| 1351 MarkConnectionPinged(conn); | 1362 MarkConnectionPinged(conn); |
| 1352 } | 1363 } |
| 1353 } | 1364 } |
| 1354 int delay = std::min(ping_interval, check_receiving_interval_); | 1365 int delay = std::min(ping_interval, check_receiving_interval_); |
| 1355 thread()->PostDelayed(RTC_FROM_HERE, delay, this, MSG_CHECK_AND_PING); | 1366 thread()->PostDelayed(RTC_FROM_HERE, delay, this, MSG_CHECK_AND_PING); |
| 1356 } | 1367 } |
| 1357 | 1368 |
| 1358 // A connection is considered a backup connection if the channel state | 1369 // A connection is considered a backup connection if the channel state |
| 1359 // is completed, the connection is not the best connection and it is active. | 1370 // is completed, the connection is not the selected connection and it is active. |
| 1360 bool P2PTransportChannel::IsBackupConnection(Connection* conn) const { | 1371 bool P2PTransportChannel::IsBackupConnection(Connection* conn) const { |
| 1361 return state_ == STATE_COMPLETED && conn != best_connection_ && | 1372 return state_ == STATE_COMPLETED && conn != selected_connection_ && |
| 1362 conn->active(); | 1373 conn->active(); |
| 1363 } | 1374 } |
| 1364 | 1375 |
| 1365 // Is the connection in a state for us to even consider pinging the other side? | 1376 // Is the connection in a state for us to even consider pinging the other side? |
| 1366 // We consider a connection pingable even if it's not connected because that's | 1377 // We consider a connection pingable even if it's not connected because that's |
| 1367 // how a TCP connection is kicked into reconnecting on the active side. | 1378 // how a TCP connection is kicked into reconnecting on the active side. |
| 1368 bool P2PTransportChannel::IsPingable(Connection* conn, int64_t now) { | 1379 bool P2PTransportChannel::IsPingable(Connection* conn, int64_t now) { |
| 1369 const Candidate& remote = conn->remote_candidate(); | 1380 const Candidate& remote = conn->remote_candidate(); |
| 1370 // We should never get this far with an empty remote ufrag. | 1381 // We should never get this far with an empty remote ufrag. |
| 1371 ASSERT(!remote.username().empty()); | 1382 ASSERT(!remote.username().empty()); |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 1401 if (!conn->writable()) { | 1412 if (!conn->writable()) { |
| 1402 return true; | 1413 return true; |
| 1403 } | 1414 } |
| 1404 | 1415 |
| 1405 // Ping writable, active connections if it's been long enough since the last | 1416 // Ping writable, active connections if it's been long enough since the last |
| 1406 // ping. | 1417 // ping. |
| 1407 int ping_interval = CalculateActiveWritablePingInterval(conn, now); | 1418 int ping_interval = CalculateActiveWritablePingInterval(conn, now); |
| 1408 return (now >= conn->last_ping_sent() + ping_interval); | 1419 return (now >= conn->last_ping_sent() + ping_interval); |
| 1409 } | 1420 } |
| 1410 | 1421 |
| 1411 bool P2PTransportChannel::IsBestConnectionPingable(int64_t now) { | 1422 bool P2PTransportChannel::IsSelectedConnectionPingable(int64_t now) { |
| 1412 if (!best_connection_ || !best_connection_->connected() || | 1423 if (!selected_connection_ || !selected_connection_->connected() || |
| 1413 !best_connection_->writable()) { | 1424 !selected_connection_->writable()) { |
| 1414 return false; | 1425 return false; |
| 1415 } | 1426 } |
| 1416 | 1427 |
| 1417 int interval = CalculateActiveWritablePingInterval(best_connection_, now); | 1428 int interval = CalculateActiveWritablePingInterval(selected_connection_, now); |
| 1418 return best_connection_->last_ping_sent() + interval <= now; | 1429 return selected_connection_->last_ping_sent() + interval <= now; |
| 1419 } | 1430 } |
| 1420 | 1431 |
| 1421 int P2PTransportChannel::CalculateActiveWritablePingInterval(Connection* conn, | 1432 int P2PTransportChannel::CalculateActiveWritablePingInterval(Connection* conn, |
| 1422 int64_t now) { | 1433 int64_t now) { |
| 1423 // Ping each connection at a higher rate at least | 1434 // Ping each connection at a higher rate at least |
| 1424 // MIN_PINGS_AT_WEAK_PING_INTERVAL times. | 1435 // MIN_PINGS_AT_WEAK_PING_INTERVAL times. |
| 1425 if (conn->num_pings_sent() < MIN_PINGS_AT_WEAK_PING_INTERVAL) { | 1436 if (conn->num_pings_sent() < MIN_PINGS_AT_WEAK_PING_INTERVAL) { |
| 1426 return weak_ping_interval_; | 1437 return weak_ping_interval_; |
| 1427 } | 1438 } |
| 1428 | 1439 |
| 1429 int stable_interval = config_.stable_writable_connection_ping_interval; | 1440 int stable_interval = config_.stable_writable_connection_ping_interval; |
| 1430 int stablizing_interval = | 1441 int stablizing_interval = |
| 1431 std::min(stable_interval, STABILIZING_WRITABLE_CONNECTION_PING_INTERVAL); | 1442 std::min(stable_interval, STABILIZING_WRITABLE_CONNECTION_PING_INTERVAL); |
| 1432 | 1443 |
| 1433 return conn->stable(now) ? stable_interval : stablizing_interval; | 1444 return conn->stable(now) ? stable_interval : stablizing_interval; |
| 1434 } | 1445 } |
| 1435 | 1446 |
| 1436 // Returns the next pingable connection to ping. This will be the oldest | 1447 // Returns the next pingable connection to ping. This will be the oldest |
| 1437 // pingable connection unless we have a connected, writable connection that is | 1448 // pingable connection unless we have a connected, writable connection that is |
| 1438 // past the writable ping interval. When reconnecting a TCP | 1449 // past the writable ping interval. When reconnecting a TCP |
| 1439 // connection, the best connection is disconnected, although still WRITABLE | 1450 // connection, the selected connection is disconnected, although still WRITABLE |
| 1440 // while reconnecting. The newly created connection should be selected as the | 1451 // while reconnecting. The newly created connection should be selected as the |
| 1441 // ping target to become writable instead. See the big comment in | 1452 // ping target to become writable instead. See the big comment in |
| 1442 // CompareConnections. | 1453 // CompareConnectionStates. |
| 1443 Connection* P2PTransportChannel::FindNextPingableConnection() { | 1454 Connection* P2PTransportChannel::FindNextPingableConnection() { |
| 1444 int64_t now = rtc::TimeMillis(); | 1455 int64_t now = rtc::TimeMillis(); |
| 1445 Connection* conn_to_ping = nullptr; | 1456 Connection* conn_to_ping = nullptr; |
| 1446 if (IsBestConnectionPingable(now)) { | 1457 if (IsSelectedConnectionPingable(now)) { |
| 1447 conn_to_ping = best_connection_; | 1458 conn_to_ping = selected_connection_; |
| 1448 } else { | 1459 } else { |
| 1449 conn_to_ping = FindConnectionToPing(now); | 1460 conn_to_ping = FindConnectionToPing(now); |
| 1450 } | 1461 } |
| 1451 return conn_to_ping; | 1462 return conn_to_ping; |
| 1452 } | 1463 } |
| 1453 | 1464 |
| 1454 void P2PTransportChannel::MarkConnectionPinged(Connection* conn) { | 1465 void P2PTransportChannel::MarkConnectionPinged(Connection* conn) { |
| 1455 if (conn && pinged_connections_.insert(conn).second) { | 1466 if (conn && pinged_connections_.insert(conn).second) { |
| 1456 unpinged_connections_.erase(conn); | 1467 unpinged_connections_.erase(conn); |
| 1457 } | 1468 } |
| 1458 } | 1469 } |
| 1459 | 1470 |
| 1460 // Apart from sending ping from |conn| this method also updates | 1471 // Apart from sending ping from |conn| this method also updates |
| 1461 // |use_candidate_attr| flag. The criteria to update this flag is | 1472 // |use_candidate_attr| flag. The criteria to update this flag is |
| 1462 // explained below. | 1473 // explained below. |
| 1463 // Set USE-CANDIDATE if doing ICE AND this channel is in CONTROLLING AND | 1474 // Set USE-CANDIDATE if doing ICE AND this channel is in CONTROLLING AND |
| 1464 // a) Channel is in FULL ICE AND | 1475 // a) Channel is in FULL ICE AND |
| 1465 // a.1) |conn| is the best connection OR | 1476 // a.1) |conn| is the selected connection OR |
| 1466 // a.2) there is no best connection OR | 1477 // a.2) there is no selected connection OR |
| 1467 // a.3) the best connection is unwritable OR | 1478 // a.3) the selected connection is unwritable OR |
| 1468 // a.4) |conn| has higher priority than best_connection. | 1479 // a.4) |conn| has higher priority than selected_connection. |
| 1469 // b) we're doing LITE ICE AND | 1480 // b) we're doing LITE ICE AND |
| 1470 // b.1) |conn| is the best_connection AND | 1481 // b.1) |conn| is the selected_connection AND |
| 1471 // b.2) |conn| is writable. | 1482 // b.2) |conn| is writable. |
| 1472 void P2PTransportChannel::PingConnection(Connection* conn) { | 1483 void P2PTransportChannel::PingConnection(Connection* conn) { |
| 1473 bool use_candidate = false; | 1484 bool use_candidate = false; |
| 1474 if (remote_ice_mode_ == ICEMODE_FULL && ice_role_ == ICEROLE_CONTROLLING) { | 1485 if (remote_ice_mode_ == ICEMODE_FULL && ice_role_ == ICEROLE_CONTROLLING) { |
| 1475 use_candidate = (conn == best_connection_) || (best_connection_ == NULL) || | 1486 use_candidate = |
| 1476 (!best_connection_->writable()) || | 1487 (conn == selected_connection_) || (selected_connection_ == NULL) || |
| 1477 (CompareConnectionCandidates(best_connection_, conn) < 0); | 1488 (!selected_connection_->writable()) || |
| 1478 } else if (remote_ice_mode_ == ICEMODE_LITE && conn == best_connection_) { | 1489 (CompareConnectionCandidates(selected_connection_, conn) < 0); |
| 1479 use_candidate = best_connection_->writable(); | 1490 } else if (remote_ice_mode_ == ICEMODE_LITE && conn == selected_connection_) { |
| 1491 use_candidate = selected_connection_->writable(); | |
| 1480 } | 1492 } |
| 1481 conn->set_use_candidate_attr(use_candidate); | 1493 conn->set_use_candidate_attr(use_candidate); |
| 1482 last_ping_sent_ms_ = rtc::TimeMillis(); | 1494 last_ping_sent_ms_ = rtc::TimeMillis(); |
| 1483 conn->Ping(last_ping_sent_ms_); | 1495 conn->Ping(last_ping_sent_ms_); |
| 1484 } | 1496 } |
| 1485 | 1497 |
| 1486 // When a connection's state changes, we need to figure out who to use as | 1498 // When a connection's state changes, we need to figure out who to use as |
| 1487 // the best connection again. It could have become usable, or become unusable. | 1499 // the selected connection again. It could have become usable, or become |
| 1500 // unusable. | |
| 1488 void P2PTransportChannel::OnConnectionStateChange(Connection* connection) { | 1501 void P2PTransportChannel::OnConnectionStateChange(Connection* connection) { |
| 1489 ASSERT(worker_thread_ == rtc::Thread::Current()); | 1502 ASSERT(worker_thread_ == rtc::Thread::Current()); |
| 1490 | 1503 |
| 1491 // Update the best connection if the state change is from pending best | |
| 1492 // connection and role is controlled. | |
| 1493 if (ice_role_ == ICEROLE_CONTROLLED) { | |
| 1494 if (connection == pending_best_connection_ && connection->writable()) { | |
| 1495 pending_best_connection_ = NULL; | |
| 1496 LOG(LS_INFO) << "Switching best connection on controlled side" | |
| 1497 << " because it's now writable: " << connection->ToString(); | |
| 1498 SwitchBestConnectionTo(connection); | |
| 1499 } | |
| 1500 } | |
| 1501 | |
| 1502 // May stop the allocator session when at least one connection becomes | 1504 // May stop the allocator session when at least one connection becomes |
| 1503 // strongly connected after starting to get ports and the local candidate of | 1505 // strongly connected after starting to get ports and the local candidate of |
| 1504 // the connection is at the latest generation. It is not enough to check | 1506 // the connection is at the latest generation. It is not enough to check |
| 1505 // that the connection becomes weakly connected because the connection may be | 1507 // that the connection becomes weakly connected because the connection may be |
| 1506 // changing from (writable, receiving) to (writable, not receiving). | 1508 // changing from (writable, receiving) to (writable, not receiving). |
| 1507 bool strongly_connected = !connection->weak(); | 1509 bool strongly_connected = !connection->weak(); |
| 1508 bool latest_generation = connection->local_candidate().generation() >= | 1510 bool latest_generation = connection->local_candidate().generation() >= |
| 1509 allocator_session()->generation(); | 1511 allocator_session()->generation(); |
| 1510 if (strongly_connected && latest_generation) { | 1512 if (strongly_connected && latest_generation) { |
| 1511 MaybeStopPortAllocatorSessions(); | 1513 MaybeStopPortAllocatorSessions(); |
| 1512 } | 1514 } |
| 1513 | 1515 |
| 1514 // We have to unroll the stack before doing this because we may be changing | 1516 // We have to unroll the stack before doing this because we may be changing |
| 1515 // the state of connections while sorting. | 1517 // the state of connections while sorting. |
| 1516 RequestSort(); | 1518 RequestSort(); |
| 1517 } | 1519 } |
| 1518 | 1520 |
| 1519 // When a connection is removed, edit it out, and then update our best | 1521 // When a connection is removed, edit it out, and then update our best |
| 1520 // connection. | 1522 // connection. |
| 1521 void P2PTransportChannel::OnConnectionDestroyed(Connection* connection) { | 1523 void P2PTransportChannel::OnConnectionDestroyed(Connection* connection) { |
| 1522 ASSERT(worker_thread_ == rtc::Thread::Current()); | 1524 ASSERT(worker_thread_ == rtc::Thread::Current()); |
| 1523 | 1525 |
| 1524 // Note: the previous best_connection_ may be destroyed by now, so don't | 1526 // Note: the previous selected_connection_ may be destroyed by now, so don't |
| 1525 // use it. | 1527 // use it. |
| 1526 | 1528 |
| 1527 // Remove this connection from the list. | 1529 // Remove this connection from the list. |
| 1528 std::vector<Connection*>::iterator iter = | 1530 std::vector<Connection*>::iterator iter = |
| 1529 std::find(connections_.begin(), connections_.end(), connection); | 1531 std::find(connections_.begin(), connections_.end(), connection); |
| 1530 ASSERT(iter != connections_.end()); | 1532 ASSERT(iter != connections_.end()); |
| 1531 pinged_connections_.erase(*iter); | 1533 pinged_connections_.erase(*iter); |
| 1532 unpinged_connections_.erase(*iter); | 1534 unpinged_connections_.erase(*iter); |
| 1533 connections_.erase(iter); | 1535 connections_.erase(iter); |
| 1534 | 1536 |
| 1535 LOG_J(LS_INFO, this) << "Removed connection (" | 1537 LOG_J(LS_INFO, this) << "Removed connection (" |
| 1536 << static_cast<int>(connections_.size()) << " remaining)"; | 1538 << static_cast<int>(connections_.size()) << " remaining)"; |
| 1537 | 1539 |
| 1538 if (pending_best_connection_ == connection) { | 1540 // If this is currently the selected connection, then we need to pick a new |
| 1539 pending_best_connection_ = NULL; | 1541 // one. The call to SortConnections will pick a new one. It looks at the |
| 1540 } | 1542 // current selected connection in order to avoid switching between fairly |
| 1541 | 1543 // similar ones. Since this connection is no longer an option, we can just |
| 1542 // If this is currently the best connection, then we need to pick a new one. | 1544 // set selected to nullptr and re-choose a best assuming that there was no |
| 1543 // The call to SortConnections will pick a new one. It looks at the current | 1545 // selected connection. |
| 1544 // best connection in order to avoid switching between fairly similar ones. | 1546 if (selected_connection_ == connection) { |
| 1545 // Since this connection is no longer an option, we can just set best to NULL | 1547 LOG(LS_INFO) << "selected connection destroyed. Will choose a new one."; |
| 1546 // and re-choose a best assuming that there was no best connection. | 1548 SwitchSelectedConnection(nullptr); |
| 1547 if (best_connection_ == connection) { | |
| 1548 LOG(LS_INFO) << "Best connection destroyed. Will choose a new one."; | |
| 1549 SwitchBestConnectionTo(NULL); | |
| 1550 RequestSort(); | 1549 RequestSort(); |
| 1551 } | 1550 } |
| 1552 | 1551 |
| 1553 UpdateState(); | 1552 UpdateState(); |
| 1554 } | 1553 } |
| 1555 | 1554 |
| 1556 // When a port is destroyed remove it from our list of ports to use for | 1555 // When a port is destroyed remove it from our list of ports to use for |
| 1557 // connection attempts. | 1556 // connection attempts. |
| 1558 void P2PTransportChannel::OnPortDestroyed(PortInterface* port) { | 1557 void P2PTransportChannel::OnPortDestroyed(PortInterface* port) { |
| 1559 ASSERT(worker_thread_ == rtc::Thread::Current()); | 1558 ASSERT(worker_thread_ == rtc::Thread::Current()); |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1599 | 1598 |
| 1600 // Do not deliver, if packet doesn't belong to the correct transport channel. | 1599 // Do not deliver, if packet doesn't belong to the correct transport channel. |
| 1601 if (!FindConnection(connection)) | 1600 if (!FindConnection(connection)) |
| 1602 return; | 1601 return; |
| 1603 | 1602 |
| 1604 // Let the client know of an incoming packet | 1603 // Let the client know of an incoming packet |
| 1605 SignalReadPacket(this, data, len, packet_time, 0); | 1604 SignalReadPacket(this, data, len, packet_time, 0); |
| 1606 | 1605 |
| 1607 // May need to switch the sending connection based on the receiving media path | 1606 // May need to switch the sending connection based on the receiving media path |
| 1608 // if this is the controlled side. | 1607 // if this is the controlled side. |
| 1609 if (ice_role_ == ICEROLE_CONTROLLED && !best_nominated_connection() && | 1608 if (ice_role_ == ICEROLE_CONTROLLED && |
| 1610 connection->writable() && best_connection_ != connection) { | 1609 ShouldSwitchSelectedConnection(connection)) { |
| 1611 SwitchBestConnectionTo(connection); | 1610 LOG(LS_INFO) << "Switching selected connection on controlled side due to " |
| 1611 << "data received: " << connection->ToString(); | |
| 1612 SwitchSelectedConnection(connection); | |
| 1612 } | 1613 } |
| 1613 } | 1614 } |
| 1614 | 1615 |
| 1615 void P2PTransportChannel::OnSentPacket(const rtc::SentPacket& sent_packet) { | 1616 void P2PTransportChannel::OnSentPacket(const rtc::SentPacket& sent_packet) { |
| 1616 ASSERT(worker_thread_ == rtc::Thread::Current()); | 1617 ASSERT(worker_thread_ == rtc::Thread::Current()); |
| 1617 | 1618 |
| 1618 SignalSentPacket(this, sent_packet); | 1619 SignalSentPacket(this, sent_packet); |
| 1619 } | 1620 } |
| 1620 | 1621 |
| 1621 void P2PTransportChannel::OnReadyToSend(Connection* connection) { | 1622 void P2PTransportChannel::OnReadyToSend(Connection* connection) { |
| 1622 if (connection == best_connection_ && writable()) { | 1623 if (connection == selected_connection_ && writable()) { |
| 1623 SignalReadyToSend(this); | 1624 SignalReadyToSend(this); |
| 1624 } | 1625 } |
| 1625 } | 1626 } |
| 1626 | 1627 |
| 1627 // Find "triggered checks". We ping first those connections that have | 1628 // Find "triggered checks". We ping first those connections that have |
| 1628 // received a ping but have not sent a ping since receiving it | 1629 // received a ping but have not sent a ping since receiving it |
| 1629 // (last_received_ping > last_sent_ping). But we shouldn't do | 1630 // (last_received_ping > last_sent_ping). But we shouldn't do |
| 1630 // triggered checks if the connection is already writable. | 1631 // triggered checks if the connection is already writable. |
| 1631 Connection* P2PTransportChannel::FindOldestConnectionNeedingTriggeredCheck( | 1632 Connection* P2PTransportChannel::FindOldestConnectionNeedingTriggeredCheck( |
| 1632 int64_t now) { | 1633 int64_t now) { |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1735 | 1736 |
| 1736 // During the initial state when nothing has been pinged yet, return the first | 1737 // During the initial state when nothing has been pinged yet, return the first |
| 1737 // one in the ordered |connections_|. | 1738 // one in the ordered |connections_|. |
| 1738 return *(std::find_if(connections_.begin(), connections_.end(), | 1739 return *(std::find_if(connections_.begin(), connections_.end(), |
| 1739 [conn1, conn2](Connection* conn) { | 1740 [conn1, conn2](Connection* conn) { |
| 1740 return conn == conn1 || conn == conn2; | 1741 return conn == conn1 || conn == conn2; |
| 1741 })); | 1742 })); |
| 1742 } | 1743 } |
| 1743 | 1744 |
| 1744 } // namespace cricket | 1745 } // namespace cricket |
| OLD | NEW |