Index: webrtc/p2p/client/basicportallocator.cc |
diff --git a/webrtc/p2p/client/basicportallocator.cc b/webrtc/p2p/client/basicportallocator.cc |
index e39a44013cdcf4f5b4cf627e225c499afb1e1687..edd5fed9cf55843c8e56a7d8089c6ec4a61c4dba 100644 |
--- a/webrtc/p2p/client/basicportallocator.cc |
+++ b/webrtc/p2p/client/basicportallocator.cc |
@@ -47,6 +47,47 @@ const int PHASE_SSLTCP = 3; |
const int kNumPhases = 4; |
+// Gets protocol priority: UDP > TCP > SSLTCP. |
+int GetProtocolPriority(cricket::ProtocolType protocol) { |
+ switch (protocol) { |
+ case cricket::PROTO_UDP: |
+ return 2; |
+ case cricket::PROTO_TCP: |
+ return 1; |
+ case cricket::PROTO_SSLTCP: |
+ return 0; |
+ default: |
+ RTC_DCHECK(false); |
+ return 0; |
+ } |
+} |
+// Gets address family priority: IPv6 > IPv4 > Unspecified. |
+int GetAddressFamilyPriority(int ip_family) { |
+ switch (ip_family) { |
+ case AF_INET6: |
+ return 2; |
+ case AF_INET: |
+ return 1; |
+ default: |
+ RTC_DCHECK(false); |
+ return 0; |
+ } |
+} |
+ |
+// Returns positive if a is better, negative if b is better, and 0 otherwise. |
+int ComparePort(const cricket::Port* a, const cricket::Port* b) { |
+ int a_protocol = GetProtocolPriority(a->GetProtocol()); |
+ int b_protocol = GetProtocolPriority(b->GetProtocol()); |
+ int cmp_protocol = a_protocol - b_protocol; |
+ if (cmp_protocol != 0) { |
+ return cmp_protocol; |
+ } |
+ |
+ int a_family = GetAddressFamilyPriority(a->Network()->GetBestIP().family()); |
+ int b_family = GetAddressFamilyPriority(b->Network()->GetBestIP().family()); |
+ return a_family - b_family; |
+} |
+ |
} // namespace |
namespace cricket { |
@@ -74,7 +115,7 @@ BasicPortAllocator::BasicPortAllocator(rtc::NetworkManager* network_manager, |
const ServerAddresses& stun_servers) |
: network_manager_(network_manager), socket_factory_(socket_factory) { |
ASSERT(socket_factory_ != NULL); |
- SetConfiguration(stun_servers, std::vector<RelayServerConfig>(), 0); |
+ SetConfiguration(stun_servers, std::vector<RelayServerConfig>(), 0, false); |
Construct(); |
} |
@@ -101,7 +142,7 @@ BasicPortAllocator::BasicPortAllocator( |
turn_servers.push_back(config); |
} |
- SetConfiguration(stun_servers, turn_servers, 0); |
+ SetConfiguration(stun_servers, turn_servers, 0, false); |
Construct(); |
} |
@@ -122,24 +163,30 @@ PortAllocatorSession* BasicPortAllocator::CreateSessionInternal( |
void BasicPortAllocator::AddTurnServer(const RelayServerConfig& turn_server) { |
std::vector<RelayServerConfig> new_turn_servers = turn_servers(); |
new_turn_servers.push_back(turn_server); |
- SetConfiguration(stun_servers(), new_turn_servers, candidate_pool_size()); |
+ SetConfiguration(stun_servers(), new_turn_servers, candidate_pool_size(), |
+ prune_turn_ports()); |
} |
// BasicPortAllocatorSession |
BasicPortAllocatorSession::BasicPortAllocatorSession( |
- BasicPortAllocator *allocator, |
+ BasicPortAllocator* allocator, |
const std::string& content_name, |
int component, |
const std::string& ice_ufrag, |
const std::string& ice_pwd) |
- : PortAllocatorSession(content_name, component, |
- ice_ufrag, ice_pwd, allocator->flags()), |
- allocator_(allocator), network_thread_(NULL), |
+ : PortAllocatorSession(content_name, |
+ component, |
+ ice_ufrag, |
+ ice_pwd, |
+ allocator->flags()), |
+ allocator_(allocator), |
+ network_thread_(NULL), |
socket_factory_(allocator->socket_factory()), |
allocation_started_(false), |
network_manager_started_(false), |
running_(false), |
- allocation_sequences_created_(false) { |
+ allocation_sequences_created_(false), |
+ prune_turn_ports_(allocator->prune_turn_ports()) { |
allocator_->network_manager()->SignalNetworksChanged.connect( |
this, &BasicPortAllocatorSession::OnNetworksChanged); |
allocator_->network_manager()->StartUpdating(); |
@@ -217,9 +264,9 @@ void BasicPortAllocatorSession::ClearGettingPorts() { |
std::vector<PortInterface*> BasicPortAllocatorSession::ReadyPorts() const { |
std::vector<PortInterface*> ret; |
- for (const PortData& port : ports_) { |
- if (port.has_pairable_candidate() && !port.error()) { |
- ret.push_back(port.port()); |
+ for (const PortData& data : ports_) { |
+ if (data.ready()) { |
+ ret.push_back(data.port()); |
} |
} |
return ret; |
@@ -228,6 +275,10 @@ std::vector<PortInterface*> BasicPortAllocatorSession::ReadyPorts() const { |
std::vector<Candidate> BasicPortAllocatorSession::ReadyCandidates() const { |
std::vector<Candidate> candidates; |
for (const PortData& data : ports_) { |
+ if (!data.ready()) { |
+ continue; |
+ } |
+ |
for (const Candidate& candidate : data.port()->Candidates()) { |
if (!CheckCandidateFilter(candidate)) { |
continue; |
@@ -278,16 +329,11 @@ bool BasicPortAllocatorSession::CandidatesAllocationDone() const { |
return false; |
} |
- // If all allocated ports are in complete state, session must have got all |
+ // If all allocated ports are no longer gathering, session must have got all |
// expected candidates. Session will trigger candidates allocation complete |
// signal. |
- if (!std::all_of(ports_.begin(), ports_.end(), [](const PortData& port) { |
- return (port.complete() || port.error()); |
- })) { |
- return false; |
- } |
- |
- return true; |
+ return std::none_of(ports_.begin(), ports_.end(), |
+ [](const PortData& port) { return port.inprogress(); }); |
} |
void BasicPortAllocatorSession::OnMessage(rtc::Message *message) { |
@@ -357,7 +403,7 @@ void BasicPortAllocatorSession::OnConfigStop() { |
bool send_signal = false; |
for (std::vector<PortData>::iterator it = ports_.begin(); |
it != ports_.end(); ++it) { |
- if (!it->complete() && !it->error()) { |
+ if (it->inprogress()) { |
// Updating port state to error, which didn't finish allocating candidates |
// yet. |
it->set_error(); |
@@ -443,11 +489,8 @@ void BasicPortAllocatorSession::DoAllocate() { |
LOG(LS_WARNING) << "Machine has no networks; no ports will be allocated"; |
done_signal_needed = true; |
} else { |
+ PortConfiguration* config = configs_.empty() ? nullptr : configs_.back(); |
for (uint32_t i = 0; i < networks.size(); ++i) { |
- PortConfiguration* config = NULL; |
- if (configs_.size() > 0) |
- config = configs_.back(); |
- |
uint32_t sequence_flags = flags(); |
if ((sequence_flags & DISABLE_ALL_PHASES) == DISABLE_ALL_PHASES) { |
// If all the ports are disabled we should just fire the allocation |
@@ -568,37 +611,85 @@ void BasicPortAllocatorSession::OnCandidateReady( |
PortData* data = FindPort(port); |
ASSERT(data != NULL); |
// Discarding any candidate signal if port allocation status is |
- // already in completed state. |
- if (data->complete() || data->error()) { |
+ // already done with gathering. |
+ if (!data->inprogress()) { |
return; |
} |
+ // Mark that the port has a pairable candidate, either because we have a |
+ // usable candidate from the port, or simply because the port is bound to the |
+ // any address and therefore has no host candidate. This will trigger the port |
+ // to start creating candidate pairs (connections) and issue connectivity |
+ // checks. If port has already been marked as having a pairable candidate, |
+ // do nothing here. |
+ // Note: We should check whether any candidates may become ready after this |
+ // because there we will check whether the candidate is generated by the ready |
+ // ports, which may include this port. |
+ bool pruned_port = false; |
+ if (CandidatePairable(c, port) && !data->has_pairable_candidate()) { |
+ data->set_has_pairable_candidate(true); |
+ |
+ if (prune_turn_ports_ && port->Type() == RELAY_PORT_TYPE) { |
+ pruned_port = PruneTurnPorts(port); |
+ } |
+ // If the current port is not pruned yet, SignalPortReady. |
+ if (!data->pruned()) { |
+ SignalPortReady(this, port); |
+ } |
+ } |
+ |
ProtocolType pvalue; |
bool candidate_protocol_enabled = |
StringToProto(c.protocol().c_str(), &pvalue) && |
data->sequence()->ProtocolEnabled(pvalue); |
- if (CheckCandidateFilter(c) && candidate_protocol_enabled) { |
+ if (data->ready() && CheckCandidateFilter(c) && candidate_protocol_enabled) { |
std::vector<Candidate> candidates; |
candidates.push_back(SanitizeRelatedAddress(c)); |
SignalCandidatesReady(this, candidates); |
} |
- // Port has already been marked as having a pairable candidate. |
- // Nothing to do here. |
- if (data->has_pairable_candidate()) { |
- return; |
+ // If we have pruned any port, maybe need to signal port allocation done. |
+ if (pruned_port) { |
+ MaybeSignalCandidatesAllocationDone(); |
} |
+} |
- // Mark that the port has a pairable candidate, either because we have a |
- // usable candidate from the port, or simply because the port is bound to the |
- // any address and therefore has no host candidate. This will trigger the port |
- // to start creating candidate pairs (connections) and issue connectivity |
- // checks. |
- if (CandidatePairable(c, port)) { |
- data->set_has_pairable_candidate(true); |
- SignalPortReady(this, port); |
+Port* BasicPortAllocatorSession::GetBestTurnPortForNetwork( |
+ const std::string& network_name) const { |
+ Port* best_turn_port = nullptr; |
+ for (const PortData& data : ports_) { |
+ if (data.port()->Network()->name() == network_name && |
+ data.port()->Type() == RELAY_PORT_TYPE && data.ready() && |
+ (!best_turn_port || ComparePort(data.port(), best_turn_port) > 0)) { |
+ best_turn_port = data.port(); |
+ } |
+ } |
+ return best_turn_port; |
+} |
+ |
+bool BasicPortAllocatorSession::PruneTurnPorts(Port* newly_pairable_turn_port) { |
+ bool pruned_port = false; |
+ // Note: We determine the same network based only on their network names. So |
+ // if an IPv4 address and an IPv6 address have the same network name, they |
+ // are considered the same network here. |
+ const std::string& network_name = newly_pairable_turn_port->Network()->name(); |
+ Port* best_turn_port = GetBestTurnPortForNetwork(network_name); |
+ // |port| is already in the list of ports, so the best port cannot be nullptr. |
+ RTC_CHECK(best_turn_port != nullptr); |
+ |
+ for (PortData& data : ports_) { |
+ if (data.port()->Network()->name() == network_name && |
+ data.port()->Type() == RELAY_PORT_TYPE && !data.pruned() && |
+ ComparePort(data.port(), best_turn_port) < 0) { |
+ data.set_pruned(); |
+ pruned_port = true; |
+ if (data.port() != newly_pairable_turn_port) { |
+ SignalPortPruned(this, data.port()); |
+ } |
+ } |
} |
+ return pruned_port; |
} |
void BasicPortAllocatorSession::OnPortComplete(Port* port) { |
@@ -607,7 +698,7 @@ void BasicPortAllocatorSession::OnPortComplete(Port* port) { |
ASSERT(data != NULL); |
// Ignore any late signals. |
- if (data->complete() || data->error()) { |
+ if (!data->inprogress()) { |
return; |
} |
@@ -622,7 +713,7 @@ void BasicPortAllocatorSession::OnPortError(Port* port) { |
PortData* data = FindPort(port); |
ASSERT(data != NULL); |
// We might have already given up on this port and stopped it. |
- if (data->complete() || data->error()) { |
+ if (!data->inprogress()) { |
return; |
} |
@@ -1028,13 +1119,11 @@ void AllocationSequence::CreateRelayPorts() { |
return; |
} |
- PortConfiguration::RelayList::const_iterator relay; |
- for (relay = config_->relays.begin(); |
- relay != config_->relays.end(); ++relay) { |
- if (relay->type == RELAY_GTURN) { |
- CreateGturnPort(*relay); |
- } else if (relay->type == RELAY_TURN) { |
- CreateTurnPort(*relay); |
+ for (RelayServerConfig& relay : config_->relays) { |
+ if (relay.type == RELAY_GTURN) { |
+ CreateGturnPort(relay); |
+ } else if (relay.type == RELAY_TURN) { |
+ CreateTurnPort(relay); |
} else { |
ASSERT(false); |
} |