| 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);
|
| }
|
|
|