[Connection] Construct ping/connection requests in one step.

This moves the construction of StunMessage instances for
ConnectionRequest, outside of the Prepare() method.

Following this, removing Construct()+Prepare() is relatively
straight forward.

Bug: none
Change-Id: Ibcf0510cef30a6e648005b43602c7ae1fb06729e
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/264558
Reviewed-by: Niels Moller <nisse@webrtc.org>
Reviewed-by: Jonas Oreland <jonaso@webrtc.org>
Commit-Queue: Tomas Gunnarsson <tommi@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#37122}
This commit is contained in:
Tommi 2022-06-03 14:28:59 +02:00 committed by WebRTC LUCI CQ
parent 0ba10283fb
commit e83500e17b
13 changed files with 195 additions and 188 deletions

View File

@ -362,22 +362,19 @@ bool StunMessage::ValidateMessageIntegrityOfType(int mi_attr_type,
mi_attr_size) == 0;
}
bool StunMessage::AddMessageIntegrity(const std::string& password) {
bool StunMessage::AddMessageIntegrity(absl::string_view password) {
return AddMessageIntegrityOfType(STUN_ATTR_MESSAGE_INTEGRITY,
kStunMessageIntegritySize, password.c_str(),
password.size());
kStunMessageIntegritySize, password);
}
bool StunMessage::AddMessageIntegrity32(absl::string_view password) {
return AddMessageIntegrityOfType(STUN_ATTR_GOOG_MESSAGE_INTEGRITY_32,
kStunMessageIntegrity32Size, password.data(),
password.length());
kStunMessageIntegrity32Size, password);
}
bool StunMessage::AddMessageIntegrityOfType(int attr_type,
size_t attr_size,
const char* key,
size_t keylen) {
absl::string_view key) {
// Add the attribute with a dummy value. Since this is a known attribute, it
// can't fail.
RTC_DCHECK(attr_size <= kStunMessageIntegritySize);
@ -394,8 +391,9 @@ bool StunMessage::AddMessageIntegrityOfType(int attr_type,
int msg_len_for_hmac = static_cast<int>(
buf.Length() - kStunAttributeHeaderSize - msg_integrity_attr->length());
char hmac[kStunMessageIntegritySize];
size_t ret = rtc::ComputeHmac(rtc::DIGEST_SHA_1, key, keylen, buf.Data(),
msg_len_for_hmac, hmac, sizeof(hmac));
size_t ret =
rtc::ComputeHmac(rtc::DIGEST_SHA_1, key.data(), key.size(), buf.Data(),
msg_len_for_hmac, hmac, sizeof(hmac));
RTC_DCHECK(ret == sizeof(hmac));
if (ret != sizeof(hmac)) {
RTC_LOG(LS_ERROR) << "HMAC computation failed. Message-Integrity "
@ -405,7 +403,7 @@ bool StunMessage::AddMessageIntegrityOfType(int attr_type,
// Insert correct HMAC into the attribute.
msg_integrity_attr->CopyBytes(hmac, attr_size);
password_.assign(key, keylen);
password_ = std::string(key);
integrity_ = IntegrityStatus::kIntegrityOk;
return true;
}
@ -1006,9 +1004,9 @@ StunByteStringAttribute::StunByteStringAttribute(uint16_t type)
: StunAttribute(type, 0), bytes_(NULL) {}
StunByteStringAttribute::StunByteStringAttribute(uint16_t type,
const std::string& str)
absl::string_view str)
: StunAttribute(type, 0), bytes_(NULL) {
CopyBytes(str.c_str(), str.size());
CopyBytes(str);
}
StunByteStringAttribute::StunByteStringAttribute(uint16_t type,
@ -1029,8 +1027,10 @@ StunAttributeValueType StunByteStringAttribute::value_type() const {
return STUN_VALUE_BYTE_STRING;
}
void StunByteStringAttribute::CopyBytes(const char* bytes) {
CopyBytes(bytes, strlen(bytes));
void StunByteStringAttribute::CopyBytes(absl::string_view bytes) {
char* new_bytes = new char[bytes.size()];
memcpy(new_bytes, bytes.data(), bytes.size());
SetBytes(new_bytes, bytes.size());
}
void StunByteStringAttribute::CopyBytes(const void* bytes, size_t length) {

View File

@ -233,7 +233,7 @@ class StunMessage {
}
// Adds a MESSAGE-INTEGRITY attribute that is valid for the current message.
bool AddMessageIntegrity(const std::string& password);
bool AddMessageIntegrity(absl::string_view password);
// Adds a STUN_ATTR_GOOG_MESSAGE_INTEGRITY_32 attribute that is valid for the
// current message.
@ -316,8 +316,7 @@ class StunMessage {
static bool IsValidTransactionId(absl::string_view transaction_id);
bool AddMessageIntegrityOfType(int mi_attr_type,
size_t mi_attr_size,
const char* key,
size_t keylen);
absl::string_view key);
static bool ValidateMessageIntegrityOfType(int mi_attr_type,
size_t mi_attr_size,
const char* data,
@ -507,7 +506,7 @@ class StunUInt64Attribute : public StunAttribute {
class StunByteStringAttribute : public StunAttribute {
public:
explicit StunByteStringAttribute(uint16_t type);
StunByteStringAttribute(uint16_t type, const std::string& str);
StunByteStringAttribute(uint16_t type, absl::string_view str);
StunByteStringAttribute(uint16_t type, const void* bytes, size_t length);
StunByteStringAttribute(uint16_t type, uint16_t length);
~StunByteStringAttribute() override;
@ -515,10 +514,16 @@ class StunByteStringAttribute : public StunAttribute {
StunAttributeValueType value_type() const override;
const char* bytes() const { return bytes_; }
std::string GetString() const { return std::string(bytes_, length()); }
absl::string_view string_view() const {
return absl::string_view(bytes_, length());
}
[[deprecated]] std::string GetString() const {
return std::string(bytes_, length());
}
void CopyBytes(const char* bytes); // uses strlen
void CopyBytes(const void* bytes, size_t length);
void CopyBytes(absl::string_view bytes);
uint8_t GetByte(size_t index) const;
void SetByte(size_t index, uint8_t value);

View File

@ -650,12 +650,12 @@ TEST_F(StunTest, ReadRfc5769RequestMessage) {
const StunByteStringAttribute* software =
msg.GetByteString(STUN_ATTR_SOFTWARE);
ASSERT_TRUE(software != NULL);
EXPECT_EQ(kRfc5769SampleMsgClientSoftware, software->GetString());
EXPECT_EQ(kRfc5769SampleMsgClientSoftware, software->string_view());
const StunByteStringAttribute* username =
msg.GetByteString(STUN_ATTR_USERNAME);
ASSERT_TRUE(username != NULL);
EXPECT_EQ(kRfc5769SampleMsgUsername, username->GetString());
EXPECT_EQ(kRfc5769SampleMsgUsername, username->string_view());
// Actual M-I value checked in a later test.
ASSERT_TRUE(msg.GetByteString(STUN_ATTR_MESSAGE_INTEGRITY) != NULL);
@ -677,7 +677,7 @@ TEST_F(StunTest, ReadRfc5769ResponseMessage) {
const StunByteStringAttribute* software =
msg.GetByteString(STUN_ATTR_SOFTWARE);
ASSERT_TRUE(software != NULL);
EXPECT_EQ(kRfc5769SampleMsgServerSoftware, software->GetString());
EXPECT_EQ(kRfc5769SampleMsgServerSoftware, software->string_view());
const StunAddressAttribute* mapped_address =
msg.GetAddress(STUN_ATTR_XOR_MAPPED_ADDRESS);
@ -700,7 +700,7 @@ TEST_F(StunTest, ReadRfc5769ResponseMessageIPv6) {
const StunByteStringAttribute* software =
msg.GetByteString(STUN_ATTR_SOFTWARE);
ASSERT_TRUE(software != NULL);
EXPECT_EQ(kRfc5769SampleMsgServerSoftware, software->GetString());
EXPECT_EQ(kRfc5769SampleMsgServerSoftware, software->string_view());
const StunAddressAttribute* mapped_address =
msg.GetAddress(STUN_ATTR_XOR_MAPPED_ADDRESS);
@ -723,15 +723,15 @@ TEST_F(StunTest, ReadRfc5769RequestMessageLongTermAuth) {
const StunByteStringAttribute* username =
msg.GetByteString(STUN_ATTR_USERNAME);
ASSERT_TRUE(username != NULL);
EXPECT_EQ(kRfc5769SampleMsgWithAuthUsername, username->GetString());
EXPECT_EQ(kRfc5769SampleMsgWithAuthUsername, username->string_view());
const StunByteStringAttribute* nonce = msg.GetByteString(STUN_ATTR_NONCE);
ASSERT_TRUE(nonce != NULL);
EXPECT_EQ(kRfc5769SampleMsgWithAuthNonce, nonce->GetString());
EXPECT_EQ(kRfc5769SampleMsgWithAuthNonce, nonce->string_view());
const StunByteStringAttribute* realm = msg.GetByteString(STUN_ATTR_REALM);
ASSERT_TRUE(realm != NULL);
EXPECT_EQ(kRfc5769SampleMsgWithAuthRealm, realm->GetString());
EXPECT_EQ(kRfc5769SampleMsgWithAuthRealm, realm->string_view());
// No fingerprint, actual M-I checked in later tests.
ASSERT_TRUE(msg.GetByteString(STUN_ATTR_MESSAGE_INTEGRITY) != NULL);
@ -1013,7 +1013,7 @@ TEST_F(StunTest, ReadByteStringAttribute) {
const StunByteStringAttribute* username =
msg.GetByteString(STUN_ATTR_USERNAME);
ASSERT_TRUE(username != NULL);
EXPECT_EQ(kTestUserName1, username->GetString());
EXPECT_EQ(kTestUserName1, username->string_view());
}
TEST_F(StunTest, ReadPaddedByteStringAttribute) {
@ -1026,7 +1026,7 @@ TEST_F(StunTest, ReadPaddedByteStringAttribute) {
const StunByteStringAttribute* username =
msg.GetByteString(STUN_ATTR_USERNAME);
ASSERT_TRUE(username != NULL);
EXPECT_EQ(kTestUserName2, username->GetString());
EXPECT_EQ(kTestUserName2, username->string_view());
}
TEST_F(StunTest, ReadErrorCodeAttribute) {
@ -1073,7 +1073,7 @@ TEST_F(StunTest, ReadMessageWithAnUnknownAttribute) {
const StunByteStringAttribute* username =
msg.GetByteString(STUN_ATTR_USERNAME);
ASSERT_TRUE(username != NULL);
EXPECT_EQ(kTestUserName2, username->GetString());
EXPECT_EQ(kTestUserName2, username->string_view());
}
TEST_F(StunTest, WriteMessageWithAnErrorCodeAttribute) {
@ -1498,7 +1498,7 @@ TEST_F(StunTest, ReadRelayMessage) {
const StunByteStringAttribute* bytes = msg.GetByteString(STUN_ATTR_USERNAME);
ASSERT_TRUE(bytes != NULL);
EXPECT_EQ(12U, bytes->length());
EXPECT_EQ("abcdefghijkl", bytes->GetString());
EXPECT_EQ("abcdefghijkl", bytes->string_view());
auto bytes2 = StunAttribute::CreateByteString(STUN_ATTR_USERNAME);
bytes2->CopyBytes("abcdefghijkl");
@ -1556,7 +1556,7 @@ TEST_F(StunTest, ReadRelayMessage) {
bytes = msg.GetByteString(STUN_ATTR_DATA);
ASSERT_TRUE(bytes != NULL);
EXPECT_EQ(7U, bytes->length());
EXPECT_EQ("abcdefg", bytes->GetString());
EXPECT_EQ("abcdefg", bytes->string_view());
bytes2 = StunAttribute::CreateByteString(STUN_ATTR_DATA);
bytes2->CopyBytes("abcdefg");

View File

@ -34,12 +34,13 @@
#include "rtc_base/strings/string_builder.h"
#include "rtc_base/third_party/base64/base64.h"
namespace cricket {
namespace {
// Determines whether we have seen at least the given maximum number of
// pings fail to have a response.
inline bool TooManyFailures(
const std::vector<cricket::Connection::SentPing>& pings_since_last_response,
const std::vector<Connection::SentPing>& pings_since_last_response,
uint32_t maximum_failures,
int rtt_estimate,
int64_t now) {
@ -56,7 +57,7 @@ inline bool TooManyFailures(
// Determines whether we have gone too long without seeing any response.
inline bool TooLongWithoutResponse(
const std::vector<cricket::Connection::SentPing>& pings_since_last_response,
const std::vector<Connection::SentPing>& pings_since_last_response,
int64_t maximum_time,
int64_t now) {
if (pings_since_last_response.size() == 0)
@ -69,13 +70,13 @@ inline bool TooLongWithoutResponse(
// Helper methods for converting string values of log description fields to
// enum.
webrtc::IceCandidateType GetCandidateTypeByString(const std::string& type) {
if (type == cricket::LOCAL_PORT_TYPE) {
if (type == LOCAL_PORT_TYPE) {
return webrtc::IceCandidateType::kLocal;
} else if (type == cricket::STUN_PORT_TYPE) {
} else if (type == STUN_PORT_TYPE) {
return webrtc::IceCandidateType::kStun;
} else if (type == cricket::PRFLX_PORT_TYPE) {
} else if (type == PRFLX_PORT_TYPE) {
return webrtc::IceCandidateType::kPrflx;
} else if (type == cricket::RELAY_PORT_TYPE) {
} else if (type == RELAY_PORT_TYPE) {
return webrtc::IceCandidateType::kRelay;
}
return webrtc::IceCandidateType::kUnknown;
@ -83,13 +84,13 @@ webrtc::IceCandidateType GetCandidateTypeByString(const std::string& type) {
webrtc::IceCandidatePairProtocol GetProtocolByString(
const std::string& protocol) {
if (protocol == cricket::UDP_PROTOCOL_NAME) {
if (protocol == UDP_PROTOCOL_NAME) {
return webrtc::IceCandidatePairProtocol::kUdp;
} else if (protocol == cricket::TCP_PROTOCOL_NAME) {
} else if (protocol == TCP_PROTOCOL_NAME) {
return webrtc::IceCandidatePairProtocol::kTcp;
} else if (protocol == cricket::SSLTCP_PROTOCOL_NAME) {
} else if (protocol == SSLTCP_PROTOCOL_NAME) {
return webrtc::IceCandidatePairProtocol::kSsltcp;
} else if (protocol == cricket::TLS_PROTOCOL_NAME) {
} else if (protocol == TLS_PROTOCOL_NAME) {
return webrtc::IceCandidatePairProtocol::kTls;
}
return webrtc::IceCandidatePairProtocol::kUnknown;
@ -148,24 +149,22 @@ const int RTT_RATIO = 3; // 3 : 1
constexpr int64_t kMinExtraPingDelayMs = 100;
// Default field trials.
const cricket::IceFieldTrials kDefaultFieldTrials;
const IceFieldTrials kDefaultFieldTrials;
constexpr int kSupportGoogPingVersionRequestIndex =
static_cast<int>(cricket::IceGoogMiscInfoBindingRequestAttributeIndex::
SUPPORT_GOOG_PING_VERSION);
constexpr int kSupportGoogPingVersionRequestIndex = static_cast<int>(
IceGoogMiscInfoBindingRequestAttributeIndex::SUPPORT_GOOG_PING_VERSION);
constexpr int kSupportGoogPingVersionResponseIndex =
static_cast<int>(cricket::IceGoogMiscInfoBindingResponseAttributeIndex::
SUPPORT_GOOG_PING_VERSION);
constexpr int kSupportGoogPingVersionResponseIndex = static_cast<int>(
IceGoogMiscInfoBindingResponseAttributeIndex::SUPPORT_GOOG_PING_VERSION);
} // namespace
namespace cricket {
// A ConnectionRequest is a STUN binding used to determine writability.
class Connection::ConnectionRequest : public StunRequest {
public:
ConnectionRequest(StunRequestManager& manager, Connection* connection);
void Prepare(StunMessage* message) override;
ConnectionRequest(StunRequestManager& manager,
Connection* connection,
std::unique_ptr<IceMessage> message);
void OnResponse(StunMessage* response) override;
void OnErrorResponse(StunMessage* response) override;
void OnTimeout() override;
@ -176,101 +175,11 @@ class Connection::ConnectionRequest : public StunRequest {
Connection* const connection_;
};
// A ConnectionRequest is a STUN binding used to determine writability.
Connection::ConnectionRequest::ConnectionRequest(StunRequestManager& manager,
Connection* connection)
: StunRequest(manager, std::make_unique<IceMessage>(STUN_BINDING_REQUEST)),
connection_(connection) {}
void Connection::ConnectionRequest::Prepare(StunMessage* message) {
RTC_DCHECK_RUN_ON(connection_->network_thread_);
RTC_DCHECK_EQ(message->type(), STUN_BINDING_REQUEST);
std::string username;
connection_->port()->CreateStunUsername(
connection_->remote_candidate().username(), &username);
// Note that the order of attributes does not impact the parsing on the
// receiver side. The attribute is retrieved then by iterating and matching
// over all parsed attributes. See StunMessage::GetAttribute.
message->AddAttribute(
std::make_unique<StunByteStringAttribute>(STUN_ATTR_USERNAME, username));
// connection_ already holds this ping, so subtract one from count.
if (connection_->port()->send_retransmit_count_attribute()) {
message->AddAttribute(std::make_unique<StunUInt32Attribute>(
STUN_ATTR_RETRANSMIT_COUNT,
static_cast<uint32_t>(connection_->pings_since_last_response_.size() -
1)));
}
uint32_t network_info = connection_->port()->Network()->id();
network_info = (network_info << 16) | connection_->port()->network_cost();
message->AddAttribute(std::make_unique<StunUInt32Attribute>(
STUN_ATTR_GOOG_NETWORK_INFO, network_info));
if (connection_->field_trials_->piggyback_ice_check_acknowledgement &&
connection_->last_ping_id_received()) {
message->AddAttribute(std::make_unique<StunByteStringAttribute>(
STUN_ATTR_GOOG_LAST_ICE_CHECK_RECEIVED,
connection_->last_ping_id_received().value()));
}
// Adding ICE_CONTROLLED or ICE_CONTROLLING attribute based on the role.
if (connection_->port()->GetIceRole() == ICEROLE_CONTROLLING) {
message->AddAttribute(std::make_unique<StunUInt64Attribute>(
STUN_ATTR_ICE_CONTROLLING, connection_->port()->IceTiebreaker()));
// We should have either USE_CANDIDATE attribute or ICE_NOMINATION
// attribute but not both. That was enforced in p2ptransportchannel.
if (connection_->use_candidate_attr()) {
message->AddAttribute(
std::make_unique<StunByteStringAttribute>(STUN_ATTR_USE_CANDIDATE));
}
if (connection_->nomination_ &&
connection_->nomination_ != connection_->acked_nomination()) {
message->AddAttribute(std::make_unique<StunUInt32Attribute>(
STUN_ATTR_NOMINATION, connection_->nomination_));
}
} else if (connection_->port()->GetIceRole() == ICEROLE_CONTROLLED) {
message->AddAttribute(std::make_unique<StunUInt64Attribute>(
STUN_ATTR_ICE_CONTROLLED, connection_->port()->IceTiebreaker()));
} else {
RTC_DCHECK_NOTREACHED();
}
// Adding PRIORITY Attribute.
// Changing the type preference to Peer Reflexive and local preference
// and component id information is unchanged from the original priority.
// priority = (2^24)*(type preference) +
// (2^8)*(local preference) +
// (2^0)*(256 - component ID)
uint32_t type_preference =
(connection_->local_candidate().protocol() == TCP_PROTOCOL_NAME)
? ICE_TYPE_PREFERENCE_PRFLX_TCP
: ICE_TYPE_PREFERENCE_PRFLX;
uint32_t prflx_priority =
type_preference << 24 |
(connection_->local_candidate().priority() & 0x00FFFFFF);
message->AddAttribute(std::make_unique<StunUInt32Attribute>(
STUN_ATTR_PRIORITY, prflx_priority));
if (connection_->field_trials_->enable_goog_ping &&
!connection_->remote_support_goog_ping_.has_value()) {
// Check if remote supports GOOG PING by announcing which version we
// support. This is sent on all STUN_BINDING_REQUEST until we get a
// STUN_BINDING_RESPONSE.
auto list =
StunAttribute::CreateUInt16ListAttribute(STUN_ATTR_GOOG_MISC_INFO);
list->AddTypeAtIndex(kSupportGoogPingVersionRequestIndex, kGoogPingVersion);
message->AddAttribute(std::move(list));
}
if (connection_->ShouldSendGoogPing(message)) {
message->SetType(GOOG_PING_REQUEST);
message->ClearAttributes();
message->AddMessageIntegrity32(connection_->remote_candidate().password());
} else {
message->AddMessageIntegrity(connection_->remote_candidate().password());
message->AddFingerprint();
}
}
Connection::ConnectionRequest::ConnectionRequest(
StunRequestManager& manager,
Connection* connection,
std::unique_ptr<IceMessage> message)
: StunRequest(manager, std::move(message)), connection_(connection) {}
void Connection::ConnectionRequest::OnResponse(StunMessage* response) {
RTC_DCHECK_RUN_ON(connection_->network_thread_);
@ -997,7 +906,7 @@ int64_t Connection::last_ping_sent() const {
void Connection::Ping(int64_t now) {
RTC_DCHECK_RUN_ON(network_thread_);
last_ping_sent_ = now;
ConnectionRequest* req = new ConnectionRequest(requests_, this);
// If not using renomination, we use "1" to mean "nominated" and "0" to mean
// "not nominated". If using renomination, values greater than 1 are used for
// re-nominated pairs.
@ -1005,15 +914,87 @@ void Connection::Ping(int64_t now) {
if (nomination_ > 0) {
nomination = nomination_;
}
auto req =
std::make_unique<ConnectionRequest>(requests_, this, BuildPingRequest());
if (ShouldSendGoogPing(req->msg())) {
auto message = std::make_unique<IceMessage>(GOOG_PING_REQUEST, req->id());
message->AddMessageIntegrity32(remote_candidate_.password());
req.reset(new ConnectionRequest(requests_, this, std::move(message)));
}
pings_since_last_response_.push_back(SentPing(req->id(), now, nomination));
RTC_LOG(LS_VERBOSE) << ToString() << ": Sending STUN ping, id="
<< rtc::hex_encode(req->id())
<< ", nomination=" << nomination_;
requests_.Send(req);
requests_.Send(req.release());
state_ = IceCandidatePairState::IN_PROGRESS;
num_pings_sent_++;
}
std::unique_ptr<IceMessage> Connection::BuildPingRequest() {
auto message = std::make_unique<IceMessage>(STUN_BINDING_REQUEST);
// Note that the order of attributes does not impact the parsing on the
// receiver side. The attribute is retrieved then by iterating and matching
// over all parsed attributes. See StunMessage::GetAttribute.
message->AddAttribute(std::make_unique<StunByteStringAttribute>(
STUN_ATTR_USERNAME,
port()->CreateStunUsername(remote_candidate_.username())));
message->AddAttribute(std::make_unique<StunUInt32Attribute>(
STUN_ATTR_GOOG_NETWORK_INFO,
(port_->Network()->id() << 16) | port_->network_cost()));
if (field_trials_->piggyback_ice_check_acknowledgement &&
last_ping_id_received_) {
message->AddAttribute(std::make_unique<StunByteStringAttribute>(
STUN_ATTR_GOOG_LAST_ICE_CHECK_RECEIVED, *last_ping_id_received_));
}
// Adding ICE_CONTROLLED or ICE_CONTROLLING attribute based on the role.
IceRole ice_role = port_->GetIceRole();
RTC_DCHECK(ice_role == ICEROLE_CONTROLLING || ice_role == ICEROLE_CONTROLLED);
message->AddAttribute(std::make_unique<StunUInt64Attribute>(
ice_role == ICEROLE_CONTROLLING ? STUN_ATTR_ICE_CONTROLLING
: STUN_ATTR_ICE_CONTROLLED,
port_->IceTiebreaker()));
if (ice_role == ICEROLE_CONTROLLING) {
// We should have either USE_CANDIDATE attribute or ICE_NOMINATION
// attribute but not both. That was enforced in p2ptransportchannel.
if (use_candidate_attr()) {
message->AddAttribute(
std::make_unique<StunByteStringAttribute>(STUN_ATTR_USE_CANDIDATE));
}
if (nomination_ && nomination_ != acked_nomination()) {
message->AddAttribute(std::make_unique<StunUInt32Attribute>(
STUN_ATTR_NOMINATION, nomination_));
}
}
message->AddAttribute(std::make_unique<StunUInt32Attribute>(
STUN_ATTR_PRIORITY, prflx_priority()));
if (port()->send_retransmit_count_attribute()) {
message->AddAttribute(std::make_unique<StunUInt32Attribute>(
STUN_ATTR_RETRANSMIT_COUNT, pings_since_last_response_.size()));
}
if (field_trials_->enable_goog_ping &&
!remote_support_goog_ping_.has_value()) {
// Check if remote supports GOOG PING by announcing which version we
// support. This is sent on all STUN_BINDING_REQUEST until we get a
// STUN_BINDING_RESPONSE.
auto list =
StunAttribute::CreateUInt16ListAttribute(STUN_ATTR_GOOG_MISC_INFO);
list->AddTypeAtIndex(kSupportGoogPingVersionRequestIndex, kGoogPingVersion);
message->AddAttribute(std::move(list));
}
message->AddMessageIntegrity(remote_candidate_.password());
message->AddFingerprint();
return message;
}
int64_t Connection::last_ping_response_received() const {
RTC_DCHECK_RUN_ON(network_thread_);
return last_ping_response_received_;
@ -1051,7 +1032,8 @@ void Connection::HandlePiggybackCheckAcknowledgementIfAny(StunMessage* msg) {
const StunByteStringAttribute* last_ice_check_received_attr =
msg->GetByteString(STUN_ATTR_GOOG_LAST_ICE_CHECK_RECEIVED);
if (last_ice_check_received_attr) {
const std::string request_id = last_ice_check_received_attr->GetString();
const absl::string_view request_id =
last_ice_check_received_attr->string_view();
auto iter = absl::c_find_if(
pings_since_last_response_,
[&request_id](const SentPing& ping) { return ping.id == request_id; });
@ -1078,7 +1060,7 @@ int64_t Connection::last_data_received() const {
void Connection::ReceivedPingResponse(
int rtt,
const std::string& request_id,
absl::string_view request_id,
const absl::optional<uint32_t>& nomination) {
RTC_DCHECK_RUN_ON(network_thread_);
RTC_DCHECK_GE(rtt, 0);
@ -1487,6 +1469,21 @@ int64_t Connection::receiving_unchanged_since() const {
return receiving_unchanged_since_;
}
uint32_t Connection::prflx_priority() const {
RTC_DCHECK_RUN_ON(network_thread_);
// PRIORITY Attribute.
// Changing the type preference to Peer Reflexive and local preference
// and component id information is unchanged from the original priority.
// priority = (2^24)*(type preference) +
// (2^8)*(local preference) +
// (2^0)*(256 - component ID)
IcePriorityValue type_preference =
(local_candidate_.protocol() == TCP_PROTOCOL_NAME)
? ICE_TYPE_PREFERENCE_PRFLX_TCP
: ICE_TYPE_PREFERENCE_PRFLX;
return type_preference << 24 | (local_candidate_.priority() & 0x00FFFFFF);
}
ConnectionInfo Connection::stats() {
RTC_DCHECK_RUN_ON(network_thread_);
stats_.recv_bytes_second = round(recv_rate_tracker_.ComputeRate());

View File

@ -202,8 +202,9 @@ class Connection : public CandidatePairInterface {
void Ping(int64_t now);
void ReceivedPingResponse(
int rtt,
const std::string& request_id,
absl::string_view request_id,
const absl::optional<uint32_t>& nomination = absl::nullopt);
std::unique_ptr<IceMessage> BuildPingRequest() RTC_RUN_ON(network_thread_);
int64_t last_ping_response_received() const;
const absl::optional<std::string>& last_ping_id_received() const;
@ -274,6 +275,10 @@ class Connection : public CandidatePairInterface {
// Returns the last time when the connection changed its receiving state.
int64_t receiving_unchanged_since() const;
// Constructs the prflx priority as described in
// https://datatracker.ietf.org/doc/html/rfc5245#section-4.1.2.1
uint32_t prflx_priority() const;
bool stable(int64_t now) const;
// Check if we sent `val` pings without receving a response.

View File

@ -653,14 +653,14 @@ bool Port::ParseStunUsername(const StunMessage* stun_msg,
return false;
// RFRAG:LFRAG
const std::string username = username_attr->GetString();
const absl::string_view username = username_attr->string_view();
size_t colon_pos = username.find(':');
if (colon_pos == std::string::npos) {
if (colon_pos == absl::string_view::npos) {
return false;
}
*local_ufrag = username.substr(0, colon_pos);
*remote_ufrag = username.substr(colon_pos + 1, username.size());
*local_ufrag = std::string(username.substr(0, colon_pos));
*remote_ufrag = std::string(username.substr(colon_pos + 1, username.size()));
return true;
}
@ -725,12 +725,8 @@ bool Port::MaybeIceRoleConflict(const rtc::SocketAddress& addr,
return ret;
}
void Port::CreateStunUsername(const std::string& remote_username,
std::string* stun_username_attr_str) const {
stun_username_attr_str->clear();
*stun_username_attr_str = remote_username;
stun_username_attr_str->append(":");
stun_username_attr_str->append(username_fragment());
std::string Port::CreateStunUsername(const std::string& remote_username) const {
return remote_username + ":" + username_fragment();
}
bool Port::HandleIncomingPacket(rtc::AsyncPacketSocket* socket,

View File

@ -62,7 +62,9 @@ extern const char TCPTYPE_ACTIVE_STR[];
extern const char TCPTYPE_PASSIVE_STR[];
extern const char TCPTYPE_SIMOPEN_STR[];
enum IcePriorityValue {
// The type preference MUST be an integer from 0 to 126 inclusive.
// https://datatracker.ietf.org/doc/html/rfc5245#section-4.1.2.1
enum IcePriorityValue : uint8_t {
ICE_TYPE_PREFERENCE_RELAY_TLS = 0,
ICE_TYPE_PREFERENCE_RELAY_TCP = 1,
ICE_TYPE_PREFERENCE_RELAY_UDP = 2,
@ -346,8 +348,7 @@ class Port : public PortInterface,
bool ParseStunUsername(const StunMessage* stun_msg,
std::string* local_username,
std::string* remote_username) const;
void CreateStunUsername(const std::string& remote_username,
std::string* stun_username_attr_str) const;
std::string CreateStunUsername(const std::string& remote_username) const;
bool MaybeIceRoleConflict(const rtc::SocketAddress& addr,
IceMessage* stun_msg,

View File

@ -1472,7 +1472,7 @@ TEST_F(PortTest, TestLoopbackCall) {
const StunByteStringAttribute* username_attr =
msg->GetByteString(STUN_ATTR_USERNAME);
modified_req->AddAttribute(std::make_unique<StunByteStringAttribute>(
STUN_ATTR_USERNAME, username_attr->GetString()));
STUN_ATTR_USERNAME, username_attr->string_view()));
// To make sure we receive error response, adding tiebreaker less than
// what's present in request.
modified_req->AddAttribute(std::make_unique<StunUInt64Attribute>(
@ -1792,7 +1792,7 @@ TEST_F(PortTest, TestSendStunMessage) {
const StunUInt32Attribute* priority_attr = msg->GetUInt32(STUN_ATTR_PRIORITY);
ASSERT_TRUE(priority_attr != NULL);
EXPECT_EQ(kDefaultPrflxPriority, priority_attr->value());
EXPECT_EQ("rfrag:lfrag", username_attr->GetString());
EXPECT_EQ("rfrag:lfrag", username_attr->string_view());
EXPECT_TRUE(msg->GetByteString(STUN_ATTR_MESSAGE_INTEGRITY) != NULL);
EXPECT_EQ(StunMessage::IntegrityStatus::kIntegrityOk,
msg->ValidateMessageIntegrity("rpass"));

View File

@ -1185,7 +1185,7 @@ bool TurnPort::UpdateNonce(StunMessage* response) {
"stale nonce error response.";
return false;
}
set_realm(realm_attr->GetString());
set_realm(realm_attr->string_view());
const StunByteStringAttribute* nonce_attr =
response->GetByteString(STUN_ATTR_NONCE);
@ -1194,7 +1194,7 @@ bool TurnPort::UpdateNonce(StunMessage* response) {
"stale nonce error response.";
return false;
}
set_nonce(nonce_attr->GetString());
set_nonce(nonce_attr->string_view());
return true;
}
@ -1499,7 +1499,7 @@ void TurnAllocateRequest::OnAuthChallenge(StunMessage* response, int code) {
"allocate unauthorized response.";
return;
}
port_->set_realm(realm_attr->GetString());
port_->set_realm(realm_attr->string_view());
const StunByteStringAttribute* nonce_attr =
response->GetByteString(STUN_ATTR_NONCE);
@ -1509,7 +1509,7 @@ void TurnAllocateRequest::OnAuthChallenge(StunMessage* response, int code) {
"allocate unauthorized response.";
return;
}
port_->set_nonce(nonce_attr->GetString());
port_->set_nonce(nonce_attr->string_view());
// Send another allocate request, with the received realm and nonce values.
port_->SendRequest(new TurnAllocateRequest(port_), 0);
@ -1544,7 +1544,7 @@ void TurnAllocateRequest::OnTryAlternate(StunMessage* response, int code) {
RTC_LOG(LS_INFO) << port_->ToString()
<< ": Applying STUN_ATTR_REALM attribute in "
"try alternate error response.";
port_->set_realm(realm_attr->GetString());
port_->set_realm(realm_attr->string_view());
}
const StunByteStringAttribute* nonce_attr =
@ -1553,7 +1553,7 @@ void TurnAllocateRequest::OnTryAlternate(StunMessage* response, int code) {
RTC_LOG(LS_INFO) << port_->ToString()
<< ": Applying STUN_ATTR_NONCE attribute in "
"try alternate error response.";
port_->set_nonce(nonce_attr->GetString());
port_->set_nonce(nonce_attr->string_view());
}
// For TCP, we can't close the original Tcp socket during handling a 300 as

View File

@ -268,10 +268,10 @@ class TurnPort : public Port {
bool CreateTurnClientSocket();
void set_nonce(const std::string& nonce) { nonce_ = nonce; }
void set_realm(const std::string& realm) {
void set_nonce(absl::string_view nonce) { nonce_ = std::string(nonce); }
void set_realm(absl::string_view realm) {
if (realm != realm_) {
realm_ = realm;
realm_ = std::string(realm);
UpdateHash();
}
}

View File

@ -876,7 +876,7 @@ class TurnLoggingIdValidator : public StunMessageObserver {
msg->GetByteString(cricket::STUN_ATTR_TURN_LOGGING_ID);
if (expect_val_) {
ASSERT_NE(nullptr, attr);
ASSERT_EQ(expect_val_, attr->GetString());
ASSERT_EQ(expect_val_, attr->string_view());
} else {
EXPECT_EQ(nullptr, attr);
}

View File

@ -286,7 +286,7 @@ void TurnServer::HandleStunMessage(TurnServerConnection* conn,
// This is a non-allocate request, or a retransmit of an allocate.
// Check that the username matches the previous username used.
if (IsStunRequestType(msg.type()) &&
msg.GetByteString(STUN_ATTR_USERNAME)->GetString() !=
msg.GetByteString(STUN_ATTR_USERNAME)->string_view() !=
allocation->username()) {
SendErrorResponse(conn, &msg, STUN_ERROR_WRONG_CREDENTIALS,
STUN_ERROR_REASON_WRONG_CREDENTIALS);
@ -307,8 +307,9 @@ bool TurnServer::GetKey(const StunMessage* msg, std::string* key) {
return false;
}
std::string username = username_attr->GetString();
return (auth_hook_ != NULL && auth_hook_->GetKey(username, realm_, key));
return (auth_hook_ != NULL &&
auth_hook_->GetKey(std::string(username_attr->string_view()), realm_,
key));
}
bool TurnServer::CheckAuthorization(TurnServerConnection* conn,
@ -342,7 +343,7 @@ bool TurnServer::CheckAuthorization(TurnServerConnection* conn,
}
// Fail if bad nonce.
if (!ValidateNonce(nonce_attr->GetString())) {
if (!ValidateNonce(nonce_attr->string_view())) {
SendErrorResponseWithRealmAndNonce(conn, msg, STUN_ERROR_STALE_NONCE,
STUN_ERROR_REASON_STALE_NONCE);
return false;
@ -359,14 +360,14 @@ bool TurnServer::CheckAuthorization(TurnServerConnection* conn,
// Fail if one-time-use nonce feature is enabled.
TurnServerAllocation* allocation = FindAllocation(conn);
if (enable_otu_nonce_ && allocation &&
allocation->last_nonce() == nonce_attr->GetString()) {
allocation->last_nonce() == nonce_attr->string_view()) {
SendErrorResponseWithRealmAndNonce(conn, msg, STUN_ERROR_STALE_NONCE,
STUN_ERROR_REASON_STALE_NONCE);
return false;
}
if (allocation) {
allocation->set_last_nonce(nonce_attr->GetString());
allocation->set_last_nonce(nonce_attr->string_view());
}
// Success.
return true;
@ -425,7 +426,7 @@ std::string TurnServer::GenerateNonce(int64_t now) const {
return nonce;
}
bool TurnServer::ValidateNonce(const std::string& nonce) const {
bool TurnServer::ValidateNonce(absl::string_view nonce) const {
// Check the size.
if (nonce.size() != kNonceSize) {
return false;
@ -662,7 +663,7 @@ void TurnServerAllocation::HandleAllocateRequest(const TurnMessage* msg) {
const StunByteStringAttribute* username_attr =
msg->GetByteString(STUN_ATTR_USERNAME);
RTC_DCHECK(username_attr != NULL);
username_ = username_attr->GetString();
username_ = std::string(username_attr->string_view());
// Figure out the lifetime and start the allocation timer.
int lifetime_secs = ComputeLifetime(*msg);

View File

@ -81,7 +81,9 @@ class TurnServerAllocation : public rtc::MessageHandlerAutoCleanup,
const std::string& transaction_id() const { return transaction_id_; }
const std::string& username() const { return username_; }
const std::string& last_nonce() const { return last_nonce_; }
void set_last_nonce(const std::string& nonce) { last_nonce_ = nonce; }
void set_last_nonce(absl::string_view nonce) {
last_nonce_ = std::string(nonce);
}
std::string ToString() const;
@ -288,7 +290,7 @@ class TurnServer : public sigslot::has_slots<> {
const char* data,
size_t size,
const std::string& key) RTC_RUN_ON(thread_);
bool ValidateNonce(const std::string& nonce) const RTC_RUN_ON(thread_);
bool ValidateNonce(absl::string_view nonce) const RTC_RUN_ON(thread_);
TurnServerAllocation* FindAllocation(TurnServerConnection* conn)
RTC_RUN_ON(thread_);