Send and parse SCTP max-message-size in SDP
This also changes the default when no max-message-size is set to the protocol defined value of 64K, and prevents messages from being sent when they are too large to send. Bug: webrtc:10358 Change-Id: Iacc1dd774d1554d9f27315378fbea6351300b5cc Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/135948 Commit-Queue: Harald Alvestrand <hta@webrtc.org> Reviewed-by: Steve Anton <steveanton@webrtc.org> Cr-Commit-Position: refs/heads/master@{#27945}
This commit is contained in:
parent
e88eefc411
commit
fbb45bd02f
@ -46,9 +46,6 @@ namespace {
|
|||||||
// take off 80 bytes for DTLS/TURN/TCP/IP overhead.
|
// take off 80 bytes for DTLS/TURN/TCP/IP overhead.
|
||||||
static constexpr size_t kSctpMtu = 1200;
|
static constexpr size_t kSctpMtu = 1200;
|
||||||
|
|
||||||
// The size of the SCTP association send buffer. 256kB, the usrsctp default.
|
|
||||||
static constexpr int kSendBufferSize = 256 * 1024;
|
|
||||||
|
|
||||||
// Set the initial value of the static SCTP Data Engines reference count.
|
// Set the initial value of the static SCTP Data Engines reference count.
|
||||||
int g_usrsctp_usage_count = 0;
|
int g_usrsctp_usage_count = 0;
|
||||||
rtc::GlobalLockPod g_usrsctp_lock_;
|
rtc::GlobalLockPod g_usrsctp_lock_;
|
||||||
@ -185,7 +182,7 @@ class SctpTransport::UsrSctpWrapper {
|
|||||||
// This is harmless, but we should find out when the library default
|
// This is harmless, but we should find out when the library default
|
||||||
// changes.
|
// changes.
|
||||||
int send_size = usrsctp_sysctl_get_sctp_sendspace();
|
int send_size = usrsctp_sysctl_get_sctp_sendspace();
|
||||||
if (send_size != kSendBufferSize) {
|
if (send_size != kSctpSendBufferSize) {
|
||||||
RTC_LOG(LS_ERROR) << "Got different send size than expected: "
|
RTC_LOG(LS_ERROR) << "Got different send size than expected: "
|
||||||
<< send_size;
|
<< send_size;
|
||||||
}
|
}
|
||||||
@ -327,7 +324,7 @@ class SctpTransport::UsrSctpWrapper {
|
|||||||
// callback. Larger messages (originating from other implementations) will
|
// callback. Larger messages (originating from other implementations) will
|
||||||
// still be delivered in chunks.
|
// still be delivered in chunks.
|
||||||
if (!(flags & MSG_EOR) &&
|
if (!(flags & MSG_EOR) &&
|
||||||
(transport->partial_message_.size() < kSendBufferSize)) {
|
(transport->partial_message_.size() < kSctpSendBufferSize)) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -410,7 +407,9 @@ void SctpTransport::SetDtlsTransport(rtc::PacketTransportInternal* transport) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SctpTransport::Start(int local_sctp_port, int remote_sctp_port) {
|
bool SctpTransport::Start(int local_sctp_port,
|
||||||
|
int remote_sctp_port,
|
||||||
|
int max_message_size) {
|
||||||
RTC_DCHECK_RUN_ON(network_thread_);
|
RTC_DCHECK_RUN_ON(network_thread_);
|
||||||
if (local_sctp_port == -1) {
|
if (local_sctp_port == -1) {
|
||||||
local_sctp_port = kSctpDefaultPort;
|
local_sctp_port = kSctpDefaultPort;
|
||||||
@ -418,6 +417,20 @@ bool SctpTransport::Start(int local_sctp_port, int remote_sctp_port) {
|
|||||||
if (remote_sctp_port == -1) {
|
if (remote_sctp_port == -1) {
|
||||||
remote_sctp_port = kSctpDefaultPort;
|
remote_sctp_port = kSctpDefaultPort;
|
||||||
}
|
}
|
||||||
|
if (max_message_size > kSctpSendBufferSize) {
|
||||||
|
RTC_LOG(LS_ERROR) << "Max message size of " << max_message_size
|
||||||
|
<< " is larger than send bufffer size "
|
||||||
|
<< kSctpSendBufferSize;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (max_message_size < 1) {
|
||||||
|
RTC_LOG(LS_ERROR) << "Max message size of " << max_message_size
|
||||||
|
<< " is too small";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// We allow changing max_message_size with a second Start() call,
|
||||||
|
// but not changing the port numbers.
|
||||||
|
max_message_size_ = max_message_size;
|
||||||
if (started_) {
|
if (started_) {
|
||||||
if (local_sctp_port != local_port_ || remote_sctp_port != remote_port_) {
|
if (local_sctp_port != local_port_ || remote_sctp_port != remote_port_) {
|
||||||
RTC_LOG(LS_ERROR)
|
RTC_LOG(LS_ERROR)
|
||||||
@ -537,6 +550,11 @@ bool SctpTransport::SendData(const SendDataParams& params,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (payload.size() > static_cast<size_t>(max_message_size_)) {
|
||||||
|
RTC_LOG(LS_ERROR) << "Attempting to send message of size " << payload.size()
|
||||||
|
<< " which is larger than limit " << max_message_size_;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
// We don't fragment.
|
// We don't fragment.
|
||||||
send_res = usrsctp_sendv(
|
send_res = usrsctp_sendv(
|
||||||
sock_, payload.data(), static_cast<size_t>(payload.size()), NULL, 0, &spa,
|
sock_, payload.data(), static_cast<size_t>(payload.size()), NULL, 0, &spa,
|
||||||
@ -657,9 +675,9 @@ bool SctpTransport::OpenSctpSocket() {
|
|||||||
|
|
||||||
UsrSctpWrapper::IncrementUsrSctpUsageCount();
|
UsrSctpWrapper::IncrementUsrSctpUsageCount();
|
||||||
|
|
||||||
// If kSendBufferSize isn't reflective of reality, we log an error, but we
|
// If kSctpSendBufferSize isn't reflective of reality, we log an error, but we
|
||||||
// still have to do something reasonable here. Look up what the buffer's
|
// still have to do something reasonable here. Look up what the buffer's real
|
||||||
// real size is and set our threshold to something reasonable.
|
// size is and set our threshold to something reasonable.
|
||||||
static const int kSendThreshold = usrsctp_sysctl_get_sctp_sendspace() / 2;
|
static const int kSendThreshold = usrsctp_sysctl_get_sctp_sendspace() / 2;
|
||||||
|
|
||||||
sock_ = usrsctp_socket(
|
sock_ = usrsctp_socket(
|
||||||
|
|||||||
@ -72,13 +72,14 @@ class SctpTransport : public SctpTransportInternal,
|
|||||||
|
|
||||||
// SctpTransportInternal overrides (see sctptransportinternal.h for comments).
|
// SctpTransportInternal overrides (see sctptransportinternal.h for comments).
|
||||||
void SetDtlsTransport(rtc::PacketTransportInternal* transport) override;
|
void SetDtlsTransport(rtc::PacketTransportInternal* transport) override;
|
||||||
bool Start(int local_port, int remote_port) override;
|
bool Start(int local_port, int remote_port, int max_message_size) override;
|
||||||
bool OpenStream(int sid) override;
|
bool OpenStream(int sid) override;
|
||||||
bool ResetStream(int sid) override;
|
bool ResetStream(int sid) override;
|
||||||
bool SendData(const SendDataParams& params,
|
bool SendData(const SendDataParams& params,
|
||||||
const rtc::CopyOnWriteBuffer& payload,
|
const rtc::CopyOnWriteBuffer& payload,
|
||||||
SendDataResult* result = nullptr) override;
|
SendDataResult* result = nullptr) override;
|
||||||
bool ReadyToSendData() override;
|
bool ReadyToSendData() override;
|
||||||
|
int max_message_size() const override { return max_message_size_; }
|
||||||
void set_debug_name_for_testing(const char* debug_name) override {
|
void set_debug_name_for_testing(const char* debug_name) override {
|
||||||
debug_name_ = debug_name;
|
debug_name_ = debug_name;
|
||||||
}
|
}
|
||||||
@ -151,6 +152,7 @@ class SctpTransport : public SctpTransportInternal,
|
|||||||
bool was_ever_writable_ = false;
|
bool was_ever_writable_ = false;
|
||||||
int local_port_ = kSctpDefaultPort;
|
int local_port_ = kSctpDefaultPort;
|
||||||
int remote_port_ = kSctpDefaultPort;
|
int remote_port_ = kSctpDefaultPort;
|
||||||
|
int max_message_size_ = kSctpSendBufferSize;
|
||||||
struct socket* sock_ = nullptr; // The socket created by usrsctp_socket(...).
|
struct socket* sock_ = nullptr; // The socket created by usrsctp_socket(...).
|
||||||
|
|
||||||
// Has Start been called? Don't create SCTP socket until it has.
|
// Has Start been called? Don't create SCTP socket until it has.
|
||||||
|
|||||||
@ -28,6 +28,10 @@
|
|||||||
|
|
||||||
namespace cricket {
|
namespace cricket {
|
||||||
|
|
||||||
|
// Constants that are important to API users
|
||||||
|
// The size of the SCTP association send buffer. 256kB, the usrsctp default.
|
||||||
|
constexpr int kSctpSendBufferSize = 256 * 1024;
|
||||||
|
|
||||||
// The number of outgoing streams that we'll negotiate. Since stream IDs (SIDs)
|
// The number of outgoing streams that we'll negotiate. Since stream IDs (SIDs)
|
||||||
// are 0-based, the highest usable SID is 1023.
|
// are 0-based, the highest usable SID is 1023.
|
||||||
//
|
//
|
||||||
@ -67,13 +71,16 @@ class SctpTransportInternal {
|
|||||||
// listener and connector must be using the same port. They are not related
|
// listener and connector must be using the same port. They are not related
|
||||||
// to the ports at the IP level. If set to -1, we default to
|
// to the ports at the IP level. If set to -1, we default to
|
||||||
// kSctpDefaultPort.
|
// kSctpDefaultPort.
|
||||||
|
// |max_message_size_| sets the max message size on the connection.
|
||||||
|
// It must be smaller than or equal to kSctpSendBufferSize.
|
||||||
|
// It can be changed by a secons Start() call.
|
||||||
//
|
//
|
||||||
// TODO(deadbeef): Add remote max message size as parameter to Start, once we
|
|
||||||
// start supporting it.
|
|
||||||
// TODO(deadbeef): Support calling Start with different local/remote ports
|
// TODO(deadbeef): Support calling Start with different local/remote ports
|
||||||
// and create a new association? Not clear if this is something we need to
|
// and create a new association? Not clear if this is something we need to
|
||||||
// support though. See: https://github.com/w3c/webrtc-pc/issues/979
|
// support though. See: https://github.com/w3c/webrtc-pc/issues/979
|
||||||
virtual bool Start(int local_sctp_port, int remote_sctp_port) = 0;
|
virtual bool Start(int local_sctp_port,
|
||||||
|
int remote_sctp_port,
|
||||||
|
int max_message_size) = 0;
|
||||||
|
|
||||||
// NOTE: Initially there was a "Stop" method here, but it was never used, so
|
// NOTE: Initially there was a "Stop" method here, but it was never used, so
|
||||||
// it was removed.
|
// it was removed.
|
||||||
@ -105,6 +112,8 @@ class SctpTransportInternal {
|
|||||||
// ICE channels may be unwritable while ReadyToSendData is true, because data
|
// ICE channels may be unwritable while ReadyToSendData is true, because data
|
||||||
// can still be queued in usrsctp.
|
// can still be queued in usrsctp.
|
||||||
virtual bool ReadyToSendData() = 0;
|
virtual bool ReadyToSendData() = 0;
|
||||||
|
// Returns the current max message size, set with Start().
|
||||||
|
virtual int max_message_size() const = 0;
|
||||||
|
|
||||||
sigslot::signal0<> SignalReadyToSendData;
|
sigslot::signal0<> SignalReadyToSendData;
|
||||||
// ReceiveDataParams includes SID, seq num, timestamp, etc. CopyOnWriteBuffer
|
// ReceiveDataParams includes SID, seq num, timestamp, etc. CopyOnWriteBuffer
|
||||||
|
|||||||
@ -151,8 +151,8 @@ class SctpTransportTest : public ::testing::Test, public sigslot::has_slots<> {
|
|||||||
<< "Connect the transports -----------------------------";
|
<< "Connect the transports -----------------------------";
|
||||||
// Both transports need to have started (with matching ports) for an
|
// Both transports need to have started (with matching ports) for an
|
||||||
// association to be formed.
|
// association to be formed.
|
||||||
transport1_->Start(port1, port2);
|
transport1_->Start(port1, port2, kSctpSendBufferSize);
|
||||||
transport2_->Start(port2, port1);
|
transport2_->Start(port2, port1, kSctpSendBufferSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AddStream(int sid) {
|
bool AddStream(int sid) {
|
||||||
@ -251,8 +251,8 @@ TEST_F(SctpTransportTest, SwitchDtlsTransport) {
|
|||||||
transport2->OpenStream(1);
|
transport2->OpenStream(1);
|
||||||
|
|
||||||
// Tell them both to start (though transport1_ is connected to black_hole).
|
// Tell them both to start (though transport1_ is connected to black_hole).
|
||||||
transport1->Start(kTransport1Port, kTransport2Port);
|
transport1->Start(kTransport1Port, kTransport2Port, kSctpSendBufferSize);
|
||||||
transport2->Start(kTransport2Port, kTransport1Port);
|
transport2->Start(kTransport2Port, kTransport1Port, kSctpSendBufferSize);
|
||||||
|
|
||||||
// Switch transport1_ to the normal fake_dtls1_ transport.
|
// Switch transport1_ to the normal fake_dtls1_ transport.
|
||||||
transport1->SetDtlsTransport(&fake_dtls1);
|
transport1->SetDtlsTransport(&fake_dtls1);
|
||||||
@ -276,7 +276,8 @@ TEST_F(SctpTransportTest, SwitchDtlsTransport) {
|
|||||||
// Calling Start twice shouldn't do anything bad, if with the same parameters.
|
// Calling Start twice shouldn't do anything bad, if with the same parameters.
|
||||||
TEST_F(SctpTransportTest, DuplicateStartCallsIgnored) {
|
TEST_F(SctpTransportTest, DuplicateStartCallsIgnored) {
|
||||||
SetupConnectedTransportsWithTwoStreams();
|
SetupConnectedTransportsWithTwoStreams();
|
||||||
EXPECT_TRUE(transport1()->Start(kTransport1Port, kTransport2Port));
|
EXPECT_TRUE(transport1()->Start(kTransport1Port, kTransport2Port,
|
||||||
|
kSctpSendBufferSize));
|
||||||
|
|
||||||
// Make sure we can still send/recv data.
|
// Make sure we can still send/recv data.
|
||||||
SendDataResult result;
|
SendDataResult result;
|
||||||
@ -289,8 +290,8 @@ TEST_F(SctpTransportTest, DuplicateStartCallsIgnored) {
|
|||||||
// Calling Start a second time with a different port should fail.
|
// Calling Start a second time with a different port should fail.
|
||||||
TEST_F(SctpTransportTest, CallingStartWithDifferentPortFails) {
|
TEST_F(SctpTransportTest, CallingStartWithDifferentPortFails) {
|
||||||
SetupConnectedTransportsWithTwoStreams();
|
SetupConnectedTransportsWithTwoStreams();
|
||||||
EXPECT_FALSE(transport1()->Start(kTransport1Port, 1234));
|
EXPECT_FALSE(transport1()->Start(kTransport1Port, 1234, kSctpSendBufferSize));
|
||||||
EXPECT_FALSE(transport1()->Start(1234, kTransport2Port));
|
EXPECT_FALSE(transport1()->Start(1234, kTransport2Port, kSctpSendBufferSize));
|
||||||
}
|
}
|
||||||
|
|
||||||
// A value of -1 for the local/remote port should be treated as the default
|
// A value of -1 for the local/remote port should be treated as the default
|
||||||
@ -311,8 +312,8 @@ TEST_F(SctpTransportTest, NegativeOnePortTreatedAsDefault) {
|
|||||||
|
|
||||||
// Tell them both to start, giving one transport the default port and the
|
// Tell them both to start, giving one transport the default port and the
|
||||||
// other transport -1.
|
// other transport -1.
|
||||||
transport1->Start(kSctpDefaultPort, kSctpDefaultPort);
|
transport1->Start(kSctpDefaultPort, kSctpDefaultPort, kSctpSendBufferSize);
|
||||||
transport2->Start(-1, -1);
|
transport2->Start(-1, -1, kSctpSendBufferSize);
|
||||||
|
|
||||||
// Connect the two fake DTLS transports.
|
// Connect the two fake DTLS transports.
|
||||||
bool asymmetric = false;
|
bool asymmetric = false;
|
||||||
@ -351,7 +352,7 @@ TEST_F(SctpTransportTest, SignalReadyToSendDataAfterDtlsWritable) {
|
|||||||
std::unique_ptr<SctpTransport> transport(CreateTransport(&fake_dtls, &recv));
|
std::unique_ptr<SctpTransport> transport(CreateTransport(&fake_dtls, &recv));
|
||||||
SctpTransportObserver observer(transport.get());
|
SctpTransportObserver observer(transport.get());
|
||||||
|
|
||||||
transport->Start(kSctpDefaultPort, kSctpDefaultPort);
|
transport->Start(kSctpDefaultPort, kSctpDefaultPort, kSctpSendBufferSize);
|
||||||
fake_dtls.SetWritable(true);
|
fake_dtls.SetWritable(true);
|
||||||
EXPECT_TRUE_WAIT(observer.ReadyToSend(), kDefaultTimeout);
|
EXPECT_TRUE_WAIT(observer.ReadyToSend(), kDefaultTimeout);
|
||||||
}
|
}
|
||||||
@ -564,4 +565,31 @@ TEST_F(SctpTransportTest, ReusesAStream) {
|
|||||||
EXPECT_EQ_WAIT(2, transport2_observer.StreamCloseCount(1), kDefaultTimeout);
|
EXPECT_EQ_WAIT(2, transport2_observer.StreamCloseCount(1), kDefaultTimeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(SctpTransportTest, RejectsTooLargeMessageSize) {
|
||||||
|
FakeDtlsTransport fake_dtls("fake dtls", 0);
|
||||||
|
SctpFakeDataReceiver recv;
|
||||||
|
std::unique_ptr<SctpTransport> transport(CreateTransport(&fake_dtls, &recv));
|
||||||
|
|
||||||
|
EXPECT_FALSE(transport->Start(kSctpDefaultPort, kSctpDefaultPort,
|
||||||
|
kSctpSendBufferSize + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(SctpTransportTest, RejectsTooSmallMessageSize) {
|
||||||
|
FakeDtlsTransport fake_dtls("fake dtls", 0);
|
||||||
|
SctpFakeDataReceiver recv;
|
||||||
|
std::unique_ptr<SctpTransport> transport(CreateTransport(&fake_dtls, &recv));
|
||||||
|
|
||||||
|
EXPECT_FALSE(transport->Start(kSctpDefaultPort, kSctpDefaultPort, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(SctpTransportTest, RejectsSendTooLargeMessages) {
|
||||||
|
SetupConnectedTransportsWithTwoStreams();
|
||||||
|
// Use "Start" to reduce the max message size
|
||||||
|
transport1()->Start(kTransport1Port, kTransport2Port, 10);
|
||||||
|
EXPECT_EQ(10, transport1()->max_message_size());
|
||||||
|
const char eleven_characters[] = "12345678901";
|
||||||
|
SendDataResult result;
|
||||||
|
EXPECT_FALSE(SendData(transport1(), 1, eleven_characters, &result));
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace cricket
|
} // namespace cricket
|
||||||
|
|||||||
@ -25,6 +25,7 @@
|
|||||||
#include "api/crypto_params.h"
|
#include "api/crypto_params.h"
|
||||||
#include "media/base/h264_profile_level_id.h"
|
#include "media/base/h264_profile_level_id.h"
|
||||||
#include "media/base/media_constants.h"
|
#include "media/base/media_constants.h"
|
||||||
|
#include "media/sctp/sctp_transport_internal.h"
|
||||||
#include "p2p/base/p2p_constants.h"
|
#include "p2p/base/p2p_constants.h"
|
||||||
#include "pc/channel_manager.h"
|
#include "pc/channel_manager.h"
|
||||||
#include "pc/media_protocol_names.h"
|
#include "pc/media_protocol_names.h"
|
||||||
@ -2238,6 +2239,8 @@ bool MediaSessionDescriptionFactory::AddSctpDataContentForOffer(
|
|||||||
data->set_protocol(secure_transport ? kMediaProtocolUdpDtlsSctp
|
data->set_protocol(secure_transport ? kMediaProtocolUdpDtlsSctp
|
||||||
: kMediaProtocolSctp);
|
: kMediaProtocolSctp);
|
||||||
data->set_use_sctpmap(session_options.use_obsolete_sctp_sdp);
|
data->set_use_sctpmap(session_options.use_obsolete_sctp_sdp);
|
||||||
|
data->set_max_message_size(kSctpSendBufferSize);
|
||||||
|
|
||||||
if (!CreateContentOffer(media_description_options, session_options,
|
if (!CreateContentOffer(media_description_options, session_options,
|
||||||
sdes_policy, GetCryptos(current_content),
|
sdes_policy, GetCryptos(current_content),
|
||||||
crypto_suites, RtpHeaderExtensions(), ssrc_generator_,
|
crypto_suites, RtpHeaderExtensions(), ssrc_generator_,
|
||||||
@ -2579,6 +2582,10 @@ bool MediaSessionDescriptionFactory::AddDataContentForAnswer(
|
|||||||
offer_content->media_description()->as_sctp();
|
offer_content->media_description()->as_sctp();
|
||||||
// Respond with the offerer's proto, whatever it is.
|
// Respond with the offerer's proto, whatever it is.
|
||||||
data_answer->as_sctp()->set_protocol(offer_data_description->protocol());
|
data_answer->as_sctp()->set_protocol(offer_data_description->protocol());
|
||||||
|
// Respond with our max message size or the remote max messsage size,
|
||||||
|
// whichever is smaller.
|
||||||
|
data_answer->as_sctp()->set_max_message_size(std::min(
|
||||||
|
offer_data_description->max_message_size(), kSctpSendBufferSize));
|
||||||
if (!CreateMediaContentAnswer(
|
if (!CreateMediaContentAnswer(
|
||||||
offer_data_description, media_description_options, session_options,
|
offer_data_description, media_description_options, session_options,
|
||||||
sdes_policy, GetCryptos(current_content), RtpHeaderExtensions(),
|
sdes_policy, GetCryptos(current_content), RtpHeaderExtensions(),
|
||||||
|
|||||||
@ -556,18 +556,6 @@ bool VerifyIceUfragPwdPresent(const SessionDescription* desc) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the SCTP port out of a SessionDescription.
|
|
||||||
// Return -1 if not found.
|
|
||||||
int GetSctpPort(const SessionDescription* session_description) {
|
|
||||||
const cricket::SctpDataContentDescription* data_desc =
|
|
||||||
GetFirstSctpDataContentDescription(session_description);
|
|
||||||
RTC_DCHECK(data_desc);
|
|
||||||
if (!data_desc) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return data_desc->port();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns true if |new_desc| requests an ICE restart (i.e., new ufrag/pwd).
|
// Returns true if |new_desc| requests an ICE restart (i.e., new ufrag/pwd).
|
||||||
bool CheckForRemoteIceRestart(const SessionDescriptionInterface* old_desc,
|
bool CheckForRemoteIceRestart(const SessionDescriptionInterface* old_desc,
|
||||||
const SessionDescriptionInterface* new_desc,
|
const SessionDescriptionInterface* new_desc,
|
||||||
@ -5663,30 +5651,39 @@ RTCError PeerConnection::PushdownMediaDescription(
|
|||||||
|
|
||||||
// Need complete offer/answer with an SCTP m= section before starting SCTP,
|
// Need complete offer/answer with an SCTP m= section before starting SCTP,
|
||||||
// according to https://tools.ietf.org/html/draft-ietf-mmusic-sctp-sdp-19
|
// according to https://tools.ietf.org/html/draft-ietf-mmusic-sctp-sdp-19
|
||||||
if (sctp_transport_ && local_description() && remote_description() &&
|
if (sctp_transport_ && local_description() && remote_description()) {
|
||||||
cricket::GetFirstDataContent(local_description()->description()) &&
|
auto local_sctp_description = cricket::GetFirstSctpDataContentDescription(
|
||||||
cricket::GetFirstDataContent(remote_description()->description())) {
|
local_description()->description());
|
||||||
|
auto remote_sctp_description = cricket::GetFirstSctpDataContentDescription(
|
||||||
|
remote_description()->description());
|
||||||
|
if (local_sctp_description && remote_sctp_description) {
|
||||||
|
int max_message_size =
|
||||||
|
std::min(local_sctp_description->max_message_size(),
|
||||||
|
remote_sctp_description->max_message_size());
|
||||||
bool success = network_thread()->Invoke<bool>(
|
bool success = network_thread()->Invoke<bool>(
|
||||||
RTC_FROM_HERE,
|
RTC_FROM_HERE,
|
||||||
rtc::Bind(&PeerConnection::PushdownSctpParameters_n, this, source,
|
rtc::Bind(&PeerConnection::PushdownSctpParameters_n, this, source,
|
||||||
GetSctpPort(local_description()->description()),
|
local_sctp_description->port(),
|
||||||
GetSctpPort(remote_description()->description())));
|
remote_sctp_description->port(), max_message_size));
|
||||||
if (!success) {
|
if (!success) {
|
||||||
LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR,
|
LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR,
|
||||||
"Failed to push down SCTP parameters.");
|
"Failed to push down SCTP parameters.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return RTCError::OK();
|
return RTCError::OK();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PeerConnection::PushdownSctpParameters_n(cricket::ContentSource source,
|
bool PeerConnection::PushdownSctpParameters_n(cricket::ContentSource source,
|
||||||
int local_sctp_port,
|
int local_sctp_port,
|
||||||
int remote_sctp_port) {
|
int remote_sctp_port,
|
||||||
|
int max_message_size) {
|
||||||
RTC_DCHECK_RUN_ON(network_thread());
|
RTC_DCHECK_RUN_ON(network_thread());
|
||||||
// Apply the SCTP port (which is hidden inside a DataCodec structure...)
|
// Apply the SCTP port (which is hidden inside a DataCodec structure...)
|
||||||
// When we support "max-message-size", that would also be pushed down here.
|
// When we support "max-message-size", that would also be pushed down here.
|
||||||
return cricket_sctp_transport()->Start(local_sctp_port, remote_sctp_port);
|
return cricket_sctp_transport()->Start(local_sctp_port, remote_sctp_port,
|
||||||
|
max_message_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
RTCError PeerConnection::PushdownTransportDescription(
|
RTCError PeerConnection::PushdownTransportDescription(
|
||||||
|
|||||||
@ -879,7 +879,8 @@ class PeerConnection : public PeerConnectionInternal,
|
|||||||
RTC_RUN_ON(signaling_thread());
|
RTC_RUN_ON(signaling_thread());
|
||||||
bool PushdownSctpParameters_n(cricket::ContentSource source,
|
bool PushdownSctpParameters_n(cricket::ContentSource source,
|
||||||
int local_sctp_port,
|
int local_sctp_port,
|
||||||
int remote_sctp_port);
|
int remote_sctp_port,
|
||||||
|
int max_message_size);
|
||||||
|
|
||||||
RTCError PushdownTransportDescription(cricket::ContentSource source,
|
RTCError PushdownTransportDescription(cricket::ContentSource source,
|
||||||
SdpType type);
|
SdpType type);
|
||||||
|
|||||||
@ -105,8 +105,14 @@ void SctpTransport::UpdateInformation(SctpTransportState state) {
|
|||||||
must_send_update = (state != info_.state());
|
must_send_update = (state != info_.state());
|
||||||
// TODO(https://bugs.webrtc.org/10358): Update max message size and
|
// TODO(https://bugs.webrtc.org/10358): Update max message size and
|
||||||
// max channels from internal SCTP transport when available.
|
// max channels from internal SCTP transport when available.
|
||||||
|
if (internal_sctp_transport_) {
|
||||||
|
info_ = SctpTransportInformation(
|
||||||
|
state, dtls_transport_, internal_sctp_transport_->max_message_size(),
|
||||||
|
info_.MaxChannels());
|
||||||
|
} else {
|
||||||
info_ = SctpTransportInformation(
|
info_ = SctpTransportInformation(
|
||||||
state, dtls_transport_, info_.MaxMessageSize(), info_.MaxChannels());
|
state, dtls_transport_, info_.MaxMessageSize(), info_.MaxChannels());
|
||||||
|
}
|
||||||
if (observer_ && must_send_update) {
|
if (observer_ && must_send_update) {
|
||||||
info_copy = info_;
|
info_copy = info_;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -32,7 +32,9 @@ namespace {
|
|||||||
class FakeCricketSctpTransport : public cricket::SctpTransportInternal {
|
class FakeCricketSctpTransport : public cricket::SctpTransportInternal {
|
||||||
public:
|
public:
|
||||||
void SetDtlsTransport(rtc::PacketTransportInternal* transport) override {}
|
void SetDtlsTransport(rtc::PacketTransportInternal* transport) override {}
|
||||||
bool Start(int local_port, int remote_port) override { return true; }
|
bool Start(int local_port, int remote_port, int max_message_size) override {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
bool OpenStream(int sid) override { return true; }
|
bool OpenStream(int sid) override { return true; }
|
||||||
bool ResetStream(int sid) override { return true; }
|
bool ResetStream(int sid) override { return true; }
|
||||||
bool SendData(const cricket::SendDataParams& params,
|
bool SendData(const cricket::SendDataParams& params,
|
||||||
@ -42,6 +44,7 @@ class FakeCricketSctpTransport : public cricket::SctpTransportInternal {
|
|||||||
}
|
}
|
||||||
bool ReadyToSendData() override { return true; }
|
bool ReadyToSendData() override { return true; }
|
||||||
void set_debug_name_for_testing(const char* debug_name) override {}
|
void set_debug_name_for_testing(const char* debug_name) override {}
|
||||||
|
int max_message_size() const override { return 0; }
|
||||||
// Methods exposed for testing
|
// Methods exposed for testing
|
||||||
void SendSignalReadyToSendData() { SignalReadyToSendData(); }
|
void SendSignalReadyToSendData() { SignalReadyToSendData(); }
|
||||||
|
|
||||||
|
|||||||
@ -498,7 +498,8 @@ class SctpDataContentDescription : public MediaContentDescription {
|
|||||||
bool use_sctpmap_ = true; // Note: "true" is no longer conformant.
|
bool use_sctpmap_ = true; // Note: "true" is no longer conformant.
|
||||||
// Defaults should be constants imported from SCTP. Quick hack.
|
// Defaults should be constants imported from SCTP. Quick hack.
|
||||||
int port_ = 5000;
|
int port_ = 5000;
|
||||||
int max_message_size_ = 256 * 1024;
|
// draft-ietf-mmusic-sdp-sctp-23: Max message size default is 64K
|
||||||
|
int max_message_size_ = 64 * 1024;
|
||||||
std::unique_ptr<DataContentDescription> shim_;
|
std::unique_ptr<DataContentDescription> shim_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -21,9 +21,10 @@
|
|||||||
class FakeSctpTransport : public cricket::SctpTransportInternal {
|
class FakeSctpTransport : public cricket::SctpTransportInternal {
|
||||||
public:
|
public:
|
||||||
void SetDtlsTransport(rtc::PacketTransportInternal* transport) override {}
|
void SetDtlsTransport(rtc::PacketTransportInternal* transport) override {}
|
||||||
bool Start(int local_port, int remote_port) override {
|
bool Start(int local_port, int remote_port, int max_message_size) override {
|
||||||
local_port_.emplace(local_port);
|
local_port_.emplace(local_port);
|
||||||
remote_port_.emplace(remote_port);
|
remote_port_.emplace(remote_port);
|
||||||
|
max_message_size_ = max_message_size;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool OpenStream(int sid) override { return true; }
|
bool OpenStream(int sid) override { return true; }
|
||||||
@ -36,12 +37,14 @@ class FakeSctpTransport : public cricket::SctpTransportInternal {
|
|||||||
bool ReadyToSendData() override { return true; }
|
bool ReadyToSendData() override { return true; }
|
||||||
void set_debug_name_for_testing(const char* debug_name) override {}
|
void set_debug_name_for_testing(const char* debug_name) override {}
|
||||||
|
|
||||||
|
int max_message_size() const { return max_message_size_; }
|
||||||
int local_port() const { return *local_port_; }
|
int local_port() const { return *local_port_; }
|
||||||
int remote_port() const { return *remote_port_; }
|
int remote_port() const { return *remote_port_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
absl::optional<int> local_port_;
|
absl::optional<int> local_port_;
|
||||||
absl::optional<int> remote_port_;
|
absl::optional<int> remote_port_;
|
||||||
|
int max_message_size_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class FakeSctpTransportFactory : public cricket::SctpTransportInternalFactory {
|
class FakeSctpTransportFactory : public cricket::SctpTransportInternalFactory {
|
||||||
|
|||||||
@ -172,6 +172,7 @@ static const char kAttributeInactive[] = "inactive";
|
|||||||
// a=sctp-port, a=max-message-size
|
// a=sctp-port, a=max-message-size
|
||||||
static const char kAttributeSctpPort[] = "sctp-port";
|
static const char kAttributeSctpPort[] = "sctp-port";
|
||||||
static const char kAttributeMaxMessageSize[] = "max-message-size";
|
static const char kAttributeMaxMessageSize[] = "max-message-size";
|
||||||
|
static const int kDefaultSctpMaxMessageSize = 65536;
|
||||||
// draft-ietf-mmusic-sdp-simulcast-13
|
// draft-ietf-mmusic-sdp-simulcast-13
|
||||||
// a=simulcast
|
// a=simulcast
|
||||||
static const char kAttributeSimulcast[] = "simulcast";
|
static const char kAttributeSimulcast[] = "simulcast";
|
||||||
@ -272,9 +273,6 @@ static void BuildMediaDescription(const ContentInfo* content_info,
|
|||||||
const std::vector<Candidate>& candidates,
|
const std::vector<Candidate>& candidates,
|
||||||
int msid_signaling,
|
int msid_signaling,
|
||||||
std::string* message);
|
std::string* message);
|
||||||
static void BuildSctpContentAttributes(std::string* message,
|
|
||||||
int sctp_port,
|
|
||||||
bool use_sctpmap);
|
|
||||||
static void BuildRtpContentAttributes(const MediaContentDescription* media_desc,
|
static void BuildRtpContentAttributes(const MediaContentDescription* media_desc,
|
||||||
const cricket::MediaType media_type,
|
const cricket::MediaType media_type,
|
||||||
int msid_signaling,
|
int msid_signaling,
|
||||||
@ -1323,6 +1321,33 @@ bool ParseExtmap(const std::string& line,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void BuildSctpContentAttributes(
|
||||||
|
std::string* message,
|
||||||
|
const cricket::SctpDataContentDescription* data_desc) {
|
||||||
|
rtc::StringBuilder os;
|
||||||
|
if (data_desc->use_sctpmap()) {
|
||||||
|
// draft-ietf-mmusic-sctp-sdp-04
|
||||||
|
// a=sctpmap:sctpmap-number protocol [streams]
|
||||||
|
rtc::StringBuilder os;
|
||||||
|
InitAttrLine(kAttributeSctpmap, &os);
|
||||||
|
os << kSdpDelimiterColon << data_desc->port() << kSdpDelimiterSpace
|
||||||
|
<< kDefaultSctpmapProtocol << kSdpDelimiterSpace
|
||||||
|
<< cricket::kMaxSctpStreams;
|
||||||
|
AddLine(os.str(), message);
|
||||||
|
} else {
|
||||||
|
// draft-ietf-mmusic-sctp-sdp-23
|
||||||
|
// a=sctp-port:<port>
|
||||||
|
InitAttrLine(kAttributeSctpPort, &os);
|
||||||
|
os << kSdpDelimiterColon << data_desc->port();
|
||||||
|
AddLine(os.str(), message);
|
||||||
|
if (data_desc->max_message_size() != kDefaultSctpMaxMessageSize) {
|
||||||
|
InitAttrLine(kAttributeMaxMessageSize, &os);
|
||||||
|
os << kSdpDelimiterColon << data_desc->max_message_size();
|
||||||
|
AddLine(os.str(), message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void BuildMediaDescription(const ContentInfo* content_info,
|
void BuildMediaDescription(const ContentInfo* content_info,
|
||||||
const TransportInfo* transport_info,
|
const TransportInfo* transport_info,
|
||||||
const cricket::MediaType media_type,
|
const cricket::MediaType media_type,
|
||||||
@ -1518,34 +1543,12 @@ void BuildMediaDescription(const ContentInfo* content_info,
|
|||||||
if (cricket::IsDtlsSctp(media_desc->protocol())) {
|
if (cricket::IsDtlsSctp(media_desc->protocol())) {
|
||||||
const cricket::SctpDataContentDescription* data_desc =
|
const cricket::SctpDataContentDescription* data_desc =
|
||||||
media_desc->as_sctp();
|
media_desc->as_sctp();
|
||||||
bool use_sctpmap = data_desc->use_sctpmap();
|
BuildSctpContentAttributes(message, data_desc);
|
||||||
BuildSctpContentAttributes(message, data_desc->port(), use_sctpmap);
|
|
||||||
} else if (cricket::IsRtpProtocol(media_desc->protocol())) {
|
} else if (cricket::IsRtpProtocol(media_desc->protocol())) {
|
||||||
BuildRtpContentAttributes(media_desc, media_type, msid_signaling, message);
|
BuildRtpContentAttributes(media_desc, media_type, msid_signaling, message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BuildSctpContentAttributes(std::string* message,
|
|
||||||
int sctp_port,
|
|
||||||
bool use_sctpmap) {
|
|
||||||
rtc::StringBuilder os;
|
|
||||||
if (use_sctpmap) {
|
|
||||||
// draft-ietf-mmusic-sctp-sdp-04
|
|
||||||
// a=sctpmap:sctpmap-number protocol [streams]
|
|
||||||
InitAttrLine(kAttributeSctpmap, &os);
|
|
||||||
os << kSdpDelimiterColon << sctp_port << kSdpDelimiterSpace
|
|
||||||
<< kDefaultSctpmapProtocol << kSdpDelimiterSpace
|
|
||||||
<< cricket::kMaxSctpStreams;
|
|
||||||
} else {
|
|
||||||
// draft-ietf-mmusic-sctp-sdp-23
|
|
||||||
// a=sctp-port:<port>
|
|
||||||
InitAttrLine(kAttributeSctpPort, &os);
|
|
||||||
os << kSdpDelimiterColon << sctp_port;
|
|
||||||
// TODO(zstein): emit max-message-size here
|
|
||||||
}
|
|
||||||
AddLine(os.str(), message);
|
|
||||||
}
|
|
||||||
|
|
||||||
void BuildRtpContentAttributes(const MediaContentDescription* media_desc,
|
void BuildRtpContentAttributes(const MediaContentDescription* media_desc,
|
||||||
const cricket::MediaType media_type,
|
const cricket::MediaType media_type,
|
||||||
int msid_signaling,
|
int msid_signaling,
|
||||||
@ -2706,6 +2709,9 @@ bool ParseMediaDescription(
|
|||||||
// m=application <port> UDP/DTLS/SCTP webrtc-datachannel
|
// m=application <port> UDP/DTLS/SCTP webrtc-datachannel
|
||||||
// use_sctpmap should be false.
|
// use_sctpmap should be false.
|
||||||
auto data_desc = absl::make_unique<SctpDataContentDescription>();
|
auto data_desc = absl::make_unique<SctpDataContentDescription>();
|
||||||
|
// Default max message size is 64K
|
||||||
|
// according to draft-ietf-mmusic-sctp-sdp-26
|
||||||
|
data_desc->set_max_message_size(kDefaultSctpMaxMessageSize);
|
||||||
int p;
|
int p;
|
||||||
if (rtc::FromString(fields[3], &p)) {
|
if (rtc::FromString(fields[3], &p)) {
|
||||||
data_desc->set_port(p);
|
data_desc->set_port(p);
|
||||||
|
|||||||
@ -2891,6 +2891,34 @@ TEST_F(WebRtcSdpTest, DeserializeSdpWithSctpDataChannelsWithMaxMessageSize) {
|
|||||||
EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
|
EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(WebRtcSdpTest, SerializeSdpWithSctpDataChannelWithMaxMessageSize) {
|
||||||
|
bool use_sctpmap = false;
|
||||||
|
AddSctpDataChannel(use_sctpmap);
|
||||||
|
JsepSessionDescription jdesc(kDummyType);
|
||||||
|
MutateJsepSctpMaxMessageSize(desc_, 12345, &jdesc);
|
||||||
|
std::string message = webrtc::SdpSerialize(jdesc);
|
||||||
|
EXPECT_NE(std::string::npos,
|
||||||
|
message.find("\r\na=max-message-size:12345\r\n"));
|
||||||
|
JsepSessionDescription jdesc_output(kDummyType);
|
||||||
|
EXPECT_TRUE(SdpDeserialize(message, &jdesc_output));
|
||||||
|
EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(WebRtcSdpTest,
|
||||||
|
SerializeSdpWithSctpDataChannelWithDefaultMaxMessageSize) {
|
||||||
|
// https://tools.ietf.org/html/draft-ietf-mmusic-sctp-sdp-26#section-6
|
||||||
|
// The default max message size is 64K.
|
||||||
|
bool use_sctpmap = false;
|
||||||
|
AddSctpDataChannel(use_sctpmap);
|
||||||
|
JsepSessionDescription jdesc(kDummyType);
|
||||||
|
MutateJsepSctpMaxMessageSize(desc_, 65536, &jdesc);
|
||||||
|
std::string message = webrtc::SdpSerialize(jdesc);
|
||||||
|
EXPECT_EQ(std::string::npos, message.find("\r\na=max-message-size:"));
|
||||||
|
JsepSessionDescription jdesc_output(kDummyType);
|
||||||
|
EXPECT_TRUE(SdpDeserialize(message, &jdesc_output));
|
||||||
|
EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
|
||||||
|
}
|
||||||
|
|
||||||
// Test to check the behaviour if sctp-port is specified
|
// Test to check the behaviour if sctp-port is specified
|
||||||
// on the m= line and in a=sctp-port.
|
// on the m= line and in a=sctp-port.
|
||||||
TEST_F(WebRtcSdpTest, DeserializeSdpWithMultiSctpPort) {
|
TEST_F(WebRtcSdpTest, DeserializeSdpWithMultiSctpPort) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user