| Index: webrtc/p2p/client/basicportallocator.cc
|
| diff --git a/webrtc/p2p/client/basicportallocator.cc b/webrtc/p2p/client/basicportallocator.cc
|
| index edd5fed9cf55843c8e56a7d8089c6ec4a61c4dba..d85548f39659457c61af7dd8dd2b37f0400ee546 100644
|
| --- a/webrtc/p2p/client/basicportallocator.cc
|
| +++ b/webrtc/p2p/client/basicportallocator.cc
|
| @@ -184,7 +184,6 @@ BasicPortAllocatorSession::BasicPortAllocatorSession(
|
| socket_factory_(allocator->socket_factory()),
|
| allocation_started_(false),
|
| network_manager_started_(false),
|
| - running_(false),
|
| allocation_sequences_created_(false),
|
| prune_turn_ports_(allocator->prune_turn_ports()) {
|
| allocator_->network_manager()->SignalNetworksChanged.connect(
|
| @@ -239,27 +238,84 @@ void BasicPortAllocatorSession::SetCandidateFilter(uint32_t filter) {
|
|
|
| void BasicPortAllocatorSession::StartGettingPorts() {
|
| network_thread_ = rtc::Thread::Current();
|
| + PortAllocatorSession::StartGettingPorts();
|
| if (!socket_factory_) {
|
| owned_socket_factory_.reset(
|
| new rtc::BasicPacketSocketFactory(network_thread_));
|
| socket_factory_ = owned_socket_factory_.get();
|
| }
|
|
|
| - running_ = true;
|
| network_thread_->Post(RTC_FROM_HERE, this, MSG_CONFIG_START);
|
| }
|
|
|
| void BasicPortAllocatorSession::StopGettingPorts() {
|
| ASSERT(rtc::Thread::Current() == network_thread_);
|
| - running_ = false;
|
| network_thread_->Post(RTC_FROM_HERE, this, MSG_CONFIG_STOP);
|
| ClearGettingPorts();
|
| + // Note: this must be called after ClearGettingPorts because both may set the
|
| + // session state and we should set the state to STOPPED.
|
| + PortAllocatorSession::StopGettingPorts();
|
| }
|
|
|
| void BasicPortAllocatorSession::ClearGettingPorts() {
|
| + ASSERT(rtc::Thread::Current() == network_thread_);
|
| network_thread_->Clear(this, MSG_ALLOCATE);
|
| - for (uint32_t i = 0; i < sequences_.size(); ++i)
|
| + for (uint32_t i = 0; i < sequences_.size(); ++i) {
|
| sequences_[i]->Stop();
|
| + }
|
| + PortAllocatorSession::ClearGettingPorts();
|
| +}
|
| +
|
| +std::vector<rtc::Network*> BasicPortAllocatorSession::GetFailedNetworks() {
|
| + std::vector<rtc::Network*> networks = GetNetworks();
|
| +
|
| + // A network interface may have both IPv4 and IPv6 networks. Only if
|
| + // neither of the networks has any connections, the network interface
|
| + // is considered failed and need to be regathered on.
|
| + std::set<std::string> networks_with_connection;
|
| + for (const PortData& data : ports_) {
|
| + Port* port = data.port();
|
| + if (!port->connections().empty()) {
|
| + networks_with_connection.insert(port->Network()->name());
|
| + }
|
| + }
|
| +
|
| + networks.erase(
|
| + std::remove_if(networks.begin(), networks.end(),
|
| + [networks_with_connection](rtc::Network* network) {
|
| + // If a network does not have any connection, it is
|
| + // considered failed.
|
| + return networks_with_connection.find(network->name()) !=
|
| + networks_with_connection.end();
|
| + }),
|
| + networks.end());
|
| + return networks;
|
| +}
|
| +
|
| +void BasicPortAllocatorSession::RegatherOnFailedNetworks() {
|
| + // Find the list of networks that have no connection.
|
| + std::vector<rtc::Network*> failed_networks = GetFailedNetworks();
|
| + if (failed_networks.empty()) {
|
| + return;
|
| + }
|
| +
|
| + // Mark a sequence as "network failed" if its network is in the list of failed
|
| + // networks, so that it won't be considered as equivalent when the session
|
| + // regathers ports and candidates.
|
| + for (AllocationSequence* sequence : sequences_) {
|
| + if (!sequence->network_failed() &&
|
| + std::find(failed_networks.begin(), failed_networks.end(),
|
| + sequence->network()) != failed_networks.end()) {
|
| + sequence->set_network_failed();
|
| + }
|
| + }
|
| + // Remove ports from being used locally and send signaling to remove
|
| + // the candidates on the remote side.
|
| + RemovePortsAndCandidates(failed_networks);
|
| +
|
| + if (allocation_started_ && network_manager_started_) {
|
| + DoAllocate();
|
| + }
|
| }
|
|
|
| std::vector<PortInterface*> BasicPortAllocatorSession::ReadyPorts() const {
|
| @@ -278,20 +334,26 @@ std::vector<Candidate> BasicPortAllocatorSession::ReadyCandidates() const {
|
| if (!data.ready()) {
|
| continue;
|
| }
|
| + GetCandidatesFromPort(data, &candidates);
|
| + }
|
| + return candidates;
|
| +}
|
|
|
| - for (const Candidate& candidate : data.port()->Candidates()) {
|
| - if (!CheckCandidateFilter(candidate)) {
|
| - continue;
|
| - }
|
| - ProtocolType pvalue;
|
| - if (!StringToProto(candidate.protocol().c_str(), &pvalue) ||
|
| - !data.sequence()->ProtocolEnabled(pvalue)) {
|
| - continue;
|
| - }
|
| - candidates.push_back(SanitizeRelatedAddress(candidate));
|
| +void BasicPortAllocatorSession::GetCandidatesFromPort(
|
| + const PortData& data,
|
| + std::vector<Candidate>* candidates) const {
|
| + RTC_CHECK(candidates != nullptr);
|
| + for (const Candidate& candidate : data.port()->Candidates()) {
|
| + if (!CheckCandidateFilter(candidate)) {
|
| + continue;
|
| + }
|
| + ProtocolType pvalue;
|
| + if (!StringToProto(candidate.protocol().c_str(), &pvalue) ||
|
| + !data.sequence()->ProtocolEnabled(pvalue)) {
|
| + continue;
|
| }
|
| + candidates->push_back(SanitizeRelatedAddress(candidate));
|
| }
|
| - return candidates;
|
| }
|
|
|
| Candidate BasicPortAllocatorSession::SanitizeRelatedAddress(
|
| @@ -437,9 +499,8 @@ void BasicPortAllocatorSession::OnAllocate() {
|
| allocation_started_ = true;
|
| }
|
|
|
| -void BasicPortAllocatorSession::GetNetworks(
|
| - std::vector<rtc::Network*>* networks) {
|
| - networks->clear();
|
| +std::vector<rtc::Network*> BasicPortAllocatorSession::GetNetworks() {
|
| + 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
|
| @@ -453,37 +514,37 @@ 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) {
|
| - return allocator_->network_ignore_mask() &
|
| - network->type();
|
| - }),
|
| - networks->end());
|
| + networks.erase(std::remove_if(networks.begin(), networks.end(),
|
| + [this](rtc::Network* network) {
|
| + return allocator_->network_ignore_mask() &
|
| + network->type();
|
| + }),
|
| + networks.end());
|
|
|
| if (flags() & PORTALLOCATOR_DISABLE_COSTLY_NETWORKS) {
|
| uint16_t lowest_cost = rtc::kNetworkCostMax;
|
| - for (rtc::Network* network : *networks) {
|
| + for (rtc::Network* network : networks) {
|
| lowest_cost = std::min<uint16_t>(lowest_cost, network->GetCost());
|
| }
|
| - networks->erase(std::remove_if(networks->begin(), networks->end(),
|
| - [lowest_cost](rtc::Network* network) {
|
| - return network->GetCost() >
|
| - lowest_cost + rtc::kNetworkCostLow;
|
| - }),
|
| - networks->end());
|
| + networks.erase(std::remove_if(networks.begin(), networks.end(),
|
| + [lowest_cost](rtc::Network* network) {
|
| + return network->GetCost() >
|
| + lowest_cost + rtc::kNetworkCostLow;
|
| + }),
|
| + 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";
|
| @@ -528,8 +589,9 @@ void BasicPortAllocatorSession::DoAllocate() {
|
| done_signal_needed = true;
|
| sequence->SignalPortAllocationComplete.connect(
|
| this, &BasicPortAllocatorSession::OnPortAllocationComplete);
|
| - if (running_)
|
| + if (!IsStopped()) {
|
| sequence->Start();
|
| + }
|
| sequences_.push_back(sequence);
|
| }
|
| }
|
| @@ -539,17 +601,19 @@ void BasicPortAllocatorSession::DoAllocate() {
|
| }
|
|
|
| void BasicPortAllocatorSession::OnNetworksChanged() {
|
| - std::vector<rtc::Network*> networks;
|
| - GetNetworks(&networks);
|
| + std::vector<rtc::Network*> networks = GetNetworks();
|
| + std::vector<rtc::Network*> failed_networks;
|
| for (AllocationSequence* sequence : sequences_) {
|
| // Remove the network from the allocation sequence if it is not in
|
| // |networks|.
|
| - if (!sequence->network_removed() &&
|
| + if (!sequence->network_failed() &&
|
| std::find(networks.begin(), networks.end(), sequence->network()) ==
|
| networks.end()) {
|
| - sequence->OnNetworkRemoved();
|
| + sequence->OnNetworkFailed();
|
| + failed_networks.push_back(sequence->network());
|
| }
|
| }
|
| + RemovePortsAndCandidates(failed_networks);
|
|
|
| network_manager_started_ = true;
|
| if (allocation_started_)
|
| @@ -847,6 +911,23 @@ BasicPortAllocatorSession::PortData* BasicPortAllocatorSession::FindPort(
|
| return NULL;
|
| }
|
|
|
| +// Removes ports and candidates created on a given list of networks.
|
| +void BasicPortAllocatorSession::RemovePortsAndCandidates(
|
| + const std::vector<rtc::Network*>& networks) {
|
| + std::vector<PortInterface*> ports_to_remove;
|
| + std::vector<Candidate> candidates_to_remove;
|
| + for (const PortData& data : ports_) {
|
| + if (std::find(networks.begin(), networks.end(),
|
| + data.sequence()->network()) == networks.end()) {
|
| + continue;
|
| + }
|
| + ports_to_remove.push_back(data.port());
|
| + GetCandidatesFromPort(data, &candidates_to_remove);
|
| + }
|
| + SignalPortsRemoved(this, ports_to_remove);
|
| + SignalCandidatesRemoved(this, candidates_to_remove);
|
| +}
|
| +
|
| // AllocationSequence
|
|
|
| AllocationSequence::AllocationSequence(BasicPortAllocatorSession* session,
|
| @@ -884,10 +965,11 @@ void AllocationSequence::Clear() {
|
| turn_ports_.clear();
|
| }
|
|
|
| -void AllocationSequence::OnNetworkRemoved() {
|
| - // Stop the allocation sequence if its network is gone.
|
| +void AllocationSequence::OnNetworkFailed() {
|
| + RTC_DCHECK(!network_failed_);
|
| + network_failed_ = true;
|
| + // Stop the allocation sequence if its network failed.
|
| Stop();
|
| - network_removed_ = true;
|
| }
|
|
|
| AllocationSequence::~AllocationSequence() {
|
| @@ -896,8 +978,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_failed_) {
|
| + // If the network of this allocation sequence has ever become failed,
|
| // it won't be equivalent to the new network.
|
| return;
|
| }
|
|
|