[Connection] Replace local index with a copy of the candidate.

This is to avoid using an index into a vector that's owned by Port.

Bug: none
Change-Id: Ifc67fcc24bcb04e55c7b963de6d29bb9541c1495
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/263643
Commit-Queue: Tomas Gunnarsson <tommi@webrtc.org>
Reviewed-by: Danil Chapovalov <danilchap@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#37015}
This commit is contained in:
Tommi
2022-05-27 11:25:05 +02:00
committed by WebRTC LUCI CQ
parent 449f5229d6
commit 94ad387f77
4 changed files with 92 additions and 53 deletions

View File

@ -291,7 +291,7 @@ Connection::Connection(rtc::WeakPtr<Port> port,
: network_thread_(port->thread()),
id_(rtc::CreateRandomId()),
port_(std::move(port)),
local_candidate_index_(index),
local_candidate_(port_->Candidates()[index]),
remote_candidate_(remote_candidate),
recv_rate_tracker_(100, 10u),
send_rate_tracker_(100, 10u),
@ -328,8 +328,7 @@ webrtc::TaskQueueBase* Connection::network_thread() const {
const Candidate& Connection::local_candidate() const {
RTC_DCHECK_RUN_ON(network_thread_);
RTC_DCHECK(local_candidate_index_ < port_->Candidates().size());
return port_->Candidates()[local_candidate_index_];
return local_candidate_;
}
const Candidate& Connection::remote_candidate() const {
@ -345,6 +344,9 @@ int Connection::generation() const {
}
uint64_t Connection::priority() const {
if (!port_)
return 0;
uint64_t priority = 0;
// RFC 5245 - 5.7.2. Computing Pair Priority and Ordering Pairs
// Let G be the priority for the candidate provided by the controlling
@ -968,6 +970,15 @@ void Connection::UpdateState(int64_t now) {
}
}
void Connection::UpdateLocalIceParameters(int component,
absl::string_view username_fragment,
absl::string_view password) {
RTC_DCHECK_RUN_ON(network_thread_);
local_candidate_.set_component(component);
local_candidate_.set_username(username_fragment);
local_candidate_.set_password(password);
}
int64_t Connection::last_ping_sent() const {
RTC_DCHECK_RUN_ON(network_thread_);
return last_ping_sent_;
@ -1216,23 +1227,23 @@ std::string Connection::ToString() const {
ss << "Conn[" << ToDebugId();
if (!port_) {
// No content name for pending delete, so temporarily substitute the name
// with a hash (rhyming with trash) and don't include any information about
// the network or candidates, state that belongs to a potentially deleted
// `port_`.
ss << ":#:";
// No content or network names for pending delete. Temporarily substitute
// the names with a hash (rhyming with trash).
ss << ":#:#:";
} else {
const Candidate& local = local_candidate();
const Candidate& remote = remote_candidate();
ss << ":" << port_->content_name() << ":" << port_->Network()->ToString()
<< ":" << local.id() << ":" << local.component() << ":"
<< local.generation() << ":" << local.type() << ":" << local.protocol()
<< ":" << local.address().ToSensitiveString() << "->" << remote.id()
<< ":" << remote.component() << ":" << remote.priority() << ":"
<< remote.type() << ":" << remote.protocol() << ":"
<< remote.address().ToSensitiveString() << "|";
<< ":";
}
const Candidate& local = local_candidate();
const Candidate& remote = remote_candidate();
ss << local.id() << ":" << local.component() << ":" << local.generation()
<< ":" << local.type() << ":" << local.protocol() << ":"
<< local.address().ToSensitiveString() << "->" << remote.id() << ":"
<< remote.component() << ":" << remote.priority() << ":" << remote.type()
<< ":" << remote.protocol() << ":" << remote.address().ToSensitiveString()
<< "|";
ss << CONNECT_STATE_ABBREV[connected_] << RECEIVE_STATE_ABBREV[receiving_]
<< WRITE_STATE_ABBREV[write_state_] << ICESTATE[static_cast<int>(state_)]
<< "|" << SELECTED_STATE_ABBREV[selected_] << "|" << remote_nomination_
@ -1504,12 +1515,12 @@ void Connection::MaybeUpdateLocalCandidate(ConnectionRequest* request,
return;
}
for (size_t i = 0; i < port_->Candidates().size(); ++i) {
if (port_->Candidates()[i].address() == addr->GetAddress()) {
if (local_candidate_index_ != i) {
for (const Candidate& candidate : port_->Candidates()) {
if (candidate.address() == addr->GetAddress()) {
if (local_candidate_ != candidate) {
RTC_LOG(LS_INFO) << ToString()
<< ": Updating local candidate type to srflx.";
local_candidate_index_ = i;
local_candidate_ = candidate;
// SignalStateChange to force a re-sort in P2PTransportChannel as this
// Connection's local candidate has changed.
SignalStateChange(this);
@ -1533,19 +1544,20 @@ void Connection::MaybeUpdateLocalCandidate(ConnectionRequest* request,
std::string id = rtc::CreateRandomString(8);
// Create a peer-reflexive candidate based on the local candidate.
Candidate new_local_candidate(local_candidate());
new_local_candidate.set_id(id);
new_local_candidate.set_type(PRFLX_PORT_TYPE);
new_local_candidate.set_address(addr->GetAddress());
new_local_candidate.set_priority(priority);
new_local_candidate.set_related_address(local_candidate().address());
new_local_candidate.set_foundation(Port::ComputeFoundation(
PRFLX_PORT_TYPE, local_candidate().protocol(),
local_candidate().relay_protocol(), local_candidate().address()));
local_candidate_.set_id(id);
local_candidate_.set_type(PRFLX_PORT_TYPE);
// Set the related address and foundation attributes before changing the
// address.
local_candidate_.set_related_address(local_candidate_.address());
local_candidate_.set_foundation(Port::ComputeFoundation(
PRFLX_PORT_TYPE, local_candidate_.protocol(),
local_candidate_.relay_protocol(), local_candidate_.address()));
local_candidate_.set_priority(priority);
local_candidate_.set_address(addr->GetAddress());
// Change the local candidate of this Connection to the new prflx candidate.
RTC_LOG(LS_INFO) << ToString() << ": Updating local candidate type to prflx.";
local_candidate_index_ = port_->AddPrflxCandidate(new_local_candidate);
port_->AddPrflxCandidate(local_candidate_);
// SignalStateChange to force a re-sort in P2PTransportChannel as this
// Connection's local candidate has changed.
@ -1580,6 +1592,20 @@ bool Connection::TooManyOutstandingPings(
return true;
}
void Connection::SetLocalCandidateNetworkCost(uint16_t cost) {
RTC_DCHECK_RUN_ON(network_thread_);
if (cost == local_candidate_.network_cost())
return;
local_candidate_.set_network_cost(cost);
// Network cost change will affect the connection selection criteria.
// Signal the connection state change to force a re-sort in
// P2PTransportChannel.
SignalStateChange(this);
}
// RTC_RUN_ON(network_thread_).
bool Connection::ShouldSendGoogPing(const StunMessage* message) {
if (remote_support_goog_ping_ == true && cached_stun_binding_ &&

View File

@ -15,6 +15,7 @@
#include <string>
#include <vector>
#include "absl/strings/string_view.h"
#include "absl/types/optional.h"
#include "api/candidate.h"
#include "api/transport/stun.h"
@ -202,6 +203,10 @@ class Connection : public CandidatePairInterface {
// the current time, which is compared against various timeouts.
void UpdateState(int64_t now);
void UpdateLocalIceParameters(int component,
absl::string_view username_fragment,
absl::string_view password);
// Called when this connection should try checking writability again.
int64_t last_ping_sent() const;
void Ping(int64_t now);
@ -284,6 +289,9 @@ class Connection : public CandidatePairInterface {
// Check if we sent `val` pings without receving a response.
bool TooManyOutstandingPings(const absl::optional<int>& val) const;
// Called by Port when the network cost changes.
void SetLocalCandidateNetworkCost(uint16_t cost);
void SetIceFieldTrials(const IceFieldTrials* field_trials);
const rtc::EventBasedExponentialMovingAverage& GetRttEstimate() const {
return rtt_estimate_;
@ -357,7 +365,7 @@ class Connection : public CandidatePairInterface {
webrtc::TaskQueueBase* const network_thread_;
const uint32_t id_;
rtc::WeakPtr<Port> port_;
size_t local_candidate_index_ RTC_GUARDED_BY(network_thread_);
Candidate local_candidate_ RTC_GUARDED_BY(network_thread_);
Candidate remote_candidate_;
ConnectionInfo stats_;

View File

@ -239,16 +239,23 @@ bool Port::SharedSocket() const {
}
void Port::SetIceParameters(int component,
const std::string& username_fragment,
const std::string& password) {
absl::string_view username_fragment,
absl::string_view password) {
RTC_DCHECK_RUN_ON(thread_);
component_ = component;
ice_username_fragment_ = username_fragment;
password_ = password;
ice_username_fragment_ = std::string(username_fragment);
password_ = std::string(password);
for (Candidate& c : candidates_) {
c.set_component(component);
c.set_username(username_fragment);
c.set_password(password);
}
// In case any connections exist make sure we update them too.
for (auto& [unused, connection] : connections_) {
connection->UpdateLocalIceParameters(component, username_fragment,
password);
}
}
const std::vector<Candidate>& Port::Candidates() const {
@ -274,6 +281,7 @@ void Port::AddAddress(const rtc::SocketAddress& address,
uint32_t relay_preference,
const std::string& url,
bool is_final) {
RTC_DCHECK_RUN_ON(thread_);
if (protocol == TCP_PROTOCOL_NAME && type == LOCAL_PORT_TYPE) {
RTC_DCHECK(!tcptype.empty());
}
@ -325,6 +333,7 @@ bool Port::MaybeObfuscateAddress(Candidate* c,
copy.set_address(hostname_address);
copy.set_related_address(rtc::SocketAddress());
if (weak_ptr != nullptr) {
RTC_DCHECK_RUN_ON(weak_ptr->thread_);
weak_ptr->set_mdns_name_registration_status(
MdnsNameRegistrationStatus::kCompleted);
weak_ptr->FinishAddingAddress(copy, is_final);
@ -429,9 +438,9 @@ void Port::OnReadyToSend() {
}
}
size_t Port::AddPrflxCandidate(const Candidate& local) {
void Port::AddPrflxCandidate(const Candidate& local) {
RTC_DCHECK_RUN_ON(thread_);
candidates_.push_back(local);
return (candidates_.size() - 1);
}
bool Port::GetStunMessage(const char* data,
@ -891,6 +900,7 @@ std::string Port::ToString() const {
// TODO(honghaiz): Make the network cost configurable from user setting.
void Port::UpdateNetworkCost() {
RTC_DCHECK_RUN_ON(thread_);
uint16_t new_cost = network_->GetCost(*field_trials_);
if (network_cost_ == new_cost) {
return;
@ -901,16 +911,11 @@ void Port::UpdateNetworkCost() {
<< ". Number of connections created: "
<< connections_.size();
network_cost_ = new_cost;
for (cricket::Candidate& candidate : candidates_) {
for (cricket::Candidate& candidate : candidates_)
candidate.set_network_cost(network_cost_);
}
// Network cost change will affect the connection selection criteria.
// Signal the connection state change on each connection to force a
// re-sort in P2PTransportChannel.
for (const auto& kv : connections_) {
Connection* conn = kv.second;
conn->SignalStateChange(conn);
}
for (auto& [unused, connection] : connections_)
connection->SetLocalCandidateNetworkCost(network_cost_);
}
void Port::EnablePortPackets() {

View File

@ -265,8 +265,8 @@ class Port : public PortInterface,
// PortAllocatorSession, and is now being assigned to an ICE transport.
// Updates the information for candidates as well.
void SetIceParameters(int component,
const std::string& username_fragment,
const std::string& password);
absl::string_view username_fragment,
absl::string_view password);
// Fired when candidates are discovered by the port. When all candidates
// are discovered that belong to port SignalAddressReady is fired.
@ -367,8 +367,7 @@ class Port : public PortInterface,
void OnReadyToSend();
// Called when the Connection discovers a local peer reflexive candidate.
// Returns the index of the new local candidate.
size_t AddPrflxCandidate(const Candidate& local);
void AddPrflxCandidate(const Candidate& local);
int16_t network_cost() const { return network_cost_; }
@ -406,7 +405,8 @@ class Port : public PortInterface,
const std::string& url,
bool is_final);
void FinishAddingAddress(const Candidate& c, bool is_final);
void FinishAddingAddress(const Candidate& c, bool is_final)
RTC_RUN_ON(thread_);
virtual void PostAddAddress(bool is_final);
@ -481,7 +481,7 @@ class Port : public PortInterface,
// username_fragment().
std::string ice_username_fragment_;
std::string password_;
std::vector<Candidate> candidates_;
std::vector<Candidate> candidates_ RTC_GUARDED_BY(thread_);
AddressMap connections_;
int timeout_delay_;
bool enable_port_packets_;
@ -508,7 +508,7 @@ class Port : public PortInterface,
bool MaybeObfuscateAddress(Candidate* c,
const std::string& type,
bool is_final);
bool is_final) RTC_RUN_ON(thread_);
friend class Connection;
webrtc::CallbackList<PortInterface*> port_destroyed_callback_list_;