[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:
parent
0ba10283fb
commit
e83500e17b
@ -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,7 +391,8 @@ 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(),
|
||||
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)) {
|
||||
@ -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) {
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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");
|
||||
|
||||
@ -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());
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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"));
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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_);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user