[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}
diff --git a/api/transport/stun.cc b/api/transport/stun.cc
index bc88dcc..e7cb5ed 100644
--- a/api/transport/stun.cc
+++ b/api/transport/stun.cc
@@ -362,22 +362,19 @@
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 @@
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 @@
// 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 @@
: 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 @@
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) {
diff --git a/api/transport/stun.h b/api/transport/stun.h
index cf9c101..43e2a08 100644
--- a/api/transport/stun.h
+++ b/api/transport/stun.h
@@ -233,7 +233,7 @@
}
// 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 @@
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 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 @@
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());
+ }
- void CopyBytes(const char* bytes); // uses strlen
+ [[deprecated]] std::string GetString() const {
+ return std::string(bytes_, length());
+ }
+
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);
diff --git a/api/transport/stun_unittest.cc b/api/transport/stun_unittest.cc
index 14cb1fa..54f91c5 100644
--- a/api/transport/stun_unittest.cc
+++ b/api/transport/stun_unittest.cc
@@ -650,12 +650,12 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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");
diff --git a/p2p/base/connection.cc b/p2p/base/connection.cc
index 4b9fa7e..58adb64 100644
--- a/p2p/base/connection.cc
+++ b/p2p/base/connection.cc
@@ -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 @@
// 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 @@
// 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::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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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());
diff --git a/p2p/base/connection.h b/p2p/base/connection.h
index 83077d2..c654e0d 100644
--- a/p2p/base/connection.h
+++ b/p2p/base/connection.h
@@ -202,8 +202,9 @@
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 @@
// 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.
diff --git a/p2p/base/port.cc b/p2p/base/port.cc
index 9a9836d..fe1a98a 100644
--- a/p2p/base/port.cc
+++ b/p2p/base/port.cc
@@ -653,14 +653,14 @@
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 @@
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,
diff --git a/p2p/base/port.h b/p2p/base/port.h
index 6a5bdfc..b3c3d85 100644
--- a/p2p/base/port.h
+++ b/p2p/base/port.h
@@ -62,7 +62,9 @@
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 @@
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,
diff --git a/p2p/base/port_unittest.cc b/p2p/base/port_unittest.cc
index 43126b6..5ef191b 100644
--- a/p2p/base/port_unittest.cc
+++ b/p2p/base/port_unittest.cc
@@ -1472,7 +1472,7 @@
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 @@
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"));
diff --git a/p2p/base/turn_port.cc b/p2p/base/turn_port.cc
index ea5327b..148fc6b 100644
--- a/p2p/base/turn_port.cc
+++ b/p2p/base/turn_port.cc
@@ -1185,7 +1185,7 @@
"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 @@
"stale nonce error response.";
return false;
}
- set_nonce(nonce_attr->GetString());
+ set_nonce(nonce_attr->string_view());
return true;
}
@@ -1499,7 +1499,7 @@
"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 @@
"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 @@
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 @@
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
diff --git a/p2p/base/turn_port.h b/p2p/base/turn_port.h
index 74d2493..143208a 100644
--- a/p2p/base/turn_port.h
+++ b/p2p/base/turn_port.h
@@ -268,10 +268,10 @@
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();
}
}
diff --git a/p2p/base/turn_port_unittest.cc b/p2p/base/turn_port_unittest.cc
index 2244b9d..2d40e97 100644
--- a/p2p/base/turn_port_unittest.cc
+++ b/p2p/base/turn_port_unittest.cc
@@ -876,7 +876,7 @@
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);
}
diff --git a/p2p/base/turn_server.cc b/p2p/base/turn_server.cc
index 557137f..1e2d5df 100644
--- a/p2p/base/turn_server.cc
+++ b/p2p/base/turn_server.cc
@@ -286,7 +286,7 @@
// 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 @@
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 @@
}
// 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 @@
// 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 @@
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 @@
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);
diff --git a/p2p/base/turn_server.h b/p2p/base/turn_server.h
index fd3639f..95c7a4d 100644
--- a/p2p/base/turn_server.h
+++ b/p2p/base/turn_server.h
@@ -81,7 +81,9 @@
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 @@
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_);