|
@@ -84,11 +84,6 @@ namespace rtc::impl {
|
|
|
|
|
|
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");
|
|
-static LogCounter
|
|
|
|
- COUNTER_BAD_NOTIF_LEN(plog::warning,
|
|
|
|
- "Number of SCTP packets received with an bad notification length");
|
|
|
|
-static LogCounter COUNTER_BAD_SCTP_STATUS(plog::warning,
|
|
|
|
- "Number of SCTP packets received with a bad status");
|
|
|
|
|
|
|
|
class SctpTransport::InstancesSet {
|
|
class SctpTransport::InstancesSet {
|
|
public:
|
|
public:
|
|
@@ -103,7 +98,7 @@ public:
|
|
}
|
|
}
|
|
|
|
|
|
using shared_lock = std::shared_lock<std::shared_mutex>;
|
|
using shared_lock = std::shared_lock<std::shared_mutex>;
|
|
- optional<shared_lock> lock(SctpTransport *instance) {
|
|
|
|
|
|
+ optional<shared_lock> lock(SctpTransport *instance) noexcept {
|
|
shared_lock lock(mMutex);
|
|
shared_lock lock(mMutex);
|
|
return mSet.find(instance) != mSet.end() ? std::make_optional(std::move(lock)) : nullopt;
|
|
return mSet.find(instance) != mSet.end() ? std::make_optional(std::move(lock)) : nullopt;
|
|
}
|
|
}
|
|
@@ -175,7 +170,7 @@ void SctpTransport::SetSettings(const SctpSettings &s) {
|
|
}
|
|
}
|
|
|
|
|
|
void SctpTransport::Cleanup() {
|
|
void SctpTransport::Cleanup() {
|
|
- while (usrsctp_finish() != 0)
|
|
|
|
|
|
+ while (usrsctp_finish())
|
|
std::this_thread::sleep_for(100ms);
|
|
std::this_thread::sleep_for(100ms);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -329,6 +324,8 @@ SctpTransport::SctpTransport(shared_ptr<Transport> lower, const Configuration &c
|
|
SctpTransport::~SctpTransport() {
|
|
SctpTransport::~SctpTransport() {
|
|
PLOG_DEBUG << "Destroying SCTP transport";
|
|
PLOG_DEBUG << "Destroying SCTP transport";
|
|
|
|
|
|
|
|
+ mProcessor.join(); // if we are here, the processor must be empty
|
|
|
|
+
|
|
// Before unregistering incoming() from the lower layer, we need to make sure the thread from
|
|
// Before unregistering incoming() from the lower layer, we need to make sure the thread from
|
|
// lower layers is not blocked in incoming() by the WrittenOnce condition.
|
|
// lower layers is not blocked in incoming() by the WrittenOnce condition.
|
|
mWrittenOnce = true;
|
|
mWrittenOnce = true;
|
|
@@ -336,7 +333,6 @@ SctpTransport::~SctpTransport() {
|
|
|
|
|
|
unregisterIncoming();
|
|
unregisterIncoming();
|
|
|
|
|
|
- mProcessor.join();
|
|
|
|
usrsctp_close(mSock);
|
|
usrsctp_close(mSock);
|
|
|
|
|
|
usrsctp_deregister_address(this);
|
|
usrsctp_deregister_address(this);
|
|
@@ -366,9 +362,6 @@ struct sockaddr_conn SctpTransport::getSockAddrConn(uint16_t port) {
|
|
}
|
|
}
|
|
|
|
|
|
void SctpTransport::connect() {
|
|
void SctpTransport::connect() {
|
|
- if (!mSock)
|
|
|
|
- throw std::logic_error("Attempted SCTP connect with closed socket");
|
|
|
|
-
|
|
|
|
PLOG_DEBUG << "SCTP connecting (local port=" << mPorts.local
|
|
PLOG_DEBUG << "SCTP connecting (local port=" << mPorts.local
|
|
<< ", remote port=" << mPorts.remote << ")";
|
|
<< ", remote port=" << mPorts.remote << ")";
|
|
changeState(State::Connecting);
|
|
changeState(State::Connecting);
|
|
@@ -386,17 +379,6 @@ void SctpTransport::connect() {
|
|
throw std::runtime_error("Connection attempt failed, errno=" + std::to_string(errno));
|
|
throw std::runtime_error("Connection attempt failed, errno=" + std::to_string(errno));
|
|
}
|
|
}
|
|
|
|
|
|
-void SctpTransport::shutdown() {
|
|
|
|
- if (!mSock)
|
|
|
|
- return;
|
|
|
|
-
|
|
|
|
- PLOG_DEBUG << "SCTP shutdown";
|
|
|
|
-
|
|
|
|
- if (usrsctp_shutdown(mSock, SHUT_RDWR) != 0 && errno != ENOTCONN) {
|
|
|
|
- PLOG_WARNING << "SCTP shutdown failed, errno=" << errno;
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
bool SctpTransport::send(message_ptr message) {
|
|
bool SctpTransport::send(message_ptr message) {
|
|
std::lock_guard lock(mSendMutex);
|
|
std::lock_guard lock(mSendMutex);
|
|
|
|
|
|
@@ -542,6 +524,28 @@ void SctpTransport::doFlush() {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+void SctpTransport::enqueueRecv() {
|
|
|
|
+ if (mPendingRecvCount > 0)
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ if (auto shared_this = weak_from_this().lock()) {
|
|
|
|
+ // This is called from the upcall callback, we must not release the shared ptr here
|
|
|
|
+ ++mPendingRecvCount;
|
|
|
|
+ mProcessor.enqueue(&SctpTransport::doRecv, std::move(shared_this));
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void SctpTransport::enqueueFlush() {
|
|
|
|
+ if (mPendingFlushCount > 0)
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ if (auto shared_this = weak_from_this().lock()) {
|
|
|
|
+ // This is called from the upcall callback, we must not release the shared ptr here
|
|
|
|
+ ++mPendingFlushCount;
|
|
|
|
+ mProcessor.enqueue(&SctpTransport::doFlush, std::move(shared_this));
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
bool SctpTransport::trySendQueue() {
|
|
bool SctpTransport::trySendQueue() {
|
|
// Requires mSendMutex to be locked
|
|
// Requires mSendMutex to be locked
|
|
while (auto next = mSendQueue.peek()) {
|
|
while (auto next = mSendQueue.peek()) {
|
|
@@ -553,9 +557,17 @@ bool SctpTransport::trySendQueue() {
|
|
updateBufferedAmount(to_uint16(message->stream), -ptrdiff_t(message_size_func(message)));
|
|
updateBufferedAmount(to_uint16(message->stream), -ptrdiff_t(message_size_func(message)));
|
|
}
|
|
}
|
|
|
|
|
|
- if (!mSendQueue.running()) {
|
|
|
|
- shutdown();
|
|
|
|
- return false;
|
|
|
|
|
|
+ if (!mSendQueue.running() && !std::exchange(mSendShutdown, true)) {
|
|
|
|
+ PLOG_DEBUG << "SCTP shutdown";
|
|
|
|
+ if (usrsctp_shutdown(mSock, SHUT_WR)) {
|
|
|
|
+ if (errno == ENOTCONN) {
|
|
|
|
+ PLOG_VERBOSE << "SCTP already shut down";
|
|
|
|
+ } else {
|
|
|
|
+ PLOG_WARNING << "SCTP shutdown failed, errno=" << errno;
|
|
|
|
+ changeState(State::Disconnected);
|
|
|
|
+ recv(nullptr);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
return true;
|
|
return true;
|
|
@@ -698,31 +710,25 @@ void SctpTransport::sendReset(uint16_t streamId) {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-void SctpTransport::handleUpcall() {
|
|
|
|
|
|
+void SctpTransport::handleUpcall() noexcept {
|
|
try {
|
|
try {
|
|
- if (!mSock)
|
|
|
|
- return;
|
|
|
|
-
|
|
|
|
PLOG_VERBOSE << "Handle upcall";
|
|
PLOG_VERBOSE << "Handle upcall";
|
|
|
|
|
|
int events = usrsctp_get_events(mSock);
|
|
int events = usrsctp_get_events(mSock);
|
|
|
|
|
|
- if (events & SCTP_EVENT_READ && mPendingRecvCount == 0) {
|
|
|
|
- ++mPendingRecvCount;
|
|
|
|
- mProcessor.enqueue(&SctpTransport::doRecv, shared_from_this());
|
|
|
|
- }
|
|
|
|
|
|
+ if (events & SCTP_EVENT_READ)
|
|
|
|
+ enqueueRecv();
|
|
|
|
|
|
- if (events & SCTP_EVENT_WRITE && mPendingFlushCount == 0) {
|
|
|
|
- ++mPendingFlushCount;
|
|
|
|
- mProcessor.enqueue(&SctpTransport::doFlush, shared_from_this());
|
|
|
|
- }
|
|
|
|
|
|
+ if (events & SCTP_EVENT_WRITE)
|
|
|
|
+ enqueueFlush();
|
|
|
|
|
|
} catch (const std::exception &e) {
|
|
} catch (const std::exception &e) {
|
|
PLOG_ERROR << "SCTP upcall: " << e.what();
|
|
PLOG_ERROR << "SCTP upcall: " << e.what();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-int SctpTransport::handleWrite(byte *data, size_t len, uint8_t /*tos*/, uint8_t /*set_df*/) {
|
|
|
|
|
|
+int SctpTransport::handleWrite(byte *data, size_t len, uint8_t /*tos*/,
|
|
|
|
+ uint8_t /*set_df*/) noexcept {
|
|
try {
|
|
try {
|
|
std::unique_lock lock(mWriteMutex);
|
|
std::unique_lock lock(mWriteMutex);
|
|
PLOG_VERBOSE << "Handle write, len=" << len;
|
|
PLOG_VERBOSE << "Handle write, len=" << len;
|
|
@@ -806,7 +812,8 @@ void SctpTransport::processData(binary &&data, uint16_t sid, PayloadId ppid) {
|
|
|
|
|
|
void SctpTransport::processNotification(const union sctp_notification *notify, size_t len) {
|
|
void SctpTransport::processNotification(const union sctp_notification *notify, size_t len) {
|
|
if (len != size_t(notify->sn_header.sn_length)) {
|
|
if (len != size_t(notify->sn_header.sn_length)) {
|
|
- COUNTER_BAD_NOTIF_LEN++;
|
|
|
|
|
|
+ PLOG_WARNING << "Unexpected notification length, expected=" << notify->sn_header.sn_length
|
|
|
|
+ << ", actual=" << len;
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -908,10 +915,9 @@ optional<milliseconds> SctpTransport::rtt() {
|
|
|
|
|
|
struct sctp_status status = {};
|
|
struct sctp_status status = {};
|
|
socklen_t len = sizeof(status);
|
|
socklen_t len = sizeof(status);
|
|
- if (usrsctp_getsockopt(mSock, IPPROTO_SCTP, SCTP_STATUS, &status, &len)) {
|
|
|
|
- COUNTER_BAD_SCTP_STATUS++;
|
|
|
|
|
|
+ if (usrsctp_getsockopt(mSock, IPPROTO_SCTP, SCTP_STATUS, &status, &len))
|
|
return nullopt;
|
|
return nullopt;
|
|
- }
|
|
|
|
|
|
+
|
|
return milliseconds(status.sstat_primary.spinfo_srtt);
|
|
return milliseconds(status.sstat_primary.spinfo_srtt);
|
|
}
|
|
}
|
|
|
|
|