From 6ca98363eeb6dd6342cfdc4419aebb90996c06bb Mon Sep 17 00:00:00 2001 From: Tim Haloun Date: Mon, 17 Sep 2018 17:06:08 -0700 Subject: [PATCH] Prepare for per-media DSCP values. Push dscp for stun packets to the port layer where they are created. Bug: webrtc:5008 Change-Id: Iaf4788ef2170fa67a8cdee6e9ea6b8c158f286cb Reviewed-on: https://webrtc-review.googlesource.com/c/92940 Reviewed-by: Stefan Holmer Commit-Queue: Tim Haloun Cr-Commit-Position: refs/heads/master@{#24963} --- media/base/fakenetworkinterface.h | 5 ++ media/base/mediachannel.cc | 8 +-- media/base/mediachannel.h | 6 +- media/engine/webrtcvideoengine.cc | 9 ++- media/engine/webrtcvideoengine_unittest.cc | 17 +++-- media/engine/webrtcvoiceengine.h | 6 ++ media/engine/webrtcvoiceengine_unittest.cc | 19 ++++-- p2p/base/port.cc | 11 +++- p2p/base/port.h | 7 +- p2p/base/relayport.cc | 11 +++- p2p/base/stunport.cc | 12 +++- p2p/base/stunport.h | 3 + p2p/base/stunport_unittest.cc | 74 +++++++++++++++++++--- p2p/base/turnport.cc | 12 +++- p2p/base/turnport.h | 3 + 15 files changed, 165 insertions(+), 38 deletions(-) diff --git a/media/base/fakenetworkinterface.h b/media/base/fakenetworkinterface.h index 98d9c469a5..0f14659c46 100644 --- a/media/base/fakenetworkinterface.h +++ b/media/base/fakenetworkinterface.h @@ -109,6 +109,7 @@ class FakeNetworkInterface : public MediaChannel::NetworkInterface, int sendbuf_size() const { return sendbuf_size_; } int recvbuf_size() const { return recvbuf_size_; } rtc::DiffServCodePoint dscp() const { return dscp_; } + rtc::PacketOptions options() const { return options_; } protected: virtual bool SendPacket(rtc::CopyOnWriteBuffer* packet, @@ -120,6 +121,7 @@ class FakeNetworkInterface : public MediaChannel::NetworkInterface, return false; } sent_ssrcs_[cur_ssrc]++; + options_ = options; rtp_packets_.push_back(*packet); if (conf_) { @@ -139,6 +141,7 @@ class FakeNetworkInterface : public MediaChannel::NetworkInterface, const rtc::PacketOptions& options) { rtc::CritScope cs(&crit_); rtcp_packets_.push_back(*packet); + options_ = options; if (!conf_) { // don't worry about RTCP in conf mode for now PostMessage(ST_RTCP, *packet); @@ -215,6 +218,8 @@ class FakeNetworkInterface : public MediaChannel::NetworkInterface, int sendbuf_size_; int recvbuf_size_; rtc::DiffServCodePoint dscp_; + // Options of the most recently sent packet. + rtc::PacketOptions options_; }; } // namespace cricket diff --git a/media/base/mediachannel.cc b/media/base/mediachannel.cc index b7f1f4f040..304d7f8232 100644 --- a/media/base/mediachannel.cc +++ b/media/base/mediachannel.cc @@ -21,14 +21,14 @@ void MediaChannel::SetInterface(NetworkInterface* iface) { SetDscp(enable_dscp_ ? PreferredDscp() : rtc::DSCP_DEFAULT); } -rtc::DiffServCodePoint MediaChannel::PreferredDscp() const { - return rtc::DSCP_DEFAULT; -} - int MediaChannel::GetRtpSendTimeExtnId() const { return -1; } +rtc::DiffServCodePoint MediaChannel::PreferredDscp() const { + return rtc::DSCP_DEFAULT; +} + void MediaChannel::SetFrameEncryptor( webrtc::FrameEncryptorInterface* frame_encryptor) { frame_encryptor_ = frame_encryptor; diff --git a/media/base/mediachannel.h b/media/base/mediachannel.h index 44beb8fcf2..98b36ac22f 100644 --- a/media/base/mediachannel.h +++ b/media/base/mediachannel.h @@ -186,7 +186,6 @@ class MediaChannel : public sigslot::has_slots<> { // Sets the abstract interface class for sending RTP/RTCP data. virtual void SetInterface(NetworkInterface* iface); - virtual rtc::DiffServCodePoint PreferredDscp() const; // Called when a RTP packet is received. virtual void OnPacketReceived(rtc::CopyOnWriteBuffer* packet, const rtc::PacketTime& packet_time) = 0; @@ -249,6 +248,11 @@ class MediaChannel : public sigslot::has_slots<> { return network_interface_->SetOption(type, opt, option); } + protected: + virtual rtc::DiffServCodePoint PreferredDscp() const; + + bool DscpEnabled() const { return enable_dscp_; } + private: // This method sets DSCP |value| on both RTP and RTCP channels. int SetDscp(rtc::DiffServCodePoint value) { diff --git a/media/engine/webrtcvideoengine.cc b/media/engine/webrtcvideoengine.cc index c7c1c15b36..f35bcb6eeb 100644 --- a/media/engine/webrtcvideoengine.cc +++ b/media/engine/webrtcvideoengine.cc @@ -1471,12 +1471,19 @@ bool WebRtcVideoChannel::SendRtp(const uint8_t* data, rtc::CopyOnWriteBuffer packet(data, len, kMaxRtpPacketLen); rtc::PacketOptions rtc_options; rtc_options.packet_id = options.packet_id; + if (DscpEnabled()) { + rtc_options.dscp = PreferredDscp(); + } return MediaChannel::SendPacket(&packet, rtc_options); } bool WebRtcVideoChannel::SendRtcp(const uint8_t* data, size_t len) { rtc::CopyOnWriteBuffer packet(data, len, kMaxRtpPacketLen); - return MediaChannel::SendRtcp(&packet, rtc::PacketOptions()); + rtc::PacketOptions rtc_options; + if (DscpEnabled()) { + rtc_options.dscp = PreferredDscp(); + } + return MediaChannel::SendRtcp(&packet, rtc_options); } WebRtcVideoChannel::WebRtcVideoSendStream::VideoSendStreamParameters:: diff --git a/media/engine/webrtcvideoengine_unittest.cc b/media/engine/webrtcvideoengine_unittest.cc index 212bcf2620..e87f63ff4a 100644 --- a/media/engine/webrtcvideoengine_unittest.cc +++ b/media/engine/webrtcvideoengine_unittest.cc @@ -4574,22 +4574,31 @@ TEST_F(WebRtcVideoChannelTest, TestSetDscpOptions) { std::unique_ptr network_interface( new cricket::FakeNetworkInterface); MediaConfig config; - std::unique_ptr channel; + std::unique_ptr channel; - channel.reset(engine_.CreateChannel(call_.get(), config, VideoOptions())); + channel.reset(static_cast( + engine_.CreateChannel(call_.get(), config, VideoOptions()))); channel->SetInterface(network_interface.get()); // Default value when DSCP is disabled should be DSCP_DEFAULT. EXPECT_EQ(rtc::DSCP_DEFAULT, network_interface->dscp()); config.enable_dscp = true; - channel.reset(engine_.CreateChannel(call_.get(), config, VideoOptions())); + channel.reset(static_cast( + engine_.CreateChannel(call_.get(), config, VideoOptions()))); channel->SetInterface(network_interface.get()); EXPECT_EQ(rtc::DSCP_AF41, network_interface->dscp()); + // Packets should also self-identify their dscp in PacketOptions. + const uint8_t kData[10] = {0}; + EXPECT_TRUE(static_cast(channel.get()) + ->SendRtcp(kData, sizeof(kData))); + EXPECT_EQ(rtc::DSCP_AF41, network_interface->options().dscp); + // Verify that setting the option to false resets the // DiffServCodePoint. config.enable_dscp = false; - channel.reset(engine_.CreateChannel(call_.get(), config, VideoOptions())); + channel.reset(static_cast( + engine_.CreateChannel(call_.get(), config, VideoOptions()))); channel->SetInterface(network_interface.get()); EXPECT_EQ(rtc::DSCP_DEFAULT, network_interface->dscp()); } diff --git a/media/engine/webrtcvoiceengine.h b/media/engine/webrtcvoiceengine.h index dcf8ebe92a..db3f7c2e7c 100644 --- a/media/engine/webrtcvoiceengine.h +++ b/media/engine/webrtcvoiceengine.h @@ -200,12 +200,18 @@ class WebRtcVoiceMediaChannel final : public VoiceMediaChannel, rtc::CopyOnWriteBuffer packet(data, len, kMaxRtpPacketLen); rtc::PacketOptions rtc_options; rtc_options.packet_id = options.packet_id; + if (DscpEnabled()) { + rtc_options.dscp = PreferredDscp(); + } return VoiceMediaChannel::SendPacket(&packet, rtc_options); } bool SendRtcp(const uint8_t* data, size_t len) override { rtc::CopyOnWriteBuffer packet(data, len, kMaxRtpPacketLen); rtc::PacketOptions rtc_options; + if (DscpEnabled()) { + rtc_options.dscp = PreferredDscp(); + } return VoiceMediaChannel::SendRtcp(&packet, rtc_options); } diff --git a/media/engine/webrtcvoiceengine_unittest.cc b/media/engine/webrtcvoiceengine_unittest.cc index f54826ec55..bb816eed11 100644 --- a/media/engine/webrtcvoiceengine_unittest.cc +++ b/media/engine/webrtcvoiceengine_unittest.cc @@ -3016,7 +3016,7 @@ TEST_F(WebRtcVoiceEngineTestFake, TestSetDscpOptions) { EXPECT_TRUE(SetupSendStream()); cricket::FakeNetworkInterface network_interface; cricket::MediaConfig config; - std::unique_ptr channel; + std::unique_ptr channel; webrtc::AudioProcessing::Config apm_config; EXPECT_CALL(*apm_, GetConfig()) @@ -3025,23 +3025,28 @@ TEST_F(WebRtcVoiceEngineTestFake, TestSetDscpOptions) { .WillRepeatedly(SaveArg<0>(&apm_config)); EXPECT_CALL(*apm_, SetExtraOptions(testing::_)).Times(3); - channel.reset( - engine_->CreateChannel(&call_, config, cricket::AudioOptions())); + channel.reset(static_cast( + engine_->CreateChannel(&call_, config, cricket::AudioOptions()))); channel->SetInterface(&network_interface); // Default value when DSCP is disabled should be DSCP_DEFAULT. EXPECT_EQ(rtc::DSCP_DEFAULT, network_interface.dscp()); config.enable_dscp = true; - channel.reset( - engine_->CreateChannel(&call_, config, cricket::AudioOptions())); + channel.reset(static_cast( + engine_->CreateChannel(&call_, config, cricket::AudioOptions()))); channel->SetInterface(&network_interface); EXPECT_EQ(rtc::DSCP_EF, network_interface.dscp()); + // Packets should also self-identify their dscp in PacketOptions. + const uint8_t kData[10] = {0}; + EXPECT_TRUE(channel->SendRtcp(kData, sizeof(kData))); + EXPECT_EQ(rtc::DSCP_EF, network_interface.options().dscp); + // Verify that setting the option to false resets the // DiffServCodePoint. config.enable_dscp = false; - channel.reset( - engine_->CreateChannel(&call_, config, cricket::AudioOptions())); + channel.reset(static_cast( + engine_->CreateChannel(&call_, config, cricket::AudioOptions()))); channel->SetInterface(&network_interface); // Default value when DSCP is disabled should be DSCP_DEFAULT. EXPECT_EQ(rtc::DSCP_DEFAULT, network_interface.dscp()); diff --git a/p2p/base/port.cc b/p2p/base/port.cc index 1fe7305fa2..ac7521e667 100644 --- a/p2p/base/port.cc +++ b/p2p/base/port.cc @@ -670,6 +670,11 @@ bool Port::IsCompatibleAddress(const rtc::SocketAddress& addr) { return true; } +rtc::DiffServCodePoint Port::StunDscpValue() const { + // By default, inherit from whatever the MediaChannel sends. + return rtc::DSCP_NO_CHANGE; +} + bool Port::ParseStunUsername(const StunMessage* stun_msg, std::string* local_ufrag, std::string* remote_ufrag) const { @@ -818,7 +823,7 @@ void Port::SendBindingResponse(StunMessage* request, // Send the response message. rtc::ByteBufferWriter buf; response.Write(&buf); - rtc::PacketOptions options(DefaultDscpValue()); + rtc::PacketOptions options(StunDscpValue()); options.info_signaled_after_sent.packet_type = rtc::PacketType::kIceConnectivityCheckResponse; auto err = SendTo(buf.Data(), buf.Length(), addr, options, false); @@ -871,7 +876,7 @@ void Port::SendBindingErrorResponse(StunMessage* request, // Send the response message. rtc::ByteBufferWriter buf; response.Write(&buf); - rtc::PacketOptions options(DefaultDscpValue()); + rtc::PacketOptions options(StunDscpValue()); options.info_signaled_after_sent.packet_type = rtc::PacketType::kIceConnectivityCheckResponse; SendTo(buf.Data(), buf.Length(), addr, options, false); @@ -1216,7 +1221,7 @@ int Connection::receiving_timeout() const { void Connection::OnSendStunPacket(const void* data, size_t size, StunRequest* req) { - rtc::PacketOptions options(port_->DefaultDscpValue()); + rtc::PacketOptions options(port_->StunDscpValue()); options.info_signaled_after_sent.packet_type = rtc::PacketType::kIceConnectivityCheck; auto err = diff --git a/p2p/base/port.h b/p2p/base/port.h index 151a4a3155..85711e41f5 100644 --- a/p2p/base/port.h +++ b/p2p/base/port.h @@ -435,11 +435,8 @@ class Port : public PortInterface, // Checks if the address in addr is compatible with the port's ip. bool IsCompatibleAddress(const rtc::SocketAddress& addr); - // Returns default DSCP value. - rtc::DiffServCodePoint DefaultDscpValue() const { - // No change from what MediaChannel set. - return rtc::DSCP_NO_CHANGE; - } + // Returns DSCP value packets generated by the port itself should use. + virtual rtc::DiffServCodePoint StunDscpValue() const; // Extra work to be done in subclasses when a connection is destroyed. virtual void HandleConnectionDestroyed(Connection* conn) {} diff --git a/p2p/base/relayport.cc b/p2p/base/relayport.cc index 7413f3b6e2..fb830ce66a 100644 --- a/p2p/base/relayport.cc +++ b/p2p/base/relayport.cc @@ -62,6 +62,7 @@ class RelayConnection : public sigslot::has_slots<> { rtc::AsyncPacketSocket* socket_; const ProtocolAddress* protocol_address_; StunRequestManager* request_manager_; + rtc::DiffServCodePoint dscp_; }; // Manages a number of connections to the relayserver, one for each @@ -407,7 +408,9 @@ void RelayPort::OnReadPacket(const char* data, RelayConnection::RelayConnection(const ProtocolAddress* protocol_address, rtc::AsyncPacketSocket* socket, rtc::Thread* thread) - : socket_(socket), protocol_address_(protocol_address) { + : socket_(socket), + protocol_address_(protocol_address), + dscp_(rtc::DSCP_NO_CHANGE) { request_manager_ = new StunRequestManager(thread); request_manager_->SignalSendPacket.connect(this, &RelayConnection::OnSendPacket); @@ -419,6 +422,9 @@ RelayConnection::~RelayConnection() { } int RelayConnection::SetSocketOption(rtc::Socket::Option opt, int value) { + if (opt == rtc::Socket::OPT_DSCP) { + dscp_ = static_cast(value); + } if (socket_) { return socket_->SetOption(opt, value); } @@ -432,8 +438,7 @@ bool RelayConnection::CheckResponse(StunMessage* msg) { void RelayConnection::OnSendPacket(const void* data, size_t size, StunRequest* req) { - // TODO(mallinath) Find a way to get DSCP value from Port. - rtc::PacketOptions options; // Default dscp set to NO_CHANGE. + rtc::PacketOptions options(dscp_); int sent = socket_->SendTo(data, size, GetAddress(), options); if (sent <= 0) { RTC_LOG(LS_VERBOSE) << "OnSendPacket: failed sending to " diff --git a/p2p/base/stunport.cc b/p2p/base/stunport.cc index c03653b344..c60bf92eb4 100644 --- a/p2p/base/stunport.cc +++ b/p2p/base/stunport.cc @@ -173,6 +173,7 @@ UDPPort::UDPPort(rtc::Thread* thread, error_(0), ready_(false), stun_keepalive_delay_(STUN_KEEPALIVE_INTERVAL), + dscp_(rtc::DSCP_NO_CHANGE), emit_local_for_anyaddress_(emit_local_for_anyaddress) { requests_.set_origin(origin); } @@ -199,6 +200,7 @@ UDPPort::UDPPort(rtc::Thread* thread, error_(0), ready_(false), stun_keepalive_delay_(STUN_KEEPALIVE_INTERVAL), + dscp_(rtc::DSCP_NO_CHANGE), emit_local_for_anyaddress_(emit_local_for_anyaddress) { requests_.set_origin(origin); } @@ -293,7 +295,15 @@ void UDPPort::UpdateNetworkCost() { stun_keepalive_lifetime_ = GetStunKeepaliveLifetime(); } +rtc::DiffServCodePoint UDPPort::StunDscpValue() const { + return dscp_; +} + int UDPPort::SetOption(rtc::Socket::Option opt, int value) { + if (opt == rtc::Socket::OPT_DSCP) { + // Save value for future packets we instantiate. + dscp_ = static_cast(value); + } return socket_->SetOption(opt, value); } @@ -534,7 +544,7 @@ void UDPPort::MaybeSetPortCompleteOrError() { // TODO(?): merge this with SendTo above. void UDPPort::OnSendPacket(const void* data, size_t size, StunRequest* req) { StunBindingRequest* sreq = static_cast(req); - rtc::PacketOptions options(DefaultDscpValue()); + rtc::PacketOptions options(StunDscpValue()); options.info_signaled_after_sent.packet_type = rtc::PacketType::kStunMessage; CopyPortInformationToPacketInfo(&options.info_signaled_after_sent); if (socket_->SendTo(data, size, sreq->server_addr(), options) < 0) { diff --git a/p2p/base/stunport.h b/p2p/base/stunport.h index 76647e8eda..5e397835db 100644 --- a/p2p/base/stunport.h +++ b/p2p/base/stunport.h @@ -152,6 +152,8 @@ class UDPPort : public Port { void UpdateNetworkCost() override; + rtc::DiffServCodePoint StunDscpValue() const override; + void OnLocalAddressReady(rtc::AsyncPacketSocket* socket, const rtc::SocketAddress& address); void OnReadPacket(rtc::AsyncPacketSocket* socket, @@ -247,6 +249,7 @@ class UDPPort : public Port { bool ready_; int stun_keepalive_delay_; int stun_keepalive_lifetime_ = INFINITE_LIFETIME; + rtc::DiffServCodePoint dscp_; StunStats stats_; diff --git a/p2p/base/stunport_unittest.cc b/p2p/base/stunport_unittest.cc index 2c18bd8d8f..29754e861c 100644 --- a/p2p/base/stunport_unittest.cc +++ b/p2p/base/stunport_unittest.cc @@ -18,9 +18,12 @@ #include "rtc_base/socketaddress.h" #include "rtc_base/ssladapter.h" #include "rtc_base/virtualsocketserver.h" +#include "test/gmock.h" using cricket::ServerAddresses; using rtc::SocketAddress; +using ::testing::_; +using ::testing::Return; static const SocketAddress kLocalAddr("127.0.0.1", 0); static const SocketAddress kStunAddr1("127.0.0.1", 5000); @@ -57,6 +60,7 @@ class StunPortTestBase : public testing::Test, public sigslot::has_slots<> { } cricket::UDPPort* port() const { return stun_port_.get(); } + rtc::AsyncPacketSocket* socket() const { return socket_.get(); } bool done() const { return done_; } bool error() const { return error_; } @@ -86,9 +90,14 @@ class StunPortTestBase : public testing::Test, public sigslot::has_slots<> { stun_port_->SignalPortError.connect(this, &StunPortTestBase::OnPortError); } - void CreateSharedUdpPort(const rtc::SocketAddress& server_addr) { - socket_.reset(socket_factory_.CreateUdpSocket( - rtc::SocketAddress(kLocalAddr.ipaddr(), 0), 0, 0)); + void CreateSharedUdpPort(const rtc::SocketAddress& server_addr, + rtc::AsyncPacketSocket* socket) { + if (socket) { + socket_.reset(socket); + } else { + socket_.reset(socket_factory_.CreateUdpSocket( + rtc::SocketAddress(kLocalAddr.ipaddr(), 0), 0, 0)); + } ASSERT_TRUE(socket_ != NULL); socket_->SignalReadPacket.connect(this, &StunPortTestBase::OnReadPacket); stun_port_.reset(cricket::UDPPort::Create( @@ -178,7 +187,7 @@ TEST_F(StunPortTest, TestCreateStunPort) { // Test that we can create a UDP port. TEST_F(StunPortTest, TestCreateUdpPort) { - CreateSharedUdpPort(kStunAddr1); + CreateSharedUdpPort(kStunAddr1, nullptr); EXPECT_EQ("local", port()->Type()); EXPECT_EQ(0U, port()->Candidates().size()); } @@ -245,7 +254,7 @@ TEST_F(StunPortTest, TestKeepAliveResponse) { // Test that a local candidate can be generated using a shared socket. TEST_F(StunPortTest, TestSharedSocketPrepareAddress) { - CreateSharedUdpPort(kStunAddr1); + CreateSharedUdpPort(kStunAddr1, nullptr); PrepareAddress(); EXPECT_TRUE_SIMULATED_WAIT(done(), kTimeoutMs, fake_clock); ASSERT_EQ(1U, port()->Candidates().size()); @@ -257,7 +266,7 @@ TEST_F(StunPortTest, TestSharedSocketPrepareAddress) { // resolved. TEST_F(StunPortTestWithRealClock, TestSharedSocketPrepareAddressInvalidHostname) { - CreateSharedUdpPort(kBadHostnameAddr); + CreateSharedUdpPort(kBadHostnameAddr, nullptr); PrepareAddress(); EXPECT_TRUE_WAIT(done(), kTimeoutMs); ASSERT_EQ(1U, port()->Candidates().size()); @@ -339,7 +348,7 @@ TEST_F(StunPortTest, TestStunPortGetStunKeepaliveLifetime) { // if the network type changes. TEST_F(StunPortTest, TestUdpPortGetStunKeepaliveLifetime) { // Lifetime for the default (unknown) network type is |kInfiniteLifetime|. - CreateSharedUdpPort(kStunAddr1); + CreateSharedUdpPort(kStunAddr1, nullptr); EXPECT_EQ(kInfiniteLifetime, port()->stun_keepalive_lifetime()); // Lifetime for the cellular network is |kHighCostPortKeepaliveLifetimeMs|. SetNetworkType(rtc::ADAPTER_TYPE_CELLULAR); @@ -348,7 +357,7 @@ TEST_F(StunPortTest, TestUdpPortGetStunKeepaliveLifetime) { // Lifetime for the wifi network type is |kInfiniteLifetime|. SetNetworkType(rtc::ADAPTER_TYPE_WIFI); - CreateSharedUdpPort(kStunAddr2); + CreateSharedUdpPort(kStunAddr2, nullptr); EXPECT_EQ(kInfiniteLifetime, port()->stun_keepalive_lifetime()); } @@ -375,3 +384,52 @@ TEST_F(StunPortTest, TestStunBindingRequestLongLifetime) { port()->HasPendingRequest(cricket::STUN_BINDING_REQUEST), 1000, fake_clock); } + +class MockAsyncPacketSocket : public rtc::AsyncPacketSocket { + public: + ~MockAsyncPacketSocket() = default; + + MOCK_CONST_METHOD0(GetLocalAddress, SocketAddress()); + MOCK_CONST_METHOD0(GetRemoteAddress, SocketAddress()); + MOCK_METHOD3(Send, + int(const void* pv, + size_t cb, + const rtc::PacketOptions& options)); + + MOCK_METHOD4(SendTo, + int(const void* pv, + size_t cb, + const SocketAddress& addr, + const rtc::PacketOptions& options)); + MOCK_METHOD0(Close, int()); + MOCK_CONST_METHOD0(GetState, State()); + MOCK_METHOD2(GetOption, int(rtc::Socket::Option opt, int* value)); + MOCK_METHOD2(SetOption, int(rtc::Socket::Option opt, int value)); + MOCK_CONST_METHOD0(GetError, int()); + MOCK_METHOD1(SetError, void(int error)); +}; + +// Test that outbound packets inherit the dscp value assigned to the socket. +TEST_F(StunPortTest, TestStunPacketsHaveDscpPacketOption) { + MockAsyncPacketSocket* socket = new MockAsyncPacketSocket(); + CreateSharedUdpPort(kStunAddr1, socket); + EXPECT_CALL(*socket, GetLocalAddress()).WillRepeatedly(Return(kLocalAddr)); + EXPECT_CALL(*socket, GetState()) + .WillRepeatedly(Return(rtc::AsyncPacketSocket::STATE_BOUND)); + EXPECT_CALL(*socket, SetOption(_, _)).WillRepeatedly(Return(0)); + + // If DSCP is not set on the socket, stun packets should have no value. + EXPECT_CALL(*socket, SendTo(_, _, _, + testing::Field(&rtc::PacketOptions::dscp, + testing::Eq(rtc::DSCP_NO_CHANGE)))) + .WillOnce(Return(100)); + PrepareAddress(); + + // Once it is set transport wide, they should inherit that value. + port()->SetOption(rtc::Socket::OPT_DSCP, rtc::DSCP_AF41); + EXPECT_CALL(*socket, SendTo(_, _, _, + testing::Field(&rtc::PacketOptions::dscp, + testing::Eq(rtc::DSCP_AF41)))) + .WillRepeatedly(Return(100)); + EXPECT_TRUE_SIMULATED_WAIT(done(), kTimeoutMs, fake_clock); +} diff --git a/p2p/base/turnport.cc b/p2p/base/turnport.cc index a6d25512b4..97541f60c0 100644 --- a/p2p/base/turnport.cc +++ b/p2p/base/turnport.cc @@ -210,6 +210,7 @@ TurnPort::TurnPort(rtc::Thread* thread, socket_(socket), resolver_(NULL), error_(0), + stun_dscp_value_(rtc::DSCP_NO_CHANGE), request_manager_(thread), next_channel_number_(TURN_CHANNEL_NUMBER_START), state_(STATE_CONNECTING), @@ -251,6 +252,7 @@ TurnPort::TurnPort(rtc::Thread* thread, socket_(NULL), resolver_(NULL), error_(0), + stun_dscp_value_(rtc::DSCP_NO_CHANGE), request_manager_(thread), next_channel_number_(TURN_CHANNEL_NUMBER_START), state_(STATE_CONNECTING), @@ -551,6 +553,10 @@ bool TurnPort::FailAndPruneConnection(const rtc::SocketAddress& address) { } int TurnPort::SetOption(rtc::Socket::Option opt, int value) { + // Remember the last requested DSCP value, for STUN traffic. + if (opt == rtc::Socket::OPT_DSCP) + stun_dscp_value_ = static_cast(value); + if (!socket_) { // If socket is not created yet, these options will be applied during socket // creation. @@ -795,7 +801,7 @@ void TurnPort::OnSendStunPacket(const void* data, size_t size, StunRequest* request) { RTC_DCHECK(connected()); - rtc::PacketOptions options(DefaultDscpValue()); + rtc::PacketOptions options(StunDscpValue()); options.info_signaled_after_sent.packet_type = rtc::PacketType::kTurnMessage; CopyPortInformationToPacketInfo(&options.info_signaled_after_sent); if (Send(data, size, options) < 0) { @@ -881,6 +887,10 @@ void TurnPort::Close() { SignalTurnPortClosed(this); } +rtc::DiffServCodePoint TurnPort::StunDscpValue() const { + return stun_dscp_value_; +} + void TurnPort::OnMessage(rtc::Message* message) { switch (message->message_id) { case MSG_ALLOCATE_ERROR: diff --git a/p2p/base/turnport.h b/p2p/base/turnport.h index 5955aafda1..11b58d4f6c 100644 --- a/p2p/base/turnport.h +++ b/p2p/base/turnport.h @@ -225,6 +225,8 @@ class TurnPort : public Port { bool CreateOrRefreshEntry(const rtc::SocketAddress& addr, int channel_number); + rtc::DiffServCodePoint StunDscpValue() const override; + private: enum { MSG_ALLOCATE_ERROR = MSG_FIRST_AVAILABLE, @@ -315,6 +317,7 @@ class TurnPort : public Port { SocketOptionsMap socket_options_; rtc::AsyncResolverInterface* resolver_; int error_; + rtc::DiffServCodePoint stun_dscp_value_; StunRequestManager request_manager_; std::string realm_; // From 401/438 response message.