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 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 180 } // unnamed namespace | 180 } // unnamed namespace |
| 181 | 181 |
| 182 namespace cricket { | 182 namespace cricket { |
| 183 | 183 |
| 184 // When the socket is unwritable, we will use 10 Kbps (ignoring IP+UDP headers) | 184 // When the socket is unwritable, we will use 10 Kbps (ignoring IP+UDP headers) |
| 185 // for pinging. When the socket is writable, we will use only 1 Kbps because | 185 // for pinging. When the socket is writable, we will use only 1 Kbps because |
| 186 // we don't want to degrade the quality on a modem. These numbers should work | 186 // we don't want to degrade the quality on a modem. These numbers should work |
| 187 // well on a 28.8K modem, which is the slowest connection on which the voice | 187 // well on a 28.8K modem, which is the slowest connection on which the voice |
| 188 // quality is reasonable at all. | 188 // quality is reasonable at all. |
| 189 static const uint32_t PING_PACKET_SIZE = 60 * 8; | 189 static const uint32_t PING_PACKET_SIZE = 60 * 8; |
| 190 // TODO(honghaiz): Change the word DELAY to INTERVAL whenever appropriate. | |
| 190 // STRONG_PING_DELAY (480ms) is applied when the best connection is both | 191 // STRONG_PING_DELAY (480ms) is applied when the best connection is both |
| 191 // writable and receiving. | 192 // writable and receiving. |
| 192 static const uint32_t STRONG_PING_DELAY = 1000 * PING_PACKET_SIZE / 1000; | 193 static const uint32_t STRONG_PING_DELAY = 1000 * PING_PACKET_SIZE / 1000; |
| 193 // WEAK_PING_DELAY (48ms) is applied when the best connection is either not | 194 // WEAK_PING_DELAY (48ms) is applied when the best connection is either not |
| 194 // writable or not receiving. | 195 // writable or not receiving. |
| 195 const uint32_t WEAK_PING_DELAY = 1000 * PING_PACKET_SIZE / 10000; | 196 const uint32_t WEAK_PING_DELAY = 1000 * PING_PACKET_SIZE / 10000; |
| 196 | 197 |
| 197 // If the current best connection is both writable and receiving, then we will | 198 // If the current best connection is both writable and receiving, then we will |
| 198 // also try hard to make sure it is pinged at this rate (a little less than | 199 // also try hard to make sure it is pinged at this rate (a little less than |
| 199 // 2 * STRONG_PING_DELAY). | 200 // 2 * STRONG_PING_DELAY). |
| 200 static const uint32_t MAX_CURRENT_STRONG_DELAY = 900; | 201 static const uint32_t MAX_CURRENT_STRONG_DELAY = 900; |
| 201 | 202 |
| 202 static const int MIN_CHECK_RECEIVING_DELAY = 50; // ms | 203 static const int MIN_CHECK_RECEIVING_DELAY = 50; // ms |
| 203 | 204 |
| 204 | |
| 205 P2PTransportChannel::P2PTransportChannel(const std::string& transport_name, | 205 P2PTransportChannel::P2PTransportChannel(const std::string& transport_name, |
| 206 int component, | 206 int component, |
| 207 P2PTransport* transport, | 207 P2PTransport* transport, |
| 208 PortAllocator* allocator) | 208 PortAllocator* allocator) |
| 209 : TransportChannelImpl(transport_name, component), | 209 : TransportChannelImpl(transport_name, component), |
| 210 transport_(transport), | 210 transport_(transport), |
| 211 allocator_(allocator), | 211 allocator_(allocator), |
| 212 worker_thread_(rtc::Thread::Current()), | 212 worker_thread_(rtc::Thread::Current()), |
| 213 incoming_only_(false), | 213 incoming_only_(false), |
| 214 error_(0), | 214 error_(0), |
| 215 best_connection_(NULL), | 215 best_connection_(NULL), |
| 216 pending_best_connection_(NULL), | 216 pending_best_connection_(NULL), |
| 217 sort_dirty_(false), | 217 sort_dirty_(false), |
| 218 remote_ice_mode_(ICEMODE_FULL), | 218 remote_ice_mode_(ICEMODE_FULL), |
| 219 ice_role_(ICEROLE_UNKNOWN), | 219 ice_role_(ICEROLE_UNKNOWN), |
| 220 tiebreaker_(0), | 220 tiebreaker_(0), |
| 221 remote_candidate_generation_(0), | 221 remote_candidate_generation_(0), |
| 222 gathering_state_(kIceGatheringNew), | 222 gathering_state_(kIceGatheringNew), |
| 223 check_receiving_delay_(MIN_CHECK_RECEIVING_DELAY * 5), | 223 check_receiving_delay_(MIN_CHECK_RECEIVING_DELAY * 5), |
| 224 receiving_timeout_(MIN_CHECK_RECEIVING_DELAY * 50) { | 224 receiving_timeout_(MIN_CHECK_RECEIVING_DELAY * 50), |
| 225 backup_connection_ping_interval_(0) { | |
| 225 uint32_t weak_ping_delay = ::strtoul( | 226 uint32_t weak_ping_delay = ::strtoul( |
| 226 webrtc::field_trial::FindFullName("WebRTC-StunInterPacketDelay").c_str(), | 227 webrtc::field_trial::FindFullName("WebRTC-StunInterPacketDelay").c_str(), |
| 227 nullptr, 10); | 228 nullptr, 10); |
| 228 if (weak_ping_delay) { | 229 if (weak_ping_delay) { |
| 229 weak_ping_delay_ = weak_ping_delay; | 230 weak_ping_delay_ = weak_ping_delay; |
| 230 } | 231 } |
| 231 } | 232 } |
| 232 | 233 |
| 233 P2PTransportChannel::~P2PTransportChannel() { | 234 P2PTransportChannel::~P2PTransportChannel() { |
| 234 ASSERT(worker_thread_ == rtc::Thread::Current()); | 235 ASSERT(worker_thread_ == rtc::Thread::Current()); |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 289 ASSERT(worker_thread_ == rtc::Thread::Current()); | 290 ASSERT(worker_thread_ == rtc::Thread::Current()); |
| 290 if (!ports_.empty()) { | 291 if (!ports_.empty()) { |
| 291 LOG(LS_ERROR) | 292 LOG(LS_ERROR) |
| 292 << "Attempt to change tiebreaker after Port has been allocated."; | 293 << "Attempt to change tiebreaker after Port has been allocated."; |
| 293 return; | 294 return; |
| 294 } | 295 } |
| 295 | 296 |
| 296 tiebreaker_ = tiebreaker; | 297 tiebreaker_ = tiebreaker; |
| 297 } | 298 } |
| 298 | 299 |
| 300 TransportChannelState P2PTransportChannel::GetState() const { | |
|
pthatcher1
2015/12/01 19:40:25
Can we just change this to state()?
honghaiz3
2015/12/01 23:43:08
This is a virtual method.
| |
| 301 return state_; | |
| 302 } | |
| 303 | |
| 299 // A channel is considered ICE completed once there is at most one active | 304 // A channel is considered ICE completed once there is at most one active |
| 300 // connection per network and at least one active connection. | 305 // connection per network and at least one active connection. |
| 301 TransportChannelState P2PTransportChannel::GetState() const { | 306 TransportChannelState P2PTransportChannel::ComputeState() const { |
| 302 if (!had_connection_) { | 307 if (!had_connection_) { |
| 303 return TransportChannelState::STATE_INIT; | 308 return TransportChannelState::STATE_INIT; |
| 304 } | 309 } |
| 305 | 310 |
| 306 std::vector<Connection*> active_connections; | 311 std::vector<Connection*> active_connections; |
| 307 for (Connection* connection : connections_) { | 312 for (Connection* connection : connections_) { |
| 308 if (connection->active()) { | 313 if (connection->active()) { |
| 309 active_connections.push_back(connection); | 314 active_connections.push_back(connection); |
| 310 } | 315 } |
| 311 } | 316 } |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 365 } | 370 } |
| 366 | 371 |
| 367 void P2PTransportChannel::SetRemoteIceMode(IceMode mode) { | 372 void P2PTransportChannel::SetRemoteIceMode(IceMode mode) { |
| 368 remote_ice_mode_ = mode; | 373 remote_ice_mode_ = mode; |
| 369 } | 374 } |
| 370 | 375 |
| 371 void P2PTransportChannel::SetIceConfig(const IceConfig& config) { | 376 void P2PTransportChannel::SetIceConfig(const IceConfig& config) { |
| 372 gather_continually_ = config.gather_continually; | 377 gather_continually_ = config.gather_continually; |
| 373 LOG(LS_INFO) << "Set gather_continually to " << gather_continually_; | 378 LOG(LS_INFO) << "Set gather_continually to " << gather_continually_; |
| 374 | 379 |
| 375 if (config.receiving_timeout_ms < 0) { | 380 if (config.backup_connection_ping_interval >= 0 && |
| 376 return; | 381 backup_connection_ping_interval_ != |
| 382 config.backup_connection_ping_interval) { | |
| 383 backup_connection_ping_interval_ = config.backup_connection_ping_interval; | |
| 384 LOG(LS_INFO) << "Set backup connection ping interval to " | |
| 385 << backup_connection_ping_interval_ << " milliseconds."; | |
| 377 } | 386 } |
| 378 receiving_timeout_ = config.receiving_timeout_ms; | |
| 379 check_receiving_delay_ = | |
| 380 std::max(MIN_CHECK_RECEIVING_DELAY, receiving_timeout_ / 10); | |
| 381 | 387 |
| 382 for (Connection* connection : connections_) { | 388 if (config.receiving_timeout_ms >= 0 && |
| 383 connection->set_receiving_timeout(receiving_timeout_); | 389 receiving_timeout_ != config.receiving_timeout_ms) { |
| 390 receiving_timeout_ = config.receiving_timeout_ms; | |
| 391 check_receiving_delay_ = | |
| 392 std::max(MIN_CHECK_RECEIVING_DELAY, receiving_timeout_ / 10); | |
| 393 | |
| 394 for (Connection* connection : connections_) { | |
| 395 connection->set_receiving_timeout(receiving_timeout_); | |
| 396 } | |
| 397 LOG(LS_INFO) << "Set ICE receiving timeout to " << receiving_timeout_ | |
| 398 << " milliseconds"; | |
| 384 } | 399 } |
| 385 LOG(LS_INFO) << "Set ICE receiving timeout to " << receiving_timeout_ | |
| 386 << " milliseconds"; | |
| 387 } | 400 } |
| 388 | 401 |
| 389 // Go into the state of processing candidates, and running in general | 402 // Go into the state of processing candidates, and running in general |
| 390 void P2PTransportChannel::Connect() { | 403 void P2PTransportChannel::Connect() { |
| 391 ASSERT(worker_thread_ == rtc::Thread::Current()); | 404 ASSERT(worker_thread_ == rtc::Thread::Current()); |
| 392 if (ice_ufrag_.empty() || ice_pwd_.empty()) { | 405 if (ice_ufrag_.empty() || ice_pwd_.empty()) { |
| 393 ASSERT(false); | 406 ASSERT(false); |
| 394 LOG(LS_ERROR) << "P2PTransportChannel::Connect: The ice_ufrag_ and the " | 407 LOG(LS_ERROR) << "P2PTransportChannel::Connect: The ice_ufrag_ and the " |
| 395 << "ice_pwd_ are not set."; | 408 << "ice_pwd_ are not set."; |
| 396 return; | 409 return; |
| (...skipping 647 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1044 } | 1057 } |
| 1045 LOG_J(LS_INFO, this) << "New best connection: " | 1058 LOG_J(LS_INFO, this) << "New best connection: " |
| 1046 << best_connection_->ToString(); | 1059 << best_connection_->ToString(); |
| 1047 SignalRouteChange(this, best_connection_->remote_candidate()); | 1060 SignalRouteChange(this, best_connection_->remote_candidate()); |
| 1048 } else { | 1061 } else { |
| 1049 LOG_J(LS_INFO, this) << "No best connection"; | 1062 LOG_J(LS_INFO, this) << "No best connection"; |
| 1050 } | 1063 } |
| 1051 } | 1064 } |
| 1052 | 1065 |
| 1053 void P2PTransportChannel::UpdateChannelState() { | 1066 void P2PTransportChannel::UpdateChannelState() { |
| 1067 state_ = ComputeState(); | |
|
pthatcher1
2015/12/01 19:40:25
Since ComputeState is never called anywhere else,
honghaiz3
2015/12/01 23:43:08
Changed to UpdateState
ComputeState has a lot of e
| |
| 1068 | |
| 1054 bool writable = best_connection_ && best_connection_->writable(); | 1069 bool writable = best_connection_ && best_connection_->writable(); |
| 1055 set_writable(writable); | 1070 set_writable(writable); |
| 1056 | 1071 |
| 1057 bool receiving = false; | 1072 bool receiving = false; |
| 1058 for (const Connection* connection : connections_) { | 1073 for (const Connection* connection : connections_) { |
| 1059 if (connection->receiving()) { | 1074 if (connection->receiving()) { |
| 1060 receiving = true; | 1075 receiving = true; |
| 1061 break; | 1076 break; |
| 1062 } | 1077 } |
| 1063 } | 1078 } |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1143 if (rtc::Time() >= last_ping_sent_ms_ + ping_delay) { | 1158 if (rtc::Time() >= last_ping_sent_ms_ + ping_delay) { |
| 1144 Connection* conn = FindNextPingableConnection(); | 1159 Connection* conn = FindNextPingableConnection(); |
| 1145 if (conn) { | 1160 if (conn) { |
| 1146 PingConnection(conn); | 1161 PingConnection(conn); |
| 1147 } | 1162 } |
| 1148 } | 1163 } |
| 1149 int check_delay = std::min(ping_delay, check_receiving_delay_); | 1164 int check_delay = std::min(ping_delay, check_receiving_delay_); |
| 1150 thread()->PostDelayed(check_delay, this, MSG_CHECK_AND_PING); | 1165 thread()->PostDelayed(check_delay, this, MSG_CHECK_AND_PING); |
| 1151 } | 1166 } |
| 1152 | 1167 |
| 1168 // A connection is considered a backup connection if the channel state | |
| 1169 // is complete, the connection is not the best connection and it is active. | |
|
pthatcher1
2015/12/01 19:40:25
complete => completed
honghaiz3
2015/12/01 23:43:08
Done.
| |
| 1170 bool P2PTransportChannel::IsBackupConnection(Connection* conn) const { | |
| 1171 return state_ == STATE_COMPLETED && conn != best_connection_ && | |
| 1172 conn->active(); | |
| 1173 } | |
| 1174 | |
| 1153 // Is the connection in a state for us to even consider pinging the other side? | 1175 // Is the connection in a state for us to even consider pinging the other side? |
| 1154 // We consider a connection pingable even if it's not connected because that's | 1176 // We consider a connection pingable even if it's not connected because that's |
| 1155 // how a TCP connection is kicked into reconnecting on the active side. | 1177 // how a TCP connection is kicked into reconnecting on the active side. |
| 1156 bool P2PTransportChannel::IsPingable(Connection* conn) { | 1178 bool P2PTransportChannel::IsPingable(Connection* conn, uint32_t now) { |
| 1157 const Candidate& remote = conn->remote_candidate(); | 1179 const Candidate& remote = conn->remote_candidate(); |
| 1158 // We should never get this far with an empty remote ufrag. | 1180 // We should never get this far with an empty remote ufrag. |
| 1159 ASSERT(!remote.username().empty()); | 1181 ASSERT(!remote.username().empty()); |
| 1160 if (remote.username().empty() || remote.password().empty()) { | 1182 if (remote.username().empty() || remote.password().empty()) { |
| 1161 // If we don't have an ICE ufrag and pwd, there's no way we can ping. | 1183 // If we don't have an ICE ufrag and pwd, there's no way we can ping. |
| 1162 return false; | 1184 return false; |
| 1163 } | 1185 } |
| 1164 | 1186 |
| 1165 // An never connected connection cannot be written to at all, so pinging is | 1187 // An never connected connection cannot be written to at all, so pinging is |
| 1166 // out of the question. However, if it has become WRITABLE, it is in the | 1188 // out of the question. However, if it has become WRITABLE, it is in the |
| 1167 // reconnecting state so ping is needed. | 1189 // reconnecting state so ping is needed. |
| 1168 if (!conn->connected() && !conn->writable()) { | 1190 if (!conn->connected() && !conn->writable()) { |
| 1169 return false; | 1191 return false; |
| 1170 } | 1192 } |
| 1171 | 1193 |
| 1172 // If the channel is weak, ping all candidates. Otherwise, we only | 1194 // If the channel is weakly connected, ping all connections. |
| 1173 // want to ping connections that have not timed out on writing. | 1195 if (weak()) { |
| 1174 return weak() || conn->write_state() != Connection::STATE_WRITE_TIMEOUT; | 1196 return true; |
| 1197 } | |
| 1198 | |
| 1199 // Always ping active connections regardless whether the channel is completed | |
| 1200 // or not, but backup connections are pinged at a slower rate. | |
| 1201 if (IsBackupConnection(conn)) { | |
| 1202 return (now >= conn->last_ping_response_received() + | |
| 1203 backup_connection_ping_interval_); | |
| 1204 } | |
| 1205 return conn->active(); | |
| 1175 } | 1206 } |
| 1176 | 1207 |
| 1177 // Returns the next pingable connection to ping. This will be the oldest | 1208 // Returns the next pingable connection to ping. This will be the oldest |
| 1178 // pingable connection unless we have a connected, writable connection that is | 1209 // pingable connection unless we have a connected, writable connection that is |
| 1179 // past the maximum acceptable ping delay. When reconnecting a TCP connection, | 1210 // past the maximum acceptable ping delay. When reconnecting a TCP connection, |
| 1180 // the best connection is disconnected, although still WRITABLE while | 1211 // the best connection is disconnected, although still WRITABLE while |
| 1181 // reconnecting. The newly created connection should be selected as the ping | 1212 // reconnecting. The newly created connection should be selected as the ping |
| 1182 // target to become writable instead. See the big comment in CompareConnections. | 1213 // target to become writable instead. See the big comment in CompareConnections. |
| 1183 Connection* P2PTransportChannel::FindNextPingableConnection() { | 1214 Connection* P2PTransportChannel::FindNextPingableConnection() { |
| 1184 uint32_t now = rtc::Time(); | 1215 uint32_t now = rtc::Time(); |
| 1185 if (best_connection_ && best_connection_->connected() && | 1216 if (best_connection_ && best_connection_->connected() && |
| 1186 best_connection_->writable() && | 1217 best_connection_->writable() && |
| 1187 (best_connection_->last_ping_sent() + MAX_CURRENT_STRONG_DELAY <= now)) { | 1218 (best_connection_->last_ping_sent() + MAX_CURRENT_STRONG_DELAY <= now)) { |
| 1188 return best_connection_; | 1219 return best_connection_; |
| 1189 } | 1220 } |
| 1190 | 1221 |
| 1191 // First, find "triggered checks". We ping first those connections | 1222 // First, find "triggered checks". We ping first those connections |
| 1192 // that have received a ping but have not sent a ping since receiving | 1223 // that have received a ping but have not sent a ping since receiving |
| 1193 // it (last_received_ping > last_sent_ping). But we shouldn't do | 1224 // it (last_received_ping > last_sent_ping). But we shouldn't do |
| 1194 // triggered checks if the connection is already writable. | 1225 // triggered checks if the connection is already writable. |
| 1195 Connection* oldest_needing_triggered_check = nullptr; | 1226 Connection* oldest_needing_triggered_check = nullptr; |
| 1196 Connection* oldest = nullptr; | 1227 Connection* oldest = nullptr; |
| 1197 for (Connection* conn : connections_) { | 1228 for (Connection* conn : connections_) { |
| 1198 if (!IsPingable(conn)) { | 1229 if (!IsPingable(conn, now)) { |
| 1199 continue; | 1230 continue; |
| 1200 } | 1231 } |
| 1201 bool needs_triggered_check = | 1232 bool needs_triggered_check = |
| 1202 (!conn->writable() && | 1233 (!conn->writable() && |
| 1203 conn->last_ping_received() > conn->last_ping_sent()); | 1234 conn->last_ping_received() > conn->last_ping_sent()); |
| 1204 if (needs_triggered_check && | 1235 if (needs_triggered_check && |
| 1205 (!oldest_needing_triggered_check || | 1236 (!oldest_needing_triggered_check || |
| 1206 (conn->last_ping_received() < | 1237 (conn->last_ping_received() < |
| 1207 oldest_needing_triggered_check->last_ping_received()))) { | 1238 oldest_needing_triggered_check->last_ping_received()))) { |
| 1208 oldest_needing_triggered_check = conn; | 1239 oldest_needing_triggered_check = conn; |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1300 // The call to SortConnections will pick a new one. It looks at the current | 1331 // The call to SortConnections will pick a new one. It looks at the current |
| 1301 // best connection in order to avoid switching between fairly similar ones. | 1332 // best connection in order to avoid switching between fairly similar ones. |
| 1302 // Since this connection is no longer an option, we can just set best to NULL | 1333 // Since this connection is no longer an option, we can just set best to NULL |
| 1303 // and re-choose a best assuming that there was no best connection. | 1334 // and re-choose a best assuming that there was no best connection. |
| 1304 if (best_connection_ == connection) { | 1335 if (best_connection_ == connection) { |
| 1305 LOG(LS_INFO) << "Best connection destroyed. Will choose a new one."; | 1336 LOG(LS_INFO) << "Best connection destroyed. Will choose a new one."; |
| 1306 SwitchBestConnectionTo(NULL); | 1337 SwitchBestConnectionTo(NULL); |
| 1307 RequestSort(); | 1338 RequestSort(); |
| 1308 } | 1339 } |
| 1309 | 1340 |
| 1341 UpdateChannelState(); | |
| 1342 // SignalConnectionRemoved should be called after the channel state is | |
| 1343 // updated because the receiver of the event may access the channel state. | |
| 1310 SignalConnectionRemoved(this); | 1344 SignalConnectionRemoved(this); |
| 1311 } | 1345 } |
| 1312 | 1346 |
| 1313 // When a port is destroyed remove it from our list of ports to use for | 1347 // When a port is destroyed remove it from our list of ports to use for |
| 1314 // connection attempts. | 1348 // connection attempts. |
| 1315 void P2PTransportChannel::OnPortDestroyed(PortInterface* port) { | 1349 void P2PTransportChannel::OnPortDestroyed(PortInterface* port) { |
| 1316 ASSERT(worker_thread_ == rtc::Thread::Current()); | 1350 ASSERT(worker_thread_ == rtc::Thread::Current()); |
| 1317 | 1351 |
| 1318 // Remove this port from the list (if we didn't drop it already). | 1352 // Remove this port from the list (if we didn't drop it already). |
| 1319 std::vector<PortInterface*>::iterator iter = | 1353 std::vector<PortInterface*>::iterator iter = |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1354 SignalSentPacket(this, sent_packet); | 1388 SignalSentPacket(this, sent_packet); |
| 1355 } | 1389 } |
| 1356 | 1390 |
| 1357 void P2PTransportChannel::OnReadyToSend(Connection* connection) { | 1391 void P2PTransportChannel::OnReadyToSend(Connection* connection) { |
| 1358 if (connection == best_connection_ && writable()) { | 1392 if (connection == best_connection_ && writable()) { |
| 1359 SignalReadyToSend(this); | 1393 SignalReadyToSend(this); |
| 1360 } | 1394 } |
| 1361 } | 1395 } |
| 1362 | 1396 |
| 1363 } // namespace cricket | 1397 } // namespace cricket |
| OLD | NEW |