Add StunDictionary - patch 2
This patch hooks up the StunDictionary to Connection and P2PTransportChannel. Bug: webrtc:15392 Change-Id: Ibeea4d8706ebd42f2353d9d300631c02bf0d484d Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/315100 Reviewed-by: Harald Alvestrand <hta@webrtc.org> Commit-Queue: Jonas Oreland <jonaso@webrtc.org> Cr-Commit-Position: refs/heads/main@{#40519}
This commit is contained in:
parent
2bfa071d09
commit
fc92d33327
@ -704,6 +704,28 @@ void Connection::SendStunBindingResponse(const StunMessage* message) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const StunByteStringAttribute* delta =
|
||||||
|
message->GetByteString(STUN_ATTR_GOOG_DELTA);
|
||||||
|
if (delta) {
|
||||||
|
if (field_trials_->answer_goog_delta && goog_delta_consumer_) {
|
||||||
|
auto ack = (*goog_delta_consumer_)(delta);
|
||||||
|
if (ack) {
|
||||||
|
RTC_LOG(LS_INFO) << "Sending GOOG_DELTA_ACK"
|
||||||
|
<< " delta len: " << delta->length();
|
||||||
|
response.AddAttribute(std::move(ack));
|
||||||
|
} else {
|
||||||
|
RTC_LOG(LS_ERROR) << "GOOG_DELTA consumer did not return ack!";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
RTC_LOG(LS_WARNING) << "Ignore GOOG_DELTA"
|
||||||
|
<< " len: " << delta->length()
|
||||||
|
<< " answer_goog_delta = "
|
||||||
|
<< field_trials_->answer_goog_delta
|
||||||
|
<< " goog_delta_consumer_ = "
|
||||||
|
<< goog_delta_consumer_.has_value();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
response.AddMessageIntegrity(local_candidate().password());
|
response.AddMessageIntegrity(local_candidate().password());
|
||||||
response.AddFingerprint();
|
response.AddFingerprint();
|
||||||
|
|
||||||
@ -933,7 +955,8 @@ int64_t Connection::last_ping_sent() const {
|
|||||||
return last_ping_sent_;
|
return last_ping_sent_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Connection::Ping(int64_t now) {
|
void Connection::Ping(int64_t now,
|
||||||
|
std::unique_ptr<StunByteStringAttribute> delta) {
|
||||||
RTC_DCHECK_RUN_ON(network_thread_);
|
RTC_DCHECK_RUN_ON(network_thread_);
|
||||||
if (!port_)
|
if (!port_)
|
||||||
return;
|
return;
|
||||||
@ -948,10 +971,11 @@ void Connection::Ping(int64_t now) {
|
|||||||
nomination = nomination_;
|
nomination = nomination_;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto req =
|
bool has_delta = delta != nullptr;
|
||||||
std::make_unique<ConnectionRequest>(requests_, this, BuildPingRequest());
|
auto req = std::make_unique<ConnectionRequest>(
|
||||||
|
requests_, this, BuildPingRequest(std::move(delta)));
|
||||||
|
|
||||||
if (ShouldSendGoogPing(req->msg())) {
|
if (!has_delta && ShouldSendGoogPing(req->msg())) {
|
||||||
auto message = std::make_unique<IceMessage>(GOOG_PING_REQUEST, req->id());
|
auto message = std::make_unique<IceMessage>(GOOG_PING_REQUEST, req->id());
|
||||||
message->AddMessageIntegrity32(remote_candidate_.password());
|
message->AddMessageIntegrity32(remote_candidate_.password());
|
||||||
req.reset(new ConnectionRequest(requests_, this, std::move(message)));
|
req.reset(new ConnectionRequest(requests_, this, std::move(message)));
|
||||||
@ -966,7 +990,8 @@ void Connection::Ping(int64_t now) {
|
|||||||
num_pings_sent_++;
|
num_pings_sent_++;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<IceMessage> Connection::BuildPingRequest() {
|
std::unique_ptr<IceMessage> Connection::BuildPingRequest(
|
||||||
|
std::unique_ptr<StunByteStringAttribute> delta) {
|
||||||
auto message = std::make_unique<IceMessage>(STUN_BINDING_REQUEST);
|
auto message = std::make_unique<IceMessage>(STUN_BINDING_REQUEST);
|
||||||
// Note that the order of attributes does not impact the parsing on the
|
// Note that the order of attributes does not impact the parsing on the
|
||||||
// receiver side. The attribute is retrieved then by iterating and matching
|
// receiver side. The attribute is retrieved then by iterating and matching
|
||||||
@ -1022,6 +1047,13 @@ std::unique_ptr<IceMessage> Connection::BuildPingRequest() {
|
|||||||
list->AddTypeAtIndex(kSupportGoogPingVersionRequestIndex, kGoogPingVersion);
|
list->AddTypeAtIndex(kSupportGoogPingVersionRequestIndex, kGoogPingVersion);
|
||||||
message->AddAttribute(std::move(list));
|
message->AddAttribute(std::move(list));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (delta) {
|
||||||
|
RTC_DCHECK(delta->type() == STUN_ATTR_GOOG_DELTA);
|
||||||
|
RTC_LOG(LS_INFO) << "Sending GOOG_DELTA: len: " << delta->length();
|
||||||
|
message->AddAttribute(std::move(delta));
|
||||||
|
}
|
||||||
|
|
||||||
message->AddMessageIntegrity(remote_candidate_.password());
|
message->AddMessageIntegrity(remote_candidate_.password());
|
||||||
message->AddFingerprint();
|
message->AddFingerprint();
|
||||||
|
|
||||||
@ -1393,6 +1425,34 @@ void Connection::OnConnectionRequestResponse(StunRequest* request,
|
|||||||
cached_stun_binding_ = request->msg()->Clone();
|
cached_stun_binding_ = request->msg()->Clone();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Did we send a delta ?
|
||||||
|
const bool sent_goog_delta =
|
||||||
|
request->msg()->GetByteString(STUN_ATTR_GOOG_DELTA) != nullptr;
|
||||||
|
// Did we get a GOOG_DELTA_ACK ?
|
||||||
|
const StunUInt64Attribute* delta_ack =
|
||||||
|
response->GetUInt64(STUN_ATTR_GOOG_DELTA_ACK);
|
||||||
|
|
||||||
|
if (goog_delta_ack_consumer_) {
|
||||||
|
if (sent_goog_delta && delta_ack) {
|
||||||
|
RTC_LOG(LS_VERBOSE) << "Got GOOG_DELTA_ACK len: " << delta_ack->length();
|
||||||
|
(*goog_delta_ack_consumer_)(delta_ack);
|
||||||
|
} else if (sent_goog_delta) {
|
||||||
|
// We sent DELTA but did not get a DELTA_ACK.
|
||||||
|
// This means that remote does not support GOOG_DELTA
|
||||||
|
RTC_LOG(LS_INFO) << "NO DELTA ACK => disable GOOG_DELTA";
|
||||||
|
(*goog_delta_ack_consumer_)(
|
||||||
|
webrtc::RTCError(webrtc::RTCErrorType::UNSUPPORTED_OPERATION));
|
||||||
|
} else if (delta_ack) {
|
||||||
|
// We did NOT send DELTA but got a DELTA_ACK.
|
||||||
|
// That is internal error.
|
||||||
|
RTC_LOG(LS_ERROR) << "DELTA ACK w/o DELTA => disable GOOG_DELTA";
|
||||||
|
(*goog_delta_ack_consumer_)(
|
||||||
|
webrtc::RTCError(webrtc::RTCErrorType::INTERNAL_ERROR));
|
||||||
|
}
|
||||||
|
} else if (delta_ack) {
|
||||||
|
RTC_LOG(LS_ERROR) << "Discard GOOG_DELTA_ACK, no consumer";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Connection::OnConnectionRequestErrorResponse(ConnectionRequest* request,
|
void Connection::OnConnectionRequestErrorResponse(ConnectionRequest* request,
|
||||||
|
|||||||
@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "absl/strings/string_view.h"
|
#include "absl/strings/string_view.h"
|
||||||
@ -205,12 +206,15 @@ class RTC_EXPORT Connection : public CandidatePairInterface {
|
|||||||
|
|
||||||
// Called when this connection should try checking writability again.
|
// Called when this connection should try checking writability again.
|
||||||
int64_t last_ping_sent() const;
|
int64_t last_ping_sent() const;
|
||||||
void Ping(int64_t now);
|
void Ping(int64_t now,
|
||||||
|
std::unique_ptr<StunByteStringAttribute> delta = nullptr);
|
||||||
void ReceivedPingResponse(
|
void ReceivedPingResponse(
|
||||||
int rtt,
|
int rtt,
|
||||||
absl::string_view request_id,
|
absl::string_view request_id,
|
||||||
const absl::optional<uint32_t>& nomination = absl::nullopt);
|
const absl::optional<uint32_t>& nomination = absl::nullopt);
|
||||||
std::unique_ptr<IceMessage> BuildPingRequest() RTC_RUN_ON(network_thread_);
|
std::unique_ptr<IceMessage> BuildPingRequest(
|
||||||
|
std::unique_ptr<StunByteStringAttribute> delta)
|
||||||
|
RTC_RUN_ON(network_thread_);
|
||||||
|
|
||||||
int64_t last_ping_response_received() const;
|
int64_t last_ping_response_received() const;
|
||||||
const absl::optional<std::string>& last_ping_id_received() const;
|
const absl::optional<std::string>& last_ping_id_received() const;
|
||||||
@ -319,7 +323,7 @@ class RTC_EXPORT Connection : public CandidatePairInterface {
|
|||||||
|
|
||||||
std::unique_ptr<IceMessage> BuildPingRequestForTest() {
|
std::unique_ptr<IceMessage> BuildPingRequestForTest() {
|
||||||
RTC_DCHECK_RUN_ON(network_thread_);
|
RTC_DCHECK_RUN_ON(network_thread_);
|
||||||
return BuildPingRequest();
|
return BuildPingRequest(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Public for unit tests.
|
// Public for unit tests.
|
||||||
@ -333,6 +337,20 @@ class RTC_EXPORT Connection : public CandidatePairInterface {
|
|||||||
remote_candidate_.set_password(pwd);
|
remote_candidate_.set_password(pwd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetStunDictConsumer(
|
||||||
|
std::function<std::unique_ptr<StunAttribute>(
|
||||||
|
const StunByteStringAttribute*)> goog_delta_consumer,
|
||||||
|
std::function<void(webrtc::RTCErrorOr<const StunUInt64Attribute*>)>
|
||||||
|
goog_delta_ack_consumer) {
|
||||||
|
goog_delta_consumer_ = std::move(goog_delta_consumer);
|
||||||
|
goog_delta_ack_consumer_ = std::move(goog_delta_ack_consumer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClearStunDictConsumer() {
|
||||||
|
goog_delta_consumer_ = absl::nullopt;
|
||||||
|
goog_delta_ack_consumer_ = absl::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// A ConnectionRequest is a simple STUN ping used to determine writability.
|
// A ConnectionRequest is a simple STUN ping used to determine writability.
|
||||||
class ConnectionRequest;
|
class ConnectionRequest;
|
||||||
@ -475,6 +493,13 @@ class RTC_EXPORT Connection : public CandidatePairInterface {
|
|||||||
const IceFieldTrials* field_trials_;
|
const IceFieldTrials* field_trials_;
|
||||||
rtc::EventBasedExponentialMovingAverage rtt_estimate_
|
rtc::EventBasedExponentialMovingAverage rtt_estimate_
|
||||||
RTC_GUARDED_BY(network_thread_);
|
RTC_GUARDED_BY(network_thread_);
|
||||||
|
|
||||||
|
absl::optional<std::function<std::unique_ptr<StunAttribute>(
|
||||||
|
const StunByteStringAttribute*)>>
|
||||||
|
goog_delta_consumer_;
|
||||||
|
absl::optional<
|
||||||
|
std::function<void(webrtc::RTCErrorOr<const StunUInt64Attribute*>)>>
|
||||||
|
goog_delta_ack_consumer_;
|
||||||
};
|
};
|
||||||
|
|
||||||
// ProxyConnection defers all the interesting work to the port.
|
// ProxyConnection defers all the interesting work to the port.
|
||||||
|
|||||||
@ -14,6 +14,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "absl/strings/string_view.h"
|
#include "absl/strings/string_view.h"
|
||||||
@ -24,6 +25,7 @@
|
|||||||
#include "p2p/base/connection.h"
|
#include "p2p/base/connection.h"
|
||||||
#include "p2p/base/packet_transport_internal.h"
|
#include "p2p/base/packet_transport_internal.h"
|
||||||
#include "p2p/base/port.h"
|
#include "p2p/base/port.h"
|
||||||
|
#include "p2p/base/stun_dictionary.h"
|
||||||
#include "p2p/base/transport_description.h"
|
#include "p2p/base/transport_description.h"
|
||||||
#include "rtc_base/network_constants.h"
|
#include "rtc_base/network_constants.h"
|
||||||
#include "rtc_base/system/rtc_export.h"
|
#include "rtc_base/system/rtc_export.h"
|
||||||
@ -293,6 +295,11 @@ class RTC_EXPORT IceTransportInternal : public rtc::PacketTransportInternal {
|
|||||||
virtual absl::optional<const CandidatePair> GetSelectedCandidatePair()
|
virtual absl::optional<const CandidatePair> GetSelectedCandidatePair()
|
||||||
const = 0;
|
const = 0;
|
||||||
|
|
||||||
|
virtual absl::optional<std::reference_wrapper<StunDictionaryWriter>>
|
||||||
|
GetDictionaryWriter() {
|
||||||
|
return absl::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
sigslot::signal1<IceTransportInternal*> SignalGatheringState;
|
sigslot::signal1<IceTransportInternal*> SignalGatheringState;
|
||||||
|
|
||||||
// Handles sending and receiving of candidates.
|
// Handles sending and receiving of candidates.
|
||||||
@ -330,6 +337,37 @@ class RTC_EXPORT IceTransportInternal : public rtc::PacketTransportInternal {
|
|||||||
|
|
||||||
// Invoked when the transport is being destroyed.
|
// Invoked when the transport is being destroyed.
|
||||||
sigslot::signal1<IceTransportInternal*> SignalDestroyed;
|
sigslot::signal1<IceTransportInternal*> SignalDestroyed;
|
||||||
|
|
||||||
|
// Invoked when remote dictionary has been updated,
|
||||||
|
// i.e. modifications to attributes from remote ice agent has
|
||||||
|
// reflected in our StunDictionaryView.
|
||||||
|
template <typename F>
|
||||||
|
void AddDictionaryViewUpdatedCallback(const void* tag, F&& callback) {
|
||||||
|
dictionary_view_updated_callback_list_.AddReceiver(
|
||||||
|
tag, std::forward<F>(callback));
|
||||||
|
}
|
||||||
|
void RemoveDictionaryViewUpdatedCallback(const void* tag) {
|
||||||
|
dictionary_view_updated_callback_list_.RemoveReceivers(tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invoked when local dictionary has been synchronized,
|
||||||
|
// i.e. remote ice agent has reported acknowledged updates from us.
|
||||||
|
template <typename F>
|
||||||
|
void AddDictionaryWriterSyncedCallback(const void* tag, F&& callback) {
|
||||||
|
dictionary_writer_synced_callback_list_.AddReceiver(
|
||||||
|
tag, std::forward<F>(callback));
|
||||||
|
}
|
||||||
|
void RemoveDictionaryWriterSyncedCallback(const void* tag) {
|
||||||
|
dictionary_writer_synced_callback_list_.RemoveReceivers(tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
webrtc::CallbackList<IceTransportInternal*,
|
||||||
|
const StunDictionaryView&,
|
||||||
|
rtc::ArrayView<uint16_t>>
|
||||||
|
dictionary_view_updated_callback_list_;
|
||||||
|
webrtc::CallbackList<IceTransportInternal*, const StunDictionaryWriter&>
|
||||||
|
dictionary_writer_synced_callback_list_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace cricket
|
} // namespace cricket
|
||||||
|
|||||||
@ -286,6 +286,13 @@ void P2PTransportChannel::AddConnection(Connection* connection) {
|
|||||||
|
|
||||||
connection->set_ice_event_log(&ice_event_log_);
|
connection->set_ice_event_log(&ice_event_log_);
|
||||||
connection->SetIceFieldTrials(&ice_field_trials_);
|
connection->SetIceFieldTrials(&ice_field_trials_);
|
||||||
|
connection->SetStunDictConsumer(
|
||||||
|
[this](const StunByteStringAttribute* delta) {
|
||||||
|
return GoogDeltaReceived(delta);
|
||||||
|
},
|
||||||
|
[this](webrtc::RTCErrorOr<const StunUInt64Attribute*> delta_ack) {
|
||||||
|
GoogDeltaAckReceived(std::move(delta_ack));
|
||||||
|
});
|
||||||
LogCandidatePairConfig(connection,
|
LogCandidatePairConfig(connection,
|
||||||
webrtc::IceCandidatePairConfigType::kAdded);
|
webrtc::IceCandidatePairConfigType::kAdded);
|
||||||
|
|
||||||
@ -727,7 +734,10 @@ void P2PTransportChannel::ParseFieldTrials(
|
|||||||
&ice_field_trials_.dead_connection_timeout_ms,
|
&ice_field_trials_.dead_connection_timeout_ms,
|
||||||
// Stop gathering on strongly connected.
|
// Stop gathering on strongly connected.
|
||||||
"stop_gather_on_strongly_connected",
|
"stop_gather_on_strongly_connected",
|
||||||
&ice_field_trials_.stop_gather_on_strongly_connected)
|
&ice_field_trials_.stop_gather_on_strongly_connected,
|
||||||
|
// GOOG_DELTA
|
||||||
|
"enable_goog_delta", &ice_field_trials_.enable_goog_delta,
|
||||||
|
"answer_goog_delta", &ice_field_trials_.answer_goog_delta)
|
||||||
->Parse(field_trials->Lookup("WebRTC-IceFieldTrials"));
|
->Parse(field_trials->Lookup("WebRTC-IceFieldTrials"));
|
||||||
|
|
||||||
if (ice_field_trials_.dead_connection_timeout_ms < 30000) {
|
if (ice_field_trials_.dead_connection_timeout_ms < 30000) {
|
||||||
@ -782,6 +792,10 @@ void P2PTransportChannel::ParseFieldTrials(
|
|||||||
|
|
||||||
ice_field_trials_.extra_ice_ping =
|
ice_field_trials_.extra_ice_ping =
|
||||||
field_trials->IsEnabled("WebRTC-ExtraICEPing");
|
field_trials->IsEnabled("WebRTC-ExtraICEPing");
|
||||||
|
|
||||||
|
if (!ice_field_trials_.enable_goog_delta) {
|
||||||
|
stun_dict_writer_.Disable();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const IceConfig& P2PTransportChannel::config() const {
|
const IceConfig& P2PTransportChannel::config() const {
|
||||||
@ -2058,7 +2072,7 @@ void P2PTransportChannel::PingConnection(Connection* conn) {
|
|||||||
conn->set_nomination(nomination);
|
conn->set_nomination(nomination);
|
||||||
conn->set_use_candidate_attr(use_candidate_attr);
|
conn->set_use_candidate_attr(use_candidate_attr);
|
||||||
last_ping_sent_ms_ = rtc::TimeMillis();
|
last_ping_sent_ms_ = rtc::TimeMillis();
|
||||||
conn->Ping(last_ping_sent_ms_);
|
conn->Ping(last_ping_sent_ms_, stun_dict_writer_.CreateDelta());
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t P2PTransportChannel::GetNominationAttr(Connection* conn) const {
|
uint32_t P2PTransportChannel::GetNominationAttr(Connection* conn) const {
|
||||||
@ -2129,11 +2143,12 @@ void P2PTransportChannel::OnConnectionDestroyed(Connection* connection) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void P2PTransportChannel::RemoveConnection(const Connection* connection) {
|
void P2PTransportChannel::RemoveConnection(Connection* connection) {
|
||||||
RTC_DCHECK_RUN_ON(network_thread_);
|
RTC_DCHECK_RUN_ON(network_thread_);
|
||||||
auto it = absl::c_find(connections_, connection);
|
auto it = absl::c_find(connections_, connection);
|
||||||
RTC_DCHECK(it != connections_.end());
|
RTC_DCHECK(it != connections_.end());
|
||||||
connections_.erase(it);
|
connections_.erase(it);
|
||||||
|
connection->ClearStunDictConsumer();
|
||||||
ice_controller_->OnConnectionDestroyed(connection);
|
ice_controller_->OnConnectionDestroyed(connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2307,4 +2322,34 @@ void P2PTransportChannel::LogCandidatePairConfig(
|
|||||||
conn->ToLogDescription());
|
conn->ToLogDescription());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<StunAttribute> P2PTransportChannel::GoogDeltaReceived(
|
||||||
|
const StunByteStringAttribute* delta) {
|
||||||
|
auto error = stun_dict_view_.ApplyDelta(*delta);
|
||||||
|
if (error.ok()) {
|
||||||
|
auto& result = error.value();
|
||||||
|
RTC_LOG(LS_INFO) << "Applied GOOG_DELTA";
|
||||||
|
dictionary_view_updated_callback_list_.Send(this, stun_dict_view_,
|
||||||
|
result.second);
|
||||||
|
return std::move(result.first);
|
||||||
|
} else {
|
||||||
|
RTC_LOG(LS_ERROR) << "Failed to apply GOOG_DELTA: "
|
||||||
|
<< error.error().message();
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void P2PTransportChannel::GoogDeltaAckReceived(
|
||||||
|
webrtc::RTCErrorOr<const StunUInt64Attribute*> error_or_ack) {
|
||||||
|
if (error_or_ack.ok()) {
|
||||||
|
RTC_LOG(LS_ERROR) << "Applied GOOG_DELTA_ACK";
|
||||||
|
auto ack = error_or_ack.value();
|
||||||
|
stun_dict_writer_.ApplyDeltaAck(*ack);
|
||||||
|
dictionary_writer_synced_callback_list_.Send(this, stun_dict_writer_);
|
||||||
|
} else {
|
||||||
|
stun_dict_writer_.Disable();
|
||||||
|
RTC_LOG(LS_ERROR) << "Failed GOOG_DELTA_ACK: "
|
||||||
|
<< error_or_ack.error().message();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace cricket
|
} // namespace cricket
|
||||||
|
|||||||
@ -61,6 +61,7 @@
|
|||||||
#include "p2p/base/port_allocator.h"
|
#include "p2p/base/port_allocator.h"
|
||||||
#include "p2p/base/port_interface.h"
|
#include "p2p/base/port_interface.h"
|
||||||
#include "p2p/base/regathering_controller.h"
|
#include "p2p/base/regathering_controller.h"
|
||||||
|
#include "p2p/base/stun_dictionary.h"
|
||||||
#include "p2p/base/transport_description.h"
|
#include "p2p/base/transport_description.h"
|
||||||
#include "rtc_base/async_packet_socket.h"
|
#include "rtc_base/async_packet_socket.h"
|
||||||
#include "rtc_base/checks.h"
|
#include "rtc_base/checks.h"
|
||||||
@ -216,7 +217,7 @@ class RTC_EXPORT P2PTransportChannel : public IceTransportInternal,
|
|||||||
int check_receiving_interval() const;
|
int check_receiving_interval() const;
|
||||||
absl::optional<rtc::NetworkRoute> network_route() const override;
|
absl::optional<rtc::NetworkRoute> network_route() const override;
|
||||||
|
|
||||||
void RemoveConnection(const Connection* connection);
|
void RemoveConnection(Connection* connection);
|
||||||
|
|
||||||
// Helper method used only in unittest.
|
// Helper method used only in unittest.
|
||||||
rtc::DiffServCodePoint DefaultDscpValue() const;
|
rtc::DiffServCodePoint DefaultDscpValue() const;
|
||||||
@ -254,6 +255,11 @@ class RTC_EXPORT P2PTransportChannel : public IceTransportInternal,
|
|||||||
return ss.Release();
|
return ss.Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
absl::optional<std::reference_wrapper<StunDictionaryWriter>>
|
||||||
|
GetDictionaryWriter() override {
|
||||||
|
return stun_dict_writer_;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
P2PTransportChannel(
|
P2PTransportChannel(
|
||||||
absl::string_view transport_name,
|
absl::string_view transport_name,
|
||||||
@ -494,6 +500,10 @@ class RTC_EXPORT P2PTransportChannel : public IceTransportInternal,
|
|||||||
Candidate candidate,
|
Candidate candidate,
|
||||||
const webrtc::AsyncDnsResolverResult& result);
|
const webrtc::AsyncDnsResolverResult& result);
|
||||||
|
|
||||||
|
std::unique_ptr<StunAttribute> GoogDeltaReceived(
|
||||||
|
const StunByteStringAttribute*);
|
||||||
|
void GoogDeltaAckReceived(webrtc::RTCErrorOr<const StunUInt64Attribute*>);
|
||||||
|
|
||||||
// Bytes/packets sent/received on this channel.
|
// Bytes/packets sent/received on this channel.
|
||||||
uint64_t bytes_sent_ = 0;
|
uint64_t bytes_sent_ = 0;
|
||||||
uint64_t bytes_received_ = 0;
|
uint64_t bytes_received_ = 0;
|
||||||
@ -509,6 +519,12 @@ class RTC_EXPORT P2PTransportChannel : public IceTransportInternal,
|
|||||||
|
|
||||||
// Parsed field trials.
|
// Parsed field trials.
|
||||||
IceFieldTrials ice_field_trials_;
|
IceFieldTrials ice_field_trials_;
|
||||||
|
|
||||||
|
// A dictionary of attributes that will be reflected to peer.
|
||||||
|
StunDictionaryWriter stun_dict_writer_;
|
||||||
|
|
||||||
|
// A dictionary that tracks attributes from peer.
|
||||||
|
StunDictionaryView stun_dict_view_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace cricket
|
} // namespace cricket
|
||||||
|
|||||||
@ -70,6 +70,10 @@ struct IceFieldTrials {
|
|||||||
|
|
||||||
bool piggyback_ice_check_acknowledgement = false;
|
bool piggyback_ice_check_acknowledgement = false;
|
||||||
bool extra_ice_ping = false;
|
bool extra_ice_ping = false;
|
||||||
|
|
||||||
|
// Announce/enable GOOG_DELTA
|
||||||
|
bool enable_goog_delta = true; // send GOOG DELTA
|
||||||
|
bool answer_goog_delta = true; // answer GOOG DELTA
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace cricket
|
} // namespace cricket
|
||||||
|
|||||||
@ -65,6 +65,7 @@ using ::testing::DoAll;
|
|||||||
using ::testing::InSequence;
|
using ::testing::InSequence;
|
||||||
using ::testing::InvokeArgument;
|
using ::testing::InvokeArgument;
|
||||||
using ::testing::InvokeWithoutArgs;
|
using ::testing::InvokeWithoutArgs;
|
||||||
|
using ::testing::MockFunction;
|
||||||
using ::testing::Return;
|
using ::testing::Return;
|
||||||
using ::testing::ReturnRef;
|
using ::testing::ReturnRef;
|
||||||
using ::testing::SaveArg;
|
using ::testing::SaveArg;
|
||||||
@ -3417,6 +3418,38 @@ TEST_F(P2PTransportChannelMultihomedTest, TestVpnOnlyVpn) {
|
|||||||
kDefaultTimeout, clock);
|
kDefaultTimeout, clock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(P2PTransportChannelMultihomedTest, StunDictionaryPerformsSync) {
|
||||||
|
rtc::ScopedFakeClock clock;
|
||||||
|
AddAddress(0, kPublicAddrs[0], "eth0", rtc::ADAPTER_TYPE_CELLULAR);
|
||||||
|
AddAddress(0, kAlternateAddrs[0], "vpn0", rtc::ADAPTER_TYPE_VPN,
|
||||||
|
rtc::ADAPTER_TYPE_ETHERNET);
|
||||||
|
AddAddress(1, kPublicAddrs[1]);
|
||||||
|
|
||||||
|
// Create channels and let them go writable, as usual.
|
||||||
|
CreateChannels();
|
||||||
|
|
||||||
|
MockFunction<void(IceTransportInternal*, const StunDictionaryView&,
|
||||||
|
rtc::ArrayView<uint16_t>)>
|
||||||
|
view_updated_func;
|
||||||
|
ep2_ch1()->AddDictionaryViewUpdatedCallback(
|
||||||
|
"tag", view_updated_func.AsStdFunction());
|
||||||
|
MockFunction<void(IceTransportInternal*, const StunDictionaryWriter&)>
|
||||||
|
writer_synced_func;
|
||||||
|
ep1_ch1()->AddDictionaryWriterSyncedCallback(
|
||||||
|
"tag", writer_synced_func.AsStdFunction());
|
||||||
|
auto& dict_writer = ep1_ch1()->GetDictionaryWriter()->get();
|
||||||
|
dict_writer.SetByteString(12)->CopyBytes("keso");
|
||||||
|
EXPECT_CALL(view_updated_func, Call)
|
||||||
|
.WillOnce([&](auto* channel, auto& view, auto keys) {
|
||||||
|
EXPECT_EQ(keys.size(), 1u);
|
||||||
|
EXPECT_EQ(keys[0], 12);
|
||||||
|
EXPECT_EQ(view.GetByteString(12)->string_view(), "keso");
|
||||||
|
});
|
||||||
|
EXPECT_CALL(writer_synced_func, Call).Times(1);
|
||||||
|
EXPECT_TRUE_SIMULATED_WAIT(CheckConnected(ep1_ch1(), ep2_ch1()),
|
||||||
|
kMediumTimeout, clock);
|
||||||
|
}
|
||||||
|
|
||||||
// A collection of tests which tests a single P2PTransportChannel by sending
|
// A collection of tests which tests a single P2PTransportChannel by sending
|
||||||
// pings.
|
// pings.
|
||||||
class P2PTransportChannelPingTest : public ::testing::Test,
|
class P2PTransportChannelPingTest : public ::testing::Test,
|
||||||
|
|||||||
@ -20,6 +20,7 @@
|
|||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "absl/memory/memory.h"
|
||||||
#include "absl/strings/string_view.h"
|
#include "absl/strings/string_view.h"
|
||||||
#include "absl/types/optional.h"
|
#include "absl/types/optional.h"
|
||||||
#include "api/candidate.h"
|
#include "api/candidate.h"
|
||||||
@ -3833,7 +3834,6 @@ class ConnectionTest : public PortTest {
|
|||||||
|
|
||||||
void OnConnectionStateChange(Connection* connection) { num_state_changes_++; }
|
void OnConnectionStateChange(Connection* connection) { num_state_changes_++; }
|
||||||
|
|
||||||
private:
|
|
||||||
std::unique_ptr<TestPort> lport_;
|
std::unique_ptr<TestPort> lport_;
|
||||||
std::unique_ptr<TestPort> rport_;
|
std::unique_ptr<TestPort> rport_;
|
||||||
};
|
};
|
||||||
@ -3922,4 +3922,93 @@ TEST_F(ConnectionTest, ConnectionForgetLearnedStateDoesNotTriggerStateChange) {
|
|||||||
EXPECT_EQ(num_state_changes_, 2);
|
EXPECT_EQ(num_state_changes_, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test normal happy case.
|
||||||
|
// Sending a delta and getting a delta ack in response.
|
||||||
|
TEST_F(ConnectionTest, SendReceiveGoogDelta) {
|
||||||
|
constexpr int64_t ms = 10;
|
||||||
|
Connection* lconn = CreateConnection(ICEROLE_CONTROLLING);
|
||||||
|
Connection* rconn = CreateConnection(ICEROLE_CONTROLLED);
|
||||||
|
|
||||||
|
std::unique_ptr<StunByteStringAttribute> delta =
|
||||||
|
absl::WrapUnique(new StunByteStringAttribute(STUN_ATTR_GOOG_DELTA));
|
||||||
|
delta->CopyBytes("DELTA");
|
||||||
|
|
||||||
|
std::unique_ptr<StunAttribute> delta_ack =
|
||||||
|
absl::WrapUnique(new StunUInt64Attribute(STUN_ATTR_GOOG_DELTA_ACK, 133));
|
||||||
|
|
||||||
|
bool received_goog_delta = false;
|
||||||
|
bool received_goog_delta_ack = false;
|
||||||
|
lconn->SetStunDictConsumer(
|
||||||
|
// DeltaReceived
|
||||||
|
[](const StunByteStringAttribute* delta)
|
||||||
|
-> std::unique_ptr<StunAttribute> { return nullptr; },
|
||||||
|
// DeltaAckReceived
|
||||||
|
[&](webrtc::RTCErrorOr<const StunUInt64Attribute*> error_or_ack) {
|
||||||
|
received_goog_delta_ack = true;
|
||||||
|
EXPECT_TRUE(error_or_ack.ok());
|
||||||
|
EXPECT_EQ(error_or_ack.value()->value(), 133ull);
|
||||||
|
});
|
||||||
|
|
||||||
|
rconn->SetStunDictConsumer(
|
||||||
|
// DeltaReceived
|
||||||
|
[&](const StunByteStringAttribute* delta)
|
||||||
|
-> std::unique_ptr<StunAttribute> {
|
||||||
|
received_goog_delta = true;
|
||||||
|
EXPECT_EQ(delta->string_view(), "DELTA");
|
||||||
|
return std::move(delta_ack);
|
||||||
|
},
|
||||||
|
// DeltaAckReceived
|
||||||
|
[](webrtc::RTCErrorOr<const StunUInt64Attribute*> error_or__ack) {});
|
||||||
|
|
||||||
|
lconn->Ping(rtc::TimeMillis(), std::move(delta));
|
||||||
|
ASSERT_TRUE_WAIT(lport_->last_stun_msg(), kDefaultTimeout);
|
||||||
|
ASSERT_TRUE(lport_->last_stun_buf());
|
||||||
|
rconn->OnReadPacket(lport_->last_stun_buf()->data<char>(),
|
||||||
|
lport_->last_stun_buf()->size(), /* packet_time_us */ -1);
|
||||||
|
EXPECT_TRUE(received_goog_delta);
|
||||||
|
|
||||||
|
clock_.AdvanceTime(webrtc::TimeDelta::Millis(ms));
|
||||||
|
ASSERT_TRUE_WAIT(rport_->last_stun_msg(), kDefaultTimeout);
|
||||||
|
ASSERT_TRUE(rport_->last_stun_buf());
|
||||||
|
lconn->OnReadPacket(rport_->last_stun_buf()->data<char>(),
|
||||||
|
rport_->last_stun_buf()->size(), /* packet_time_us */ -1);
|
||||||
|
EXPECT_TRUE(received_goog_delta_ack);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that sending a goog delta and not getting
|
||||||
|
// a delta ack in reply gives an error callback.
|
||||||
|
TEST_F(ConnectionTest, SendGoogDeltaNoReply) {
|
||||||
|
constexpr int64_t ms = 10;
|
||||||
|
Connection* lconn = CreateConnection(ICEROLE_CONTROLLING);
|
||||||
|
Connection* rconn = CreateConnection(ICEROLE_CONTROLLED);
|
||||||
|
|
||||||
|
std::unique_ptr<StunByteStringAttribute> delta =
|
||||||
|
absl::WrapUnique(new StunByteStringAttribute(STUN_ATTR_GOOG_DELTA));
|
||||||
|
delta->CopyBytes("DELTA");
|
||||||
|
|
||||||
|
bool received_goog_delta_ack_error = false;
|
||||||
|
lconn->SetStunDictConsumer(
|
||||||
|
// DeltaReceived
|
||||||
|
[](const StunByteStringAttribute* delta)
|
||||||
|
-> std::unique_ptr<StunAttribute> { return nullptr; },
|
||||||
|
// DeltaAckReceived
|
||||||
|
[&](webrtc::RTCErrorOr<const StunUInt64Attribute*> error_or_ack) {
|
||||||
|
received_goog_delta_ack_error = true;
|
||||||
|
EXPECT_FALSE(error_or_ack.ok());
|
||||||
|
});
|
||||||
|
|
||||||
|
lconn->Ping(rtc::TimeMillis(), std::move(delta));
|
||||||
|
ASSERT_TRUE_WAIT(lport_->last_stun_msg(), kDefaultTimeout);
|
||||||
|
ASSERT_TRUE(lport_->last_stun_buf());
|
||||||
|
rconn->OnReadPacket(lport_->last_stun_buf()->data<char>(),
|
||||||
|
lport_->last_stun_buf()->size(), /* packet_time_us */ -1);
|
||||||
|
|
||||||
|
clock_.AdvanceTime(webrtc::TimeDelta::Millis(ms));
|
||||||
|
ASSERT_TRUE_WAIT(rport_->last_stun_msg(), kDefaultTimeout);
|
||||||
|
ASSERT_TRUE(rport_->last_stun_buf());
|
||||||
|
lconn->OnReadPacket(rport_->last_stun_buf()->data<char>(),
|
||||||
|
rport_->last_stun_buf()->size(), /* packet_time_us */ -1);
|
||||||
|
EXPECT_TRUE(received_goog_delta_ack_error);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace cricket
|
} // namespace cricket
|
||||||
|
|||||||
@ -233,7 +233,15 @@ size_t StunDictionaryView::GetLength(int key) const {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void StunDictionaryWriter::Disable() {
|
||||||
|
disabled_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
void StunDictionaryWriter::Delete(int key) {
|
void StunDictionaryWriter::Delete(int key) {
|
||||||
|
if (disabled_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (dictionary_) {
|
if (dictionary_) {
|
||||||
if (dictionary_->attrs_.find(key) == dictionary_->attrs_.end()) {
|
if (dictionary_->attrs_.find(key) == dictionary_->attrs_.end()) {
|
||||||
return;
|
return;
|
||||||
@ -262,6 +270,9 @@ void StunDictionaryWriter::Delete(int key) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void StunDictionaryWriter::Set(std::unique_ptr<StunAttribute> attr) {
|
void StunDictionaryWriter::Set(std::unique_ptr<StunAttribute> attr) {
|
||||||
|
if (disabled_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
int key = attr->type();
|
int key = attr->type();
|
||||||
// remove any pending updates.
|
// remove any pending updates.
|
||||||
pending_.erase(
|
pending_.erase(
|
||||||
@ -284,6 +295,9 @@ void StunDictionaryWriter::Set(std::unique_ptr<StunAttribute> attr) {
|
|||||||
// Create an StunByteStringAttribute containing the pending (e.g not ack:ed)
|
// Create an StunByteStringAttribute containing the pending (e.g not ack:ed)
|
||||||
// modifications.
|
// modifications.
|
||||||
std::unique_ptr<StunByteStringAttribute> StunDictionaryWriter::CreateDelta() {
|
std::unique_ptr<StunByteStringAttribute> StunDictionaryWriter::CreateDelta() {
|
||||||
|
if (disabled_) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
if (pending_.empty()) {
|
if (pending_.empty()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -62,7 +62,7 @@ class StunDictionaryView {
|
|||||||
const StunUInt16ListAttribute* GetUInt16List(int key) const;
|
const StunUInt16ListAttribute* GetUInt16List(int key) const;
|
||||||
|
|
||||||
bool empty() const { return attrs_.empty(); }
|
bool empty() const { return attrs_.empty(); }
|
||||||
int size() const { return attrs_.size(); }
|
size_t size() const { return attrs_.size(); }
|
||||||
int bytes_stored() const { return bytes_stored_; }
|
int bytes_stored() const { return bytes_stored_; }
|
||||||
void set_max_bytes_stored(int max_bytes_stored) {
|
void set_max_bytes_stored(int max_bytes_stored) {
|
||||||
max_bytes_stored_ = max_bytes_stored;
|
max_bytes_stored_ = max_bytes_stored;
|
||||||
@ -175,9 +175,17 @@ class StunDictionaryWriter {
|
|||||||
const StunDictionaryView* dictionary() { return dictionary_.get(); }
|
const StunDictionaryView* dictionary() { return dictionary_.get(); }
|
||||||
const StunDictionaryView* operator->() { return dictionary_.get(); }
|
const StunDictionaryView* operator->() { return dictionary_.get(); }
|
||||||
|
|
||||||
|
// Disable writer,
|
||||||
|
// i.e CreateDelta always return null, and no modifications are made.
|
||||||
|
// This is called if remote peer does not support GOOG_DELTA.
|
||||||
|
void Disable();
|
||||||
|
bool disabled() const { return disabled_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void Set(std::unique_ptr<StunAttribute> attr);
|
void Set(std::unique_ptr<StunAttribute> attr);
|
||||||
|
|
||||||
|
bool disabled_ = false;
|
||||||
|
|
||||||
// version of modification.
|
// version of modification.
|
||||||
int64_t version_ = 1;
|
int64_t version_ = 1;
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user