Chromium Code Reviews| Index: webrtc/p2p/client/basicportallocator.cc |
| diff --git a/webrtc/p2p/client/basicportallocator.cc b/webrtc/p2p/client/basicportallocator.cc |
| index e39a44013cdcf4f5b4cf627e225c499afb1e1687..c5de5b61f911b36f1d6e901d9d411f65a7cfbb2a 100644 |
| --- a/webrtc/p2p/client/basicportallocator.cc |
| +++ b/webrtc/p2p/client/basicportallocator.cc |
| @@ -138,7 +138,6 @@ BasicPortAllocatorSession::BasicPortAllocatorSession( |
| socket_factory_(allocator->socket_factory()), |
| allocation_started_(false), |
| network_manager_started_(false), |
| - running_(false), |
| allocation_sequences_created_(false) { |
| allocator_->network_manager()->SignalNetworksChanged.connect( |
| this, &BasicPortAllocatorSession::OnNetworksChanged); |
| @@ -198,23 +197,72 @@ void BasicPortAllocatorSession::StartGettingPorts() { |
| socket_factory_ = owned_socket_factory_.get(); |
| } |
| - running_ = true; |
| + running_ = STATE_RUNNING; |
|
Taylor Brandstetter
2016/06/21 23:36:12
Should be "state_ = STATE_RUNNING"? Also can "runn
|
| network_thread_->Post(RTC_FROM_HERE, this, MSG_CONFIG_START); |
| } |
| void BasicPortAllocatorSession::StopGettingPorts() { |
| ASSERT(rtc::Thread::Current() == network_thread_); |
| - running_ = false; |
| + state_ = STATE_STOPPED; |
| network_thread_->Post(RTC_FROM_HERE, this, MSG_CONFIG_STOP); |
| ClearGettingPorts(); |
| } |
| void BasicPortAllocatorSession::ClearGettingPorts() { |
| + state_ = STATE_CLEARED; |
| network_thread_->Clear(this, MSG_ALLOCATE); |
| for (uint32_t i = 0; i < sequences_.size(); ++i) |
| sequences_[i]->Stop(); |
| } |
| +std::vector<rtc::Network*> BasicPortAllocatorSession::GetFailedNetworks() { |
| + rtc::NetworkManager::NetworkList networks = GetNetworks(); |
| + |
| + // Whether a network has at least one connection, keyed by interface name. |
| + // So if an adapter interface has both IPv4 and IPv6 networks, they will |
| + // be considered as one network. |
| + std::map<std::string, bool> network_has_connection; |
| + for (const PortData& data : ports_) { |
| + PortInterface* port = data.port(); |
| + if (!port->connections().empty()) { |
| + network_has_connection[port->Network()->name()] = true; |
| + } |
| + } |
| + |
| + networks.erase( |
| + std::remove_if(networks.begin(), networks.end(), |
| + [network_has_connection](rtc::Network* network) { |
| + // If a network does not have any connection, it is |
| + // considered failed. |
| + return network_has_connection[network->name()]; |
| + }), |
| + networks.end()); |
| + return networks; |
| +} |
| + |
| +void BasicPortAllocatorSession::RegatherOnFailedNetworks() { |
| + // Find the list of networks that have no connection. |
| + rtc::NetworkManager::NetworkList networks = GetFailedNetworks(); |
| + if (networks.empty()) { |
| + return; |
| + } |
| + |
| + // Inactivate sequences whose networks are in failed |networks|, |
| + // so that they won't be considered as duplicates when the session |
| + // regathers ports and candidates. |
| + for (AllocationSequence* sequence : sequences_) { |
| + if (!sequence->network_inactive() && |
| + std::find(networks->begin(), networks->end(), sequence->network()) != |
| + networks->end()) { |
| + sequence->set_network_inactive(true); |
| + // Close ports and signal candidate removals. |
| + sequence->ClosePorts(); |
| + } |
| + } |
| + |
| + StartGettingPorts(); |
| +} |
| + |
| std::vector<PortInterface*> BasicPortAllocatorSession::ReadyPorts() const { |
| std::vector<PortInterface*> ret; |
| for (const PortData& port : ports_) { |
| @@ -243,6 +291,18 @@ std::vector<Candidate> BasicPortAllocatorSession::ReadyCandidates() const { |
| return candidates; |
| } |
| +std::vector<Candidate> BasicPortAllocatorSession::ReadyCandidates( |
| + PortInterface* port) const { |
| + std::vector<Candidate> candidates; |
| + for (const Candidate& candidate : port->Candidates()) { |
| + if (!CheckCandidateFilter(candidate)) { |
| + continue; |
| + } |
| + candidates.push_back(SanitizeRelatedAddress(candidate)); |
| + } |
| + return candidates; |
| +} |
| + |
| Candidate BasicPortAllocatorSession::SanitizeRelatedAddress( |
| const Candidate& c) const { |
| Candidate copy = c; |
| @@ -391,9 +451,8 @@ void BasicPortAllocatorSession::OnAllocate() { |
| allocation_started_ = true; |
| } |
| -void BasicPortAllocatorSession::GetNetworks( |
| - std::vector<rtc::Network*>* networks) { |
| - networks->clear(); |
| +std::vector<rtc::Network*> BasicPortAllocatorSession::GetNetworks() const { |
| + std::vector<rtc::Network*> networks; |
| rtc::NetworkManager* network_manager = allocator_->network_manager(); |
| ASSERT(network_manager != nullptr); |
| // If the network permission state is BLOCKED, we just act as if the flag has |
| @@ -407,9 +466,9 @@ void BasicPortAllocatorSession::GetNetworks( |
| // traffic by OS is also used here to avoid any local or public IP leakage |
| // during stun process. |
| if (flags() & PORTALLOCATOR_DISABLE_ADAPTER_ENUMERATION) { |
| - network_manager->GetAnyAddressNetworks(networks); |
| + network_manager->GetAnyAddressNetworks(&networks); |
| } else { |
| - network_manager->GetNetworks(networks); |
| + network_manager->GetNetworks(&networks); |
| } |
| networks->erase(std::remove_if(networks->begin(), networks->end(), |
| [this](rtc::Network* network) { |
| @@ -430,14 +489,14 @@ void BasicPortAllocatorSession::GetNetworks( |
| }), |
| networks->end()); |
| } |
| + return networks; |
| } |
| // For each network, see if we have a sequence that covers it already. If not, |
| // create a new sequence to create the appropriate ports. |
| void BasicPortAllocatorSession::DoAllocate() { |
| bool done_signal_needed = false; |
| - std::vector<rtc::Network*> networks; |
| - GetNetworks(&networks); |
| + std::vector<rtc::Network*> networks = GetNetworks(); |
| if (networks.empty()) { |
| LOG(LS_WARNING) << "Machine has no networks; no ports will be allocated"; |
| @@ -485,8 +544,12 @@ void BasicPortAllocatorSession::DoAllocate() { |
| done_signal_needed = true; |
| sequence->SignalPortAllocationComplete.connect( |
| this, &BasicPortAllocatorSession::OnPortAllocationComplete); |
| - if (running_) |
| + // TODO(honghaiz): Move this check at the beginning of the method. I do |
| + // not see the point of creating a sequence without starting it. Will |
| + // do this in a separate CL. |
| + if (CanGetPorts()) { |
| sequence->Start(); |
| + } |
| sequences_.push_back(sequence); |
| } |
| } |
| @@ -496,15 +559,14 @@ void BasicPortAllocatorSession::DoAllocate() { |
| } |
| void BasicPortAllocatorSession::OnNetworksChanged() { |
| - std::vector<rtc::Network*> networks; |
| - GetNetworks(&networks); |
| + std::vector<rtc::Network*> networks = GetNetworks(); |
| for (AllocationSequence* sequence : sequences_) { |
| // Remove the network from the allocation sequence if it is not in |
| // |networks|. |
| - if (!sequence->network_removed() && |
| + if (!sequence->network_inactive() && |
| std::find(networks.begin(), networks.end(), sequence->network()) == |
| networks.end()) { |
| - sequence->OnNetworkRemoved(); |
| + sequence->OnNetworkInactivated(); |
| } |
| } |
| @@ -544,6 +606,8 @@ void BasicPortAllocatorSession::AddAllocatedPort(Port* port, |
| port->SignalCandidateReady.connect( |
| this, &BasicPortAllocatorSession::OnCandidateReady); |
| + port->SignalCandidatesRemoved.connect( |
| + this, &BasicPortAllocatorSession::OnCandidatesRemoved); |
| port->SignalPortComplete.connect(this, |
| &BasicPortAllocatorSession::OnPortComplete); |
| port->SignalDestroyed.connect(this, |
| @@ -601,6 +665,28 @@ void BasicPortAllocatorSession::OnCandidateReady( |
| } |
| } |
| +void BasicPortAllocatorSession::OnCandidatesRemoved( |
| + Port* port, |
| + const std::vector<Candidate>& candidates) { |
| + ASSERT(rtc::Thread::Current() == network_thread_); |
| + PortData* data = FindPort(port); |
| + ASSERT(data != NULL); |
| + |
| + std::vector<Candidate> filtered_candidates; |
| + for (Candidate c : candidates) { |
| + ProtocolType pvalue; |
| + bool candidate_protocol_enabled = |
| + StringToProto(c.protocol().c_str(), &pvalue) && |
| + data->sequence()->ProtocolEnabled(pvalue); |
| + if (candidate_protocol_enabled && CheckCandidateFilter(c)) { |
| + filtered_candidates.push_back(SanitizeRelatedAddress(c)); |
| + } |
| + } |
| + if (!filtered_candidates.empty()) { |
| + SignalCandidatesRemoved(this, filtered_candidates); |
| + } |
| +} |
| + |
| void BasicPortAllocatorSession::OnPortComplete(Port* port) { |
| ASSERT(rtc::Thread::Current() == network_thread_); |
| PortData* data = FindPort(port); |
| @@ -793,10 +879,10 @@ void AllocationSequence::Clear() { |
| turn_ports_.clear(); |
| } |
| -void AllocationSequence::OnNetworkRemoved() { |
| +void AllocationSequence::OnNetworkInactivated() { |
| // Stop the allocation sequence if its network is gone. |
| + network_inactive_ = true; |
|
Taylor Brandstetter
2016/06/21 23:36:12
nit: Would be better to store this bool as "networ
|
| Stop(); |
| - network_removed_ = true; |
| } |
| AllocationSequence::~AllocationSequence() { |
| @@ -805,8 +891,8 @@ AllocationSequence::~AllocationSequence() { |
| void AllocationSequence::DisableEquivalentPhases(rtc::Network* network, |
| PortConfiguration* config, uint32_t* flags) { |
| - if (network_removed_) { |
| - // If the network of this allocation sequence has ever gone away, |
| + if (network_inactive_) { |
| + // If the network of this allocation sequence has ever become inactive, |
| // it won't be equivalent to the new network. |
| return; |
| } |
| @@ -851,6 +937,15 @@ void AllocationSequence::Stop() { |
| } |
| } |
| +void AllocationSequence::ClosePorts() { |
| + if (udp_port_) { |
| + udp_port_->CloseAndSignalCandidateRemovals(); |
| + } |
| + for (Port& port : turn_ports_) { |
| + port.CloseAndSignalCandidateRemovals(); |
| + } |
| +} |
| + |
| void AllocationSequence::OnMessage(rtc::Message* msg) { |
| ASSERT(rtc::Thread::Current() == session_->network_thread()); |
| ASSERT(msg->message_id == MSG_ALLOCATION_PHASE); |