diff --git a/api/transport/stun.cc b/api/transport/stun.cc index bc88dcc5b6..e7cb5ed0f7 100644 --- a/api/transport/stun.cc +++ b/api/transport/stun.cc @@ -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( 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) { diff --git a/api/transport/stun.h b/api/transport/stun.h index cf9c101b02..43e2a087a0 100644 --- a/api/transport/stun.h +++ b/api/transport/stun.h @@ -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); diff --git a/api/transport/stun_unittest.cc b/api/transport/stun_unittest.cc index 14cb1fad93..54f91c522c 100644 --- a/api/transport/stun_unittest.cc +++ b/api/transport/stun_unittest.cc @@ -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"); diff --git a/p2p/base/connection.cc b/p2p/base/connection.cc index 4b9fa7e563..58adb6440b 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& pings_since_last_response, + const std::vector& 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& pings_since_last_response, + const std::vector& 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(cricket::IceGoogMiscInfoBindingRequestAttributeIndex:: - SUPPORT_GOOG_PING_VERSION); +constexpr int kSupportGoogPingVersionRequestIndex = static_cast( + IceGoogMiscInfoBindingRequestAttributeIndex::SUPPORT_GOOG_PING_VERSION); -constexpr int kSupportGoogPingVersionResponseIndex = - static_cast(cricket::IceGoogMiscInfoBindingResponseAttributeIndex:: - SUPPORT_GOOG_PING_VERSION); +constexpr int kSupportGoogPingVersionResponseIndex = static_cast( + 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 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(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(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( - STUN_ATTR_RETRANSMIT_COUNT, - static_cast(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( - 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( - 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( - 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(STUN_ATTR_USE_CANDIDATE)); - } - if (connection_->nomination_ && - connection_->nomination_ != connection_->acked_nomination()) { - message->AddAttribute(std::make_unique( - STUN_ATTR_NOMINATION, connection_->nomination_)); - } - } else if (connection_->port()->GetIceRole() == ICEROLE_CONTROLLED) { - message->AddAttribute(std::make_unique( - 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( - 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 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(requests_, this, BuildPingRequest()); + + if (ShouldSendGoogPing(req->msg())) { + auto message = std::make_unique(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 Connection::BuildPingRequest() { + auto message = std::make_unique(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( + STUN_ATTR_USERNAME, + port()->CreateStunUsername(remote_candidate_.username()))); + message->AddAttribute(std::make_unique( + 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( + 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( + 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(STUN_ATTR_USE_CANDIDATE)); + } + if (nomination_ && nomination_ != acked_nomination()) { + message->AddAttribute(std::make_unique( + STUN_ATTR_NOMINATION, nomination_)); + } + } + + message->AddAttribute(std::make_unique( + STUN_ATTR_PRIORITY, prflx_priority())); + + if (port()->send_retransmit_count_attribute()) { + message->AddAttribute(std::make_unique( + 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& 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()); diff --git a/p2p/base/connection.h b/p2p/base/connection.h index 83077d2f17..c654e0d075 100644 --- a/p2p/base/connection.h +++ b/p2p/base/connection.h @@ -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& nomination = absl::nullopt); + std::unique_ptr BuildPingRequest() RTC_RUN_ON(network_thread_); int64_t last_ping_response_received() const; const absl::optional& 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. diff --git a/p2p/base/port.cc b/p2p/base/port.cc index 9a9836deb9..fe1a98ab9d 100644 --- a/p2p/base/port.cc +++ b/p2p/base/port.cc @@ -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, diff --git a/p2p/base/port.h b/p2p/base/port.h index 6a5bdfcc9b..b3c3d851dd 100644 --- a/p2p/base/port.h +++ b/p2p/base/port.h @@ -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, diff --git a/p2p/base/port_unittest.cc b/p2p/base/port_unittest.cc index 43126b68d8..5ef191b6cd 100644 --- a/p2p/base/port_unittest.cc +++ b/p2p/base/port_unittest.cc @@ -1472,7 +1472,7 @@ TEST_F(PortTest, TestLoopbackCall) { const StunByteStringAttribute* username_attr = msg->GetByteString(STUN_ATTR_USERNAME); modified_req->AddAttribute(std::make_unique( - 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( @@ -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")); diff --git a/p2p/base/turn_port.cc b/p2p/base/turn_port.cc index ea5327b6a4..148fc6b4e3 100644 --- a/p2p/base/turn_port.cc +++ b/p2p/base/turn_port.cc @@ -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 diff --git a/p2p/base/turn_port.h b/p2p/base/turn_port.h index 74d249317f..143208a0f2 100644 --- a/p2p/base/turn_port.h +++ b/p2p/base/turn_port.h @@ -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(); } } diff --git a/p2p/base/turn_port_unittest.cc b/p2p/base/turn_port_unittest.cc index 2244b9d78d..2d40e970fc 100644 --- a/p2p/base/turn_port_unittest.cc +++ b/p2p/base/turn_port_unittest.cc @@ -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); } diff --git a/p2p/base/turn_server.cc b/p2p/base/turn_server.cc index 557137f484..1e2d5df516 100644 --- a/p2p/base/turn_server.cc +++ b/p2p/base/turn_server.cc @@ -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); diff --git a/p2p/base/turn_server.h b/p2p/base/turn_server.h index fd3639fc7f..95c7a4d3b7 100644 --- a/p2p/base/turn_server.h +++ b/p2p/base/turn_server.h @@ -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_);