Index: webrtc/p2p/base/p2ptransportchannel.cc |
diff --git a/webrtc/p2p/base/p2ptransportchannel.cc b/webrtc/p2p/base/p2ptransportchannel.cc |
index da8b5f76c2f7b85d6684975f1c66881fec25e2f0..9693b7cee8d4e7e252e3f3a6d8606b57e4278d3c 100644 |
--- a/webrtc/p2p/base/p2ptransportchannel.cc |
+++ b/webrtc/p2p/base/p2ptransportchannel.cc |
@@ -218,7 +218,6 @@ P2PTransportChannel::P2PTransportChannel(const std::string& transport_name, |
remote_ice_mode_(ICEMODE_FULL), |
ice_role_(ICEROLE_UNKNOWN), |
tiebreaker_(0), |
- remote_candidate_generation_(0), |
gathering_state_(kIceGatheringNew), |
check_receiving_delay_(MIN_CHECK_RECEIVING_DELAY * 5), |
receiving_timeout_(MIN_CHECK_RECEIVING_DELAY * 50), |
@@ -347,26 +346,19 @@ void P2PTransportChannel::SetIceCredentials(const std::string& ice_ufrag, |
void P2PTransportChannel::SetRemoteIceCredentials(const std::string& ice_ufrag, |
const std::string& ice_pwd) { |
ASSERT(worker_thread_ == rtc::Thread::Current()); |
- bool ice_restart = false; |
- if (!remote_ice_ufrag_.empty() && !remote_ice_pwd_.empty()) { |
- ice_restart = (remote_ice_ufrag_ != ice_ufrag) || |
- (remote_ice_pwd_!= ice_pwd); |
+ IceParameters* current_ice = remote_ice(); |
+ IceParameters new_ice(ice_ufrag, ice_pwd); |
+ if (!current_ice || *current_ice != new_ice) { |
+ // Keep the ICE credentials so that newer connections |
+ // are prioritized over the older ones. |
+ remote_ice_parameters_.push_back(new_ice); |
} |
- remote_ice_ufrag_ = ice_ufrag; |
- remote_ice_pwd_ = ice_pwd; |
- |
// We need to update the credentials for any peer reflexive candidates. |
std::vector<Connection*>::iterator it = connections_.begin(); |
for (; it != connections_.end(); ++it) { |
(*it)->MaybeSetRemoteIceCredentials(ice_ufrag, ice_pwd); |
} |
- |
- if (ice_restart) { |
- // We need to keep track of the remote ice restart so newer |
- // connections are prioritized over the older. |
- ++remote_candidate_generation_; |
- } |
} |
void P2PTransportChannel::SetRemoteIceMode(IceMode mode) { |
@@ -536,8 +528,11 @@ void P2PTransportChannel::OnUnknownAddress( |
// The STUN binding request may arrive after setRemoteDescription and before |
// adding remote candidate, so we need to set the password to the shared |
// password if the user name matches. |
- if (remote_password.empty() && remote_username == remote_ice_ufrag_) { |
- remote_password = remote_ice_pwd_; |
+ if (remote_password.empty()) { |
+ IceParameters* current_ice = remote_ice(); |
+ if (current_ice && remote_username == current_ice->ufrag) { |
+ remote_password = current_ice->pwd; |
+ } |
} |
Candidate remote_candidate; |
@@ -655,19 +650,39 @@ void P2PTransportChannel::OnNominated(Connection* conn) { |
void P2PTransportChannel::AddRemoteCandidate(const Candidate& candidate) { |
ASSERT(worker_thread_ == rtc::Thread::Current()); |
- uint32_t generation = candidate.generation(); |
- // Network may not guarantee the order of the candidate delivery. If a |
- // remote candidate with an older generation arrives, drop it. |
- if (generation != 0 && generation < remote_candidate_generation_) { |
- LOG(LS_WARNING) << "Dropping a remote candidate because its generation " |
- << generation |
- << " is lower than the current remote generation " |
- << remote_candidate_generation_; |
+ uint32_t generation = GetRemoteCandidateGeneration(candidate); |
+ // If a remote candidate with a previous generation arrives, drop it. |
+ if (generation < remote_ice_generation()) { |
+ LOG(LS_WARNING) << "Dropping a remote candidate because its ufrag " |
+ << candidate.username() |
+ << " indicates it was for a previous generation."; |
return; |
} |
+ Candidate new_remote_candidate(candidate); |
+ new_remote_candidate.set_generation(generation); |
+ // ICE candidates don't need to have username and password set, but |
+ // the code below this (specifically, ConnectionRequest::Prepare in |
+ // port.cc) uses the remote candidates's username. So, we set it |
+ // here. |
+ if (remote_ice()) { |
+ if (candidate.username().empty()) { |
+ new_remote_candidate.set_username(remote_ice()->ufrag); |
+ } |
+ if (new_remote_candidate.username() == remote_ice()->ufrag) { |
+ if (candidate.password().empty()) { |
+ new_remote_candidate.set_password(remote_ice()->pwd); |
+ } |
+ } else { |
+ // The candidate belongs to the next generation. Its pwd will be set |
+ // when the new remote ICE credentials arrive. |
+ LOG(LS_WARNING) << "A remote candidate arrives with an unknown ufrag: " |
+ << candidate.username(); |
+ } |
+ } |
+ |
// Create connections to this remote candidate. |
- CreateConnections(candidate, NULL); |
+ CreateConnections(new_remote_candidate, NULL); |
// Resort the connections list, which may have new elements. |
SortConnections(); |
@@ -680,20 +695,6 @@ bool P2PTransportChannel::CreateConnections(const Candidate& remote_candidate, |
PortInterface* origin_port) { |
ASSERT(worker_thread_ == rtc::Thread::Current()); |
- Candidate new_remote_candidate(remote_candidate); |
- new_remote_candidate.set_generation( |
- GetRemoteCandidateGeneration(remote_candidate)); |
- // ICE candidates don't need to have username and password set, but |
- // the code below this (specifically, ConnectionRequest::Prepare in |
- // port.cc) uses the remote candidates's username. So, we set it |
- // here. |
- if (remote_candidate.username().empty()) { |
- new_remote_candidate.set_username(remote_ice_ufrag_); |
- } |
- if (remote_candidate.password().empty()) { |
- new_remote_candidate.set_password(remote_ice_pwd_); |
- } |
- |
// If we've already seen the new remote candidate (in the current candidate |
// generation), then we shouldn't try creating connections for it. |
// We either already have a connection for it, or we previously created one |
@@ -702,7 +703,7 @@ bool P2PTransportChannel::CreateConnections(const Candidate& remote_candidate, |
// immediately be re-pruned, churning the network for no purpose. |
// This only applies to candidates received over signaling (i.e. origin_port |
// is NULL). |
- if (!origin_port && IsDuplicateRemoteCandidate(new_remote_candidate)) { |
+ if (!origin_port && IsDuplicateRemoteCandidate(remote_candidate)) { |
// return true to indicate success, without creating any new connections. |
return true; |
} |
@@ -715,7 +716,7 @@ bool P2PTransportChannel::CreateConnections(const Candidate& remote_candidate, |
bool created = false; |
std::vector<PortInterface *>::reverse_iterator it; |
for (it = ports_.rbegin(); it != ports_.rend(); ++it) { |
- if (CreateConnection(*it, new_remote_candidate, origin_port)) { |
+ if (CreateConnection(*it, remote_candidate, origin_port)) { |
if (*it == origin_port) |
created = true; |
} |
@@ -723,12 +724,12 @@ bool P2PTransportChannel::CreateConnections(const Candidate& remote_candidate, |
if ((origin_port != NULL) && |
std::find(ports_.begin(), ports_.end(), origin_port) == ports_.end()) { |
- if (CreateConnection(origin_port, new_remote_candidate, origin_port)) |
+ if (CreateConnection(origin_port, remote_candidate, origin_port)) |
created = true; |
} |
// Remember this remote candidate so that we can add it to future ports. |
- RememberRemoteCandidate(new_remote_candidate, origin_port); |
+ RememberRemoteCandidate(remote_candidate, origin_port); |
return created; |
} |
@@ -786,9 +787,27 @@ uint32_t P2PTransportChannel::GetRemoteCandidateGeneration( |
const Candidate& candidate) { |
// We need to keep track of the remote ice restart so newer |
// connections are prioritized over the older. |
- ASSERT(candidate.generation() == 0 || |
- candidate.generation() == remote_candidate_generation_); |
- return remote_candidate_generation_; |
+ const auto& params = remote_ice_parameters_; |
+ if (!candidate.username().empty()) { |
+ // If remote side sets the ufrag, we use that to determine the candidate |
+ // generation. |
+ // Search backward as it is more likely to find it near the end. |
+ auto it = std::find_if(params.rbegin(), params.rend(), |
+ [candidate](const IceParameters& param) { |
+ return param.ufrag == candidate.username(); |
+ }); |
+ if (it == params.rend()) { |
+ // If not found, assume it is the next (future) generation. |
+ return static_cast<uint32_t>(remote_ice_parameters_.size()); |
+ } |
+ return params.rend() - it - 1; |
+ } |
+ // If candidate generation is set, use that. |
+ if (candidate.generation() > 0) { |
+ return candidate.generation(); |
+ } |
+ // Otherwise, assume the generation from remote ice parameters. |
+ return remote_ice_generation(); |
} |
// Check if remote candidate is already cached. |