|
@@ -10,6 +10,7 @@
|
|
#include "dtlstransport.hpp"
|
|
#include "dtlstransport.hpp"
|
|
#include "internals.hpp"
|
|
#include "internals.hpp"
|
|
#include "logcounter.hpp"
|
|
#include "logcounter.hpp"
|
|
|
|
+#include "utils.hpp"
|
|
|
|
|
|
#include <algorithm>
|
|
#include <algorithm>
|
|
#include <chrono>
|
|
#include <chrono>
|
|
@@ -50,28 +51,11 @@
|
|
using namespace std::chrono_literals;
|
|
using namespace std::chrono_literals;
|
|
using namespace std::chrono;
|
|
using namespace std::chrono;
|
|
|
|
|
|
-namespace {
|
|
|
|
-
|
|
|
|
-template <typename T> uint16_t to_uint16(T i) {
|
|
|
|
- if (i >= 0 && static_cast<typename std::make_unsigned<T>::type>(i) <=
|
|
|
|
- std::numeric_limits<uint16_t>::max())
|
|
|
|
- return static_cast<uint16_t>(i);
|
|
|
|
- else
|
|
|
|
- throw std::invalid_argument("Integer out of range");
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-template <typename T> uint32_t to_uint32(T i) {
|
|
|
|
- if (i >= 0 && static_cast<typename std::make_unsigned<T>::type>(i) <=
|
|
|
|
- std::numeric_limits<uint32_t>::max())
|
|
|
|
- return static_cast<uint32_t>(i);
|
|
|
|
- else
|
|
|
|
- throw std::invalid_argument("Integer out of range");
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-} // namespace
|
|
|
|
-
|
|
|
|
namespace rtc::impl {
|
|
namespace rtc::impl {
|
|
|
|
|
|
|
|
+using utils::to_uint16;
|
|
|
|
+using utils::to_uint32;
|
|
|
|
+
|
|
static LogCounter COUNTER_UNKNOWN_PPID(plog::warning,
|
|
static LogCounter COUNTER_UNKNOWN_PPID(plog::warning,
|
|
"Number of SCTP packets received with an unknown PPID");
|
|
"Number of SCTP packets received with an unknown PPID");
|
|
|
|
|
|
@@ -102,7 +86,6 @@ SctpTransport::InstancesSet *SctpTransport::Instances = new InstancesSet;
|
|
|
|
|
|
void SctpTransport::Init() {
|
|
void SctpTransport::Init() {
|
|
usrsctp_init(0, SctpTransport::WriteCallback, SctpTransport::DebugCallback);
|
|
usrsctp_init(0, SctpTransport::WriteCallback, SctpTransport::DebugCallback);
|
|
- usrsctp_enable_crc32c_offload(); // We'll compute CRC32 only for outgoing packets
|
|
|
|
usrsctp_sysctl_set_sctp_pr_enable(1); // Enable Partial Reliability Extension (RFC 3758)
|
|
usrsctp_sysctl_set_sctp_pr_enable(1); // Enable Partial Reliability Extension (RFC 3758)
|
|
usrsctp_sysctl_set_sctp_ecn_enable(0); // Disable Explicit Congestion Notification
|
|
usrsctp_sysctl_set_sctp_ecn_enable(0); // Disable Explicit Congestion Notification
|
|
#ifdef SCTP_DEBUG
|
|
#ifdef SCTP_DEBUG
|
|
@@ -284,6 +267,14 @@ SctpTransport::SctpTransport(shared_ptr<Transport> lower, const Configuration &c
|
|
throw std::runtime_error("Could not disable SCTP fragmented interleave, errno=" +
|
|
throw std::runtime_error("Could not disable SCTP fragmented interleave, errno=" +
|
|
std::to_string(errno));
|
|
std::to_string(errno));
|
|
|
|
|
|
|
|
+ // When using SCTP over DTLS, the data integrity is ensured by DTLS. Therefore, there's no need
|
|
|
|
+ // to check CRC32c additionally when receiving.
|
|
|
|
+ // See https://datatracker.ietf.org/doc/html/draft-ietf-tsvwg-sctp-zero-checksum
|
|
|
|
+ int edmid = SCTP_EDMID_LOWER_LAYER_DTLS;
|
|
|
|
+ if (usrsctp_setsockopt(mSock, IPPROTO_SCTP, SCTP_ACCEPT_ZERO_CHECKSUM, &edmid, sizeof(edmid)))
|
|
|
|
+ throw std::runtime_error("Could set socket option SCTP_ACCEPT_ZERO_CHECKSUM, errno=" +
|
|
|
|
+ std::to_string(errno));
|
|
|
|
+
|
|
int rcvBuf = 0;
|
|
int rcvBuf = 0;
|
|
socklen_t rcvBufLen = sizeof(rcvBuf);
|
|
socklen_t rcvBufLen = sizeof(rcvBuf);
|
|
if (usrsctp_getsockopt(mSock, SOL_SOCKET, SO_RCVBUF, &rcvBuf, &rcvBufLen))
|
|
if (usrsctp_getsockopt(mSock, SOL_SOCKET, SO_RCVBUF, &rcvBuf, &rcvBufLen))
|
|
@@ -380,7 +371,7 @@ bool SctpTransport::send(message_ptr message) {
|
|
|
|
|
|
PLOG_VERBOSE << "Send size=" << message->size();
|
|
PLOG_VERBOSE << "Send size=" << message->size();
|
|
|
|
|
|
- if(message->size() > mMaxMessageSize)
|
|
|
|
|
|
+ if (message->size() > mMaxMessageSize)
|
|
throw std::invalid_argument("Message is too large");
|
|
throw std::invalid_argument("Message is too large");
|
|
|
|
|
|
// Flush the queue, and if nothing is pending, try to send directly
|
|
// Flush the queue, and if nothing is pending, try to send directly
|
|
@@ -515,7 +506,7 @@ void SctpTransport::doRecv() {
|
|
} else {
|
|
} else {
|
|
// SCTP message
|
|
// SCTP message
|
|
mPartialMessage.insert(mPartialMessage.end(), buffer, buffer + len);
|
|
mPartialMessage.insert(mPartialMessage.end(), buffer, buffer + len);
|
|
- if(mPartialMessage.size() > mMaxMessageSize) {
|
|
|
|
|
|
+ if (mPartialMessage.size() > mMaxMessageSize) {
|
|
PLOG_WARNING << "SCTP message is too large, truncating it";
|
|
PLOG_WARNING << "SCTP message is too large, truncating it";
|
|
mPartialMessage.resize(mMaxMessageSize);
|
|
mPartialMessage.resize(mMaxMessageSize);
|
|
}
|
|
}
|
|
@@ -639,7 +630,20 @@ bool SctpTransport::trySendMessage(message_ptr message) {
|
|
if (reliability.unordered)
|
|
if (reliability.unordered)
|
|
spa.sendv_sndinfo.snd_flags |= SCTP_UNORDERED;
|
|
spa.sendv_sndinfo.snd_flags |= SCTP_UNORDERED;
|
|
|
|
|
|
- switch (reliability.type) {
|
|
|
|
|
|
+ if (reliability.maxPacketLifeTime) {
|
|
|
|
+ spa.sendv_flags |= SCTP_SEND_PRINFO_VALID;
|
|
|
|
+ spa.sendv_prinfo.pr_policy = SCTP_PR_SCTP_TTL;
|
|
|
|
+ spa.sendv_prinfo.pr_value = to_uint32(reliability.maxPacketLifeTime->count());
|
|
|
|
+ } else if (reliability.maxRetransmits) {
|
|
|
|
+ spa.sendv_flags |= SCTP_SEND_PRINFO_VALID;
|
|
|
|
+ spa.sendv_prinfo.pr_policy = SCTP_PR_SCTP_RTX;
|
|
|
|
+ spa.sendv_prinfo.pr_value = to_uint32(*reliability.maxRetransmits);
|
|
|
|
+ }
|
|
|
|
+ // else {
|
|
|
|
+ // spa.sendv_prinfo.pr_policy = SCTP_PR_SCTP_NONE;
|
|
|
|
+ // }
|
|
|
|
+ // Deprecated
|
|
|
|
+ else switch (reliability.typeDeprecated) {
|
|
case Reliability::Type::Rexmit:
|
|
case Reliability::Type::Rexmit:
|
|
spa.sendv_flags |= SCTP_SEND_PRINFO_VALID;
|
|
spa.sendv_flags |= SCTP_SEND_PRINFO_VALID;
|
|
spa.sendv_prinfo.pr_policy = SCTP_PR_SCTP_RTX;
|
|
spa.sendv_prinfo.pr_policy = SCTP_PR_SCTP_RTX;
|
|
@@ -960,13 +964,6 @@ void SctpTransport::UpcallCallback(struct socket *, void *arg, int /* flags */)
|
|
int SctpTransport::WriteCallback(void *ptr, void *data, size_t len, uint8_t tos, uint8_t set_df) {
|
|
int SctpTransport::WriteCallback(void *ptr, void *data, size_t len, uint8_t tos, uint8_t set_df) {
|
|
auto *transport = static_cast<SctpTransport *>(ptr);
|
|
auto *transport = static_cast<SctpTransport *>(ptr);
|
|
|
|
|
|
- // Set the CRC32 ourselves as we have enabled CRC32 offloading
|
|
|
|
- if (len >= 12) {
|
|
|
|
- uint32_t *checksum = reinterpret_cast<uint32_t *>(data) + 2;
|
|
|
|
- *checksum = 0;
|
|
|
|
- *checksum = usrsctp_crc32c(data, len);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
// Workaround for sctplab/usrsctp#405: Send callback is invoked on already closed socket
|
|
// Workaround for sctplab/usrsctp#405: Send callback is invoked on already closed socket
|
|
// https://github.com/sctplab/usrsctp/issues/405
|
|
// https://github.com/sctplab/usrsctp/issues/405
|
|
if (auto locked = Instances->lock(transport))
|
|
if (auto locked = Instances->lock(transport))
|