aboutsummaryrefslogtreecommitdiff
path: root/media/sctp/usrsctp_transport.cc
diff options
context:
space:
mode:
Diffstat (limited to 'media/sctp/usrsctp_transport.cc')
-rw-r--r--media/sctp/usrsctp_transport.cc139
1 files changed, 79 insertions, 60 deletions
diff --git a/media/sctp/usrsctp_transport.cc b/media/sctp/usrsctp_transport.cc
index fc226bf7ff..d43c017207 100644
--- a/media/sctp/usrsctp_transport.cc
+++ b/media/sctp/usrsctp_transport.cc
@@ -74,24 +74,25 @@ static constexpr size_t kSctpMtu = 1191;
ABSL_CONST_INIT int g_usrsctp_usage_count = 0;
ABSL_CONST_INIT bool g_usrsctp_initialized_ = false;
ABSL_CONST_INIT webrtc::GlobalMutex g_usrsctp_lock_(absl::kConstInit);
+ABSL_CONST_INIT char kZero[] = {'\0'};
// DataMessageType is used for the SCTP "Payload Protocol Identifier", as
// defined in http://tools.ietf.org/html/rfc4960#section-14.4
//
// For the list of IANA approved values see:
+// https://tools.ietf.org/html/rfc8831 Sec. 8
// http://www.iana.org/assignments/sctp-parameters/sctp-parameters.xml
// The value is not used by SCTP itself. It indicates the protocol running
// on top of SCTP.
enum {
PPID_NONE = 0, // No protocol is specified.
- // Matches the PPIDs in mozilla source and
- // https://datatracker.ietf.org/doc/draft-ietf-rtcweb-data-protocol Sec. 9
- // They're not yet assigned by IANA.
PPID_CONTROL = 50,
- PPID_BINARY_PARTIAL = 52,
+ PPID_TEXT_LAST = 51,
+ PPID_BINARY_PARTIAL = 52, // Deprecated
PPID_BINARY_LAST = 53,
- PPID_TEXT_PARTIAL = 54,
- PPID_TEXT_LAST = 51
+ PPID_TEXT_PARTIAL = 54, // Deprecated
+ PPID_TEXT_EMPTY = 56,
+ PPID_BINARY_EMPTY = 57,
};
// Should only be modified by UsrSctpWrapper.
@@ -128,44 +129,41 @@ void DebugSctpPrintf(const char* format, ...) {
}
// Get the PPID to use for the terminating fragment of this type.
-uint32_t GetPpid(cricket::DataMessageType type) {
+uint32_t GetPpid(webrtc::DataMessageType type, size_t size) {
switch (type) {
- default:
- case cricket::DMT_NONE:
- return PPID_NONE;
- case cricket::DMT_CONTROL:
+ case webrtc::DataMessageType::kControl:
return PPID_CONTROL;
- case cricket::DMT_BINARY:
- return PPID_BINARY_LAST;
- case cricket::DMT_TEXT:
- return PPID_TEXT_LAST;
+ case webrtc::DataMessageType::kBinary:
+ return size > 0 ? PPID_BINARY_LAST : PPID_BINARY_EMPTY;
+ case webrtc::DataMessageType::kText:
+ return size > 0 ? PPID_TEXT_LAST : PPID_TEXT_EMPTY;
}
}
-bool GetDataMediaType(uint32_t ppid, cricket::DataMessageType* dest) {
+bool GetDataMediaType(uint32_t ppid, webrtc::DataMessageType* dest) {
RTC_DCHECK(dest != NULL);
switch (ppid) {
case PPID_BINARY_PARTIAL:
case PPID_BINARY_LAST:
- *dest = cricket::DMT_BINARY;
+ case PPID_BINARY_EMPTY:
+ *dest = webrtc::DataMessageType::kBinary;
return true;
case PPID_TEXT_PARTIAL:
case PPID_TEXT_LAST:
- *dest = cricket::DMT_TEXT;
+ case PPID_TEXT_EMPTY:
+ *dest = webrtc::DataMessageType::kText;
return true;
case PPID_CONTROL:
- *dest = cricket::DMT_CONTROL;
- return true;
-
- case PPID_NONE:
- *dest = cricket::DMT_NONE;
+ *dest = webrtc::DataMessageType::kControl;
return true;
-
- default:
- return false;
}
+ return false;
+}
+
+bool IsEmptyPPID(uint32_t ppid) {
+ return ppid == PPID_BINARY_EMPTY || ppid == PPID_TEXT_EMPTY;
}
// Log the packet in text2pcap format, if log level is at LS_VERBOSE.
@@ -205,11 +203,13 @@ void VerboseLogPacket(const void* data, size_t length, int direction) {
// Creates the sctp_sendv_spa struct used for setting flags in the
// sctp_sendv() call.
-sctp_sendv_spa CreateSctpSendParams(const cricket::SendDataParams& params) {
+sctp_sendv_spa CreateSctpSendParams(int sid,
+ const webrtc::SendDataParams& params,
+ size_t size) {
struct sctp_sendv_spa spa = {0};
spa.sendv_flags |= SCTP_SEND_SNDINFO_VALID;
- spa.sendv_sndinfo.snd_sid = params.sid;
- spa.sendv_sndinfo.snd_ppid = rtc::HostToNetwork32(GetPpid(params.type));
+ spa.sendv_sndinfo.snd_sid = sid;
+ spa.sendv_sndinfo.snd_ppid = rtc::HostToNetwork32(GetPpid(params.type, size));
// Explicitly marking the EOR flag turns the usrsctp_sendv call below into a
// non atomic operation. This means that the sctp lib might only accept the
// message partially. This is done in order to improve throughput, so that we
@@ -217,18 +217,22 @@ sctp_sendv_spa CreateSctpSendParams(const cricket::SendDataParams& params) {
// example.
spa.sendv_sndinfo.snd_flags |= SCTP_EOR;
- // Ordered implies reliable.
if (!params.ordered) {
spa.sendv_sndinfo.snd_flags |= SCTP_UNORDERED;
- if (params.max_rtx_count >= 0 || params.max_rtx_ms == 0) {
- spa.sendv_flags |= SCTP_SEND_PRINFO_VALID;
- spa.sendv_prinfo.pr_policy = SCTP_PR_SCTP_RTX;
- spa.sendv_prinfo.pr_value = params.max_rtx_count;
- } else {
- spa.sendv_flags |= SCTP_SEND_PRINFO_VALID;
- spa.sendv_prinfo.pr_policy = SCTP_PR_SCTP_TTL;
- spa.sendv_prinfo.pr_value = params.max_rtx_ms;
- }
+ }
+ if (params.max_rtx_count.has_value()) {
+ RTC_DCHECK(*params.max_rtx_count >= 0 &&
+ *params.max_rtx_count <= std::numeric_limits<uint16_t>::max());
+ spa.sendv_flags |= SCTP_SEND_PRINFO_VALID;
+ spa.sendv_prinfo.pr_policy = SCTP_PR_SCTP_RTX;
+ spa.sendv_prinfo.pr_value = *params.max_rtx_count;
+ }
+ if (params.max_rtx_ms.has_value()) {
+ RTC_DCHECK(*params.max_rtx_ms >= 0 &&
+ *params.max_rtx_ms <= std::numeric_limits<uint16_t>::max());
+ spa.sendv_flags |= SCTP_SEND_PRINFO_VALID;
+ spa.sendv_prinfo.pr_policy = SCTP_PR_SCTP_TTL;
+ spa.sendv_prinfo.pr_value = *params.max_rtx_ms;
}
return spa;
}
@@ -712,7 +716,8 @@ bool UsrsctpTransport::ResetStream(int sid) {
return true;
}
-bool UsrsctpTransport::SendData(const SendDataParams& params,
+bool UsrsctpTransport::SendData(int sid,
+ const webrtc::SendDataParams& params,
const rtc::CopyOnWriteBuffer& payload,
SendDataResult* result) {
RTC_DCHECK_RUN_ON(network_thread_);
@@ -727,13 +732,13 @@ bool UsrsctpTransport::SendData(const SendDataParams& params,
}
// Do not queue data to send on a closing stream.
- auto it = stream_status_by_sid_.find(params.sid);
+ auto it = stream_status_by_sid_.find(sid);
if (it == stream_status_by_sid_.end() || !it->second.is_open()) {
RTC_LOG(LS_WARNING)
<< debug_name_
<< "->SendData(...): "
"Not sending data because sid is unknown or closing: "
- << params.sid;
+ << sid;
if (result) {
*result = SDR_ERROR;
}
@@ -741,7 +746,7 @@ bool UsrsctpTransport::SendData(const SendDataParams& params,
}
size_t payload_size = payload.size();
- OutgoingMessage message(payload, params);
+ OutgoingMessage message(payload, sid, params);
SendDataResult send_message_result = SendMessageInternal(&message);
if (result) {
*result = send_message_result;
@@ -770,17 +775,17 @@ SendDataResult UsrsctpTransport::SendMessageInternal(OutgoingMessage* message) {
RTC_LOG(LS_WARNING) << debug_name_
<< "->SendMessageInternal(...): "
"Not sending packet with sid="
- << message->send_params().sid
- << " len=" << message->size() << " before Start().";
+ << message->sid() << " len=" << message->size()
+ << " before Start().";
return SDR_ERROR;
}
- if (message->send_params().type != DMT_CONTROL) {
- auto it = stream_status_by_sid_.find(message->send_params().sid);
+ if (message->send_params().type != webrtc::DataMessageType::kControl) {
+ auto it = stream_status_by_sid_.find(message->sid());
if (it == stream_status_by_sid_.end()) {
RTC_LOG(LS_WARNING) << debug_name_
<< "->SendMessageInternal(...): "
"Not sending data because sid is unknown: "
- << message->send_params().sid;
+ << message->sid();
return SDR_ERROR;
}
}
@@ -792,13 +797,23 @@ SendDataResult UsrsctpTransport::SendMessageInternal(OutgoingMessage* message) {
}
// Send data using SCTP.
- sctp_sendv_spa spa = CreateSctpSendParams(message->send_params());
+ sctp_sendv_spa spa = CreateSctpSendParams(
+ message->sid(), message->send_params(), message->size());
+ const void* data = message->data();
+ size_t data_length = message->size();
+ if (message->size() == 0) {
+ // Empty messages are replaced by a single NUL byte on the wire as SCTP
+ // doesn't support empty messages.
+ // The PPID carries the information that the payload needs to be ignored.
+ data = kZero;
+ data_length = 1;
+ }
// Note: this send call is not atomic because the EOR bit is set. This means
// that usrsctp can partially accept this message and it is our duty to buffer
// the rest.
- ssize_t send_res = usrsctp_sendv(
- sock_, message->data(), message->size(), NULL, 0, &spa,
- rtc::checked_cast<socklen_t>(sizeof(spa)), SCTP_SENDV_SPA, 0);
+ ssize_t send_res = usrsctp_sendv(sock_, data, data_length, NULL, 0, &spa,
+ rtc::checked_cast<socklen_t>(sizeof(spa)),
+ SCTP_SENDV_SPA, 0);
if (send_res < 0) {
if (errno == SCTP_EWOULDBLOCK) {
ready_to_send_data_ = false;
@@ -814,8 +829,9 @@ SendDataResult UsrsctpTransport::SendMessageInternal(OutgoingMessage* message) {
}
size_t amount_sent = static_cast<size_t>(send_res);
- RTC_DCHECK_LE(amount_sent, message->size());
- message->Advance(amount_sent);
+ RTC_DCHECK_LE(amount_sent, data_length);
+ if (message->size() != 0)
+ message->Advance(amount_sent);
// Only way out now is success.
return SDR_SUCCESS;
}
@@ -1058,7 +1074,7 @@ bool UsrsctpTransport::SendQueuedStreamResets() {
// https://w3c.github.io/webrtc-pc/#closing-procedure
return stream.second.need_outgoing_reset() &&
(!partial_outgoing_message_.has_value() ||
- partial_outgoing_message_.value().send_params().sid !=
+ partial_outgoing_message_.value().sid() !=
static_cast<int>(stream.first));
};
// Figure out how many streams need to be reset. We need to do this so we can
@@ -1135,7 +1151,7 @@ bool UsrsctpTransport::SendBufferedMessage() {
}
RTC_DCHECK_EQ(0u, partial_outgoing_message_->size());
- int sid = partial_outgoing_message_->send_params().sid;
+ int sid = partial_outgoing_message_->sid();
partial_outgoing_message_.reset();
// Send the queued stream reset if it was pending for this stream.
@@ -1291,7 +1307,7 @@ void UsrsctpTransport::OnDataOrNotificationFromSctp(const void* data,
<< ", eor=" << ((flags & MSG_EOR) ? "y" : "n");
// Validate payload protocol identifier
- DataMessageType type = DMT_NONE;
+ webrtc::DataMessageType type;
if (!GetDataMediaType(ppid, &type)) {
// Unexpected PPID, dropping
RTC_LOG(LS_ERROR) << "Received an unknown PPID " << ppid
@@ -1319,9 +1335,12 @@ void UsrsctpTransport::OnDataOrNotificationFromSctp(const void* data,
// association.
params.seq_num = rcv.rcv_ssn;
- // Append the chunk's data to the message buffer
- partial_incoming_message_.AppendData(reinterpret_cast<const uint8_t*>(data),
- length);
+ // Append the chunk's data to the message buffer unless we have a chunk with a
+ // PPID marking an empty message.
+ // See: https://tools.ietf.org/html/rfc8831#section-6.6
+ if (!IsEmptyPPID(ppid))
+ partial_incoming_message_.AppendData(reinterpret_cast<const uint8_t*>(data),
+ length);
partial_params_ = params;
partial_flags_ = flags;