Chromium Code Reviews| Index: webrtc/p2p/base/p2ptransportchannel.cc |
| diff --git a/webrtc/p2p/base/p2ptransportchannel.cc b/webrtc/p2p/base/p2ptransportchannel.cc |
| index 94eb01754d459111533fa7f9a7c71e9e5e3223d1..44ce095dc2de962f19c993dca977766d7b2b6657 100644 |
| --- a/webrtc/p2p/base/p2ptransportchannel.cc |
| +++ b/webrtc/p2p/base/p2ptransportchannel.cc |
| @@ -565,7 +565,7 @@ void P2PTransportChannel::OnUnknownAddress( |
| // There shouldn't be an existing connection with this remote address. |
| // When ports are muxed, this channel might get multiple unknown address |
| // signals. In that case if the connection is already exists, we should |
| - // simply ignore the signal othewise send server error. |
| + // simply ignore the signal otherwise send server error. |
| if (port->GetConnection(remote_candidate.address())) { |
| if (port_muxed) { |
| LOG(LS_INFO) << "Connection already exists for peer reflexive " |
| @@ -596,6 +596,15 @@ void P2PTransportChannel::OnUnknownAddress( |
| AddConnection(connection); |
| connection->ReceivedPing(); |
| + bool received_use_candidate = |
| + stun_msg->GetByteString(STUN_ATTR_USE_CANDIDATE) != nullptr; |
| + if (received_use_candidate && ice_role_ == ICEROLE_CONTROLLED && |
| + protocol_type_ == ICEPROTO_RFC5245) { |
| + // This need to be after AddConnection so that the event |
| + // SignalUseCandidate is connected to this class. |
| + connection->set_nominated(true); |
| + } |
| + |
| // Send the pinger a successful stun response. |
| port->SendBindingResponse(stun_msg, address); |
| @@ -999,63 +1008,34 @@ void P2PTransportChannel::SortConnections() { |
| // Any changes after this point will require a re-sort. |
| sort_dirty_ = false; |
| - // Get a list of the networks that we are using. |
| - std::set<rtc::Network*> networks; |
| - for (uint32 i = 0; i < connections_.size(); ++i) |
| - networks.insert(connections_[i]->port()->Network()); |
| - |
| // Find the best alternative connection by sorting. It is important to note |
| // that amongst equal preference, writable connections, this will choose the |
| // one whose estimated latency is lowest. So it is the only one that we |
| // need to consider switching to. |
| - |
| ConnectionCompare cmp; |
| std::stable_sort(connections_.begin(), connections_.end(), cmp); |
| LOG(LS_VERBOSE) << "Sorting available connections:"; |
| for (uint32 i = 0; i < connections_.size(); ++i) { |
| LOG(LS_VERBOSE) << connections_[i]->ToString(); |
| } |
| - |
| - Connection* top_connection = NULL; |
| - if (connections_.size() > 0) |
| - top_connection = connections_[0]; |
| - |
| - // We don't want to pick the best connections if channel is using RFC5245 |
| - // and it's mode is CONTROLLED, as connections will be selected by the |
| - // CONTROLLING agent. |
| + Connection* top_connection = |
| + (connections_.size() > 0) ? connections_[0] : nullptr; |
| // If necessary, switch to the new choice. |
| - if (protocol_type_ != ICEPROTO_RFC5245 || ice_role_ == ICEROLE_CONTROLLING) { |
| - if (ShouldSwitch(best_connection_, top_connection)) { |
| - LOG(LS_INFO) << "Switching best connection on controlling side: " |
| - << top_connection->ToString(); |
| - SwitchBestConnectionTo(top_connection); |
| - } |
| + // Note that top_connection don't have to be writable to be |
|
juberti1
2015/08/07 01:31:19
don't ->doesn't
honghaiz3
2015/08/07 20:42:04
Done.
|
| + // switched to although it will have higher priority if it is writable. |
| + // Controlled side can switch the best connection only if the best connection |
| + // was not nominated yet. |
| + if ((protocol_type_ != ICEPROTO_RFC5245 || ice_role_ == ICEROLE_CONTROLLING || |
| + !best_nominated_connection()) && |
| + ShouldSwitch(best_connection_, top_connection)) { |
| + LOG(LS_INFO) << "Switching best connection: " << top_connection->ToString(); |
| + SwitchBestConnectionTo(top_connection); |
| } |
| - // We can prune any connection for which there is a connected, writable |
| - // connection on the same network with better or equal priority. We leave |
| - // those with better priority just in case they become writable later (at |
| - // which point, we would prune out the current best connection). We leave |
| - // connections on other networks because they may not be using the same |
| - // resources and they may represent very distinct paths over which we can |
| - // switch. If the |primier| connection is not connected, we may be |
| - // reconnecting a TCP connection and temporarily do not prune connections in |
| - // this network. See the big comment in CompareConnections. |
| - std::set<rtc::Network*>::iterator network; |
| - for (network = networks.begin(); network != networks.end(); ++network) { |
| - Connection* primier = GetBestConnectionOnNetwork(*network); |
| - if (!primier || (primier->write_state() != Connection::STATE_WRITABLE) || |
| - !primier->connected()) |
| - continue; |
| - |
| - for (uint32 i = 0; i < connections_.size(); ++i) { |
| - if ((connections_[i] != primier) && |
| - (connections_[i]->port()->Network() == *network) && |
| - (CompareConnectionCandidates(primier, connections_[i]) >= 0)) { |
| - connections_[i]->Prune(); |
| - } |
| - } |
| + // Controlled side can prune only if the best connection has been nominated. |
| + if (ice_role_ == ICEROLE_CONTROLLING || best_nominated_connection()) { |
| + PruneConnections(); |
| } |
| // Check if all connections are timedout. |
| @@ -1082,6 +1062,43 @@ void P2PTransportChannel::SortConnections() { |
| UpdateChannelState(); |
| } |
| +Connection* P2PTransportChannel::best_nominated_connection() const { |
| + return (best_connection_ && best_connection_->nominated()) ? best_connection_ |
| + : nullptr; |
| +} |
| + |
| +void P2PTransportChannel::PruneConnections() { |
| + // We can prune any connection for which there is a connected, writable |
| + // connection on the same network with better or equal priority. We leave |
| + // those with better priority just in case they become writable later (at |
| + // which point, we would prune out the current best connection). We leave |
| + // connections on other networks because they may not be using the same |
| + // resources and they may represent very distinct paths over which we can |
| + // switch. If the |primier| connection is not connected, we may be |
| + // reconnecting a TCP connection and temporarily do not prune connections in |
| + // this network. See the big comment in CompareConnections. |
| + // NOTE: If the ICE role is controlled and it has not received requests with |
| + // use_candidate yet, do not prune the connections because it may delete the |
| + // connection that will be selected by the controlling side. |
| + |
| + // Get a list of the networks that we are using. |
| + std::set<rtc::Network*> networks; |
| + for (uint32 i = 0; i < connections_.size(); ++i) |
| + networks.insert(connections_[i]->port()->Network()); |
| + for (auto network : networks) { |
| + Connection* primier = GetBestConnectionOnNetwork(network); |
| + if (!(primier && primier->writable() && primier->connected())) |
| + continue; |
| + |
| + for (auto connection : connections_) { |
| + if ((connection != primier) && |
| + (connection->port()->Network() == network) && |
| + (CompareConnectionCandidates(primier, connection) >= 0)) { |
| + connection->Prune(); |
| + } |
| + } |
| + } |
| +} |
| // Track the best connection, and let listeners know |
| void P2PTransportChannel::SwitchBestConnectionTo(Connection* conn) { |
| @@ -1417,6 +1434,13 @@ void P2PTransportChannel::OnReadPacket( |
| // Let the client know of an incoming packet |
| SignalReadPacket(this, data, len, packet_time, 0); |
| + |
| + // May need to switch the sending connection based on the receiving media path |
| + // if this is the controlled side. |
| + if (best_connection_ != connection && ice_role_ == ICEROLE_CONTROLLED && |
| + !best_nominated_connection() && connection->writable()) { |
| + SwitchBestConnectionTo(connection); |
| + } |
| } |
| void P2PTransportChannel::OnReadyToSend(Connection* connection) { |