Selaa lähdekoodia

Added SCTP settings API and enhanced integer conversions in SctpTransport

Paul-Louis Ageneau 4 vuotta sitten
vanhempi
commit
251bfc7def
7 muutettua tiedostoa jossa 166 lisäystä ja 52 poistoa
  1. 1 0
      include/rtc/common.hpp
  2. 13 0
      include/rtc/init.hpp
  3. 47 24
      include/rtc/rtc.h
  4. 27 0
      src/capi.cpp
  5. 65 26
      src/impl/sctptransport.cpp
  6. 2 1
      src/impl/sctptransport.hpp
  7. 11 1
      src/init.cpp

+ 1 - 0
include/rtc/common.hpp

@@ -70,6 +70,7 @@ using binary = std::vector<byte>;
 using binary_ptr = std::shared_ptr<binary>;
 
 using std::size_t;
+using std::ptrdiff_t;
 using std::uint16_t;
 using std::uint32_t;
 using std::uint64_t;

+ 13 - 0
include/rtc/init.hpp

@@ -21,17 +21,28 @@
 
 #include "common.hpp"
 
+#include <chrono>
 #include <mutex>
 
 namespace rtc {
 
 using init_token = shared_ptr<void>;
 
+struct SctpSettings {
+	optional<size_t> recvBufferSize;
+	optional<size_t> sendBufferSize;
+	optional<size_t> maxChunksOnQueue;
+	optional<size_t> initialCongestionWindow;
+	optional<unsigned int> congestionControlModule;
+	optional<std::chrono::milliseconds> delayedSackTime;
+};
+
 class RTC_CPP_EXPORT Init {
 public:
 	static init_token Token();
 	static void Preload();
 	static void Cleanup();
+	static void SetSctpSettings(SctpSettings s);
 
 	~Init();
 
@@ -41,11 +52,13 @@ private:
 	static weak_ptr<void> Weak;
 	static shared_ptr<void> *Global;
 	static bool Initialized;
+	static SctpSettings CurrentSctpSettings;
 	static std::recursive_mutex Mutex;
 };
 
 inline void Preload() { Init::Preload(); }
 inline void Cleanup() { Init::Cleanup(); }
+inline void SetSctpSettings(SctpSettings s) { Init::SetSctpSettings(std::move(s)); }
 
 } // namespace rtc
 

+ 47 - 24
include/rtc/rtc.h

@@ -46,7 +46,8 @@ extern "C" {
 #define RTC_DEFAULT_MTU 1280 // IPv6 minimum guaranteed MTU
 
 #if RTC_ENABLE_MEDIA
-#define RTC_DEFAULT_MAXIMUM_FRAGMENT_SIZE ((uint16_t)(RTC_DEFAULT_MTU - 12 - 8 - 40)) // SRTP/UDP/IPv6
+#define RTC_DEFAULT_MAXIMUM_FRAGMENT_SIZE                                                          \
+	((uint16_t)(RTC_DEFAULT_MTU - 12 - 8 - 40)) // SRTP/UDP/IPv6
 #define RTC_DEFAULT_MAXIMUM_PACKET_COUNT_FOR_NACK_CACHE ((unsigned)512)
 #endif
 
@@ -97,21 +98,21 @@ typedef enum {
 #if RTC_ENABLE_MEDIA
 
 typedef enum {
-    // video
-    RTC_CODEC_H264 = 0,
-    RTC_CODEC_VP8 = 1,
-    RTC_CODEC_VP9 = 2,
+	// video
+	RTC_CODEC_H264 = 0,
+	RTC_CODEC_VP8 = 1,
+	RTC_CODEC_VP9 = 2,
 
-    // audio
-    RTC_CODEC_OPUS = 128
+	// audio
+	RTC_CODEC_OPUS = 128
 } rtcCodec;
 
 typedef enum {
-    RTC_DIRECTION_UNKNOWN = 0,
-    RTC_DIRECTION_SENDONLY = 1,
-    RTC_DIRECTION_RECVONLY = 2,
-    RTC_DIRECTION_SENDRECV = 3,
-    RTC_DIRECTION_INACTIVE = 4
+	RTC_DIRECTION_UNKNOWN = 0,
+	RTC_DIRECTION_SENDONLY = 1,
+	RTC_DIRECTION_RECVONLY = 2,
+	RTC_DIRECTION_SENDRECV = 3,
+	RTC_DIRECTION_INACTIVE = 4
 } rtcDirection;
 
 #endif // RTC_ENABLE_MEDIA
@@ -130,7 +131,7 @@ typedef struct {
 	bool disableAutoNegotiation;
 	uint16_t portRangeBegin;
 	uint16_t portRangeEnd;
-	int mtu; // <= 0 means automatic
+	int mtu;            // <= 0 means automatic
 	int maxMessageSize; // <= 0 means default
 } rtcConfiguration;
 
@@ -172,7 +173,7 @@ RTC_EXPORT void rtcInitLogger(rtcLogLevel level, rtcLogCallbackFunc cb);
 
 // User pointer
 RTC_EXPORT void rtcSetUserPointer(int id, void *ptr);
-RTC_EXPORT void * rtcGetUserPointer(int i);
+RTC_EXPORT void *rtcGetUserPointer(int i);
 
 // PeerConnection
 RTC_EXPORT int rtcCreatePeerConnection(const rtcConfiguration *config); // returns pc id
@@ -219,6 +220,19 @@ RTC_EXPORT int rtcDeleteTrack(int tr);
 
 RTC_EXPORT int rtcGetTrackDescription(int tr, char *buffer, int size);
 
+// SCTP settings
+typedef struct {
+	int recvBufferSize;          // <= 0 means optimized default
+	int sendBufferSize;          // <= 0 means optimized default
+	int maxChunksOnQueue;        // <= 0 means optimized default
+	int initialCongestionWindow; // <= 0 means optimized default
+	int congestionControlModule; // <= 0 means default (0: RFC2581, 1: HSTCP, 2: H-TCP, 3: RTCC)
+	int delayedSackTimeMs;       // <= 0 means optimized default
+} rtcSctpSettings;
+
+// Note: SCTP settings apply to newly-created PeerConnections only
+RTC_EXPORT int rtcSetSctpSettings(const rtcSctpSettings *settings);
+
 // Media
 #if RTC_ENABLE_MEDIA
 
@@ -233,7 +247,9 @@ RTC_EXPORT int rtcGetTrackDescription(int tr, char *buffer, int size);
 /// @param _msid MSID (optional)
 /// @param _trackID Track ID used in MSID (optional)
 /// @returns Track id
-RTC_EXPORT int rtcAddTrackEx(int pc, rtcCodec codec, int payloadType, uint32_t ssrc, const char *_mid, rtcDirection direction, const char *_name, const char *_msid, const char *_trackID);
+RTC_EXPORT int rtcAddTrackEx(int pc, rtcCodec codec, int payloadType, uint32_t ssrc,
+                             const char *_mid, rtcDirection direction, const char *_name,
+                             const char *_msid, const char *_trackID);
 
 /// Set H264PacketizationHandler for track
 /// @param tr Track id
@@ -244,7 +260,10 @@ RTC_EXPORT int rtcAddTrackEx(int pc, rtcCodec codec, int payloadType, uint32_t s
 /// @param maxFragmentSize Maximum NALU fragment size
 /// @param sequenceNumber Sequence number
 /// @param timestamp Timestamp
-RTC_EXPORT int rtcSetH264PacketizationHandler(int tr, uint32_t ssrc, const char * cname, uint8_t payloadType, uint32_t clockRate, uint16_t maxFragmentSize, uint16_t sequenceNumber, uint32_t timestamp);
+RTC_EXPORT int rtcSetH264PacketizationHandler(int tr, uint32_t ssrc, const char *cname,
+                                              uint8_t payloadType, uint32_t clockRate,
+                                              uint16_t maxFragmentSize, uint16_t sequenceNumber,
+                                              uint32_t timestamp);
 
 /// Set OpusPacketizationHandler for track
 /// @param tr Track id
@@ -254,7 +273,9 @@ RTC_EXPORT int rtcSetH264PacketizationHandler(int tr, uint32_t ssrc, const char
 /// @param clockRate Clock rate
 /// @param _sequenceNumber Sequence number
 /// @param _timestamp Timestamp
-RTC_EXPORT int rtcSetOpusPacketizationHandler(int tr, uint32_t ssrc, const char * cname, uint8_t payloadType, uint32_t clockRate, uint16_t _sequenceNumber, uint32_t _timestamp);
+RTC_EXPORT int rtcSetOpusPacketizationHandler(int tr, uint32_t ssrc, const char *cname,
+                                              uint8_t payloadType, uint32_t clockRate,
+                                              uint16_t _sequenceNumber, uint32_t _timestamp);
 
 /// Chain RtcpSrReporter to handler chain for given track
 /// @param tr Track id
@@ -267,9 +288,11 @@ int rtcChainRtcpNackResponder(int tr, unsigned maxStoredPacketsCount);
 
 /// Set start time for RTP stream
 /// @param startTime_s Start time in seconds
-/// @param timeIntervalSince1970 Set true if `startTime_s` is time interval since 1970, false if `startTime_s` is time interval since 1900
+/// @param timeIntervalSince1970 Set true if `startTime_s` is time interval since 1970, false if
+/// `startTime_s` is time interval since 1900
 /// @param _timestamp Start timestamp
-int rtcSetRtpConfigurationStartTime(int id, double startTime_s, bool timeIntervalSince1970, uint32_t _timestamp);
+int rtcSetRtpConfigurationStartTime(int id, double startTime_s, bool timeIntervalSince1970,
+                                    uint32_t _timestamp);
 
 /// Start stats recording for RTCP Sender Reporter
 /// @param id Track identifier
@@ -279,23 +302,23 @@ int rtcStartRtcpSenderReporterRecording(int id);
 /// @param id Track id
 /// @param seconds Seconds
 /// @param timestamp Pointer to result
-int rtcTransformSecondsToTimestamp(int id, double seconds, uint32_t * timestamp);
+int rtcTransformSecondsToTimestamp(int id, double seconds, uint32_t *timestamp);
 
 /// Transform timestamp to seconds using track's clock rate
 /// @param id Track id
 /// @param timestamp Timestamp
 /// @param seconds Pointer for result
-int rtcTransformTimestampToSeconds(int id, uint32_t timestamp, double * seconds);
+int rtcTransformTimestampToSeconds(int id, uint32_t timestamp, double *seconds);
 
 /// Get current timestamp
 /// @param id Track id
 /// @param timestamp Pointer for result
-int rtcGetCurrentTrackTimestamp(int id, uint32_t * timestamp);
+int rtcGetCurrentTrackTimestamp(int id, uint32_t *timestamp);
 
 /// Get start timestamp for track identified by given id
 /// @param id Track id
 /// @param timestamp Pointer for result
-int rtcGetTrackStartTimestamp(int id, uint32_t * timestamp);
+int rtcGetTrackStartTimestamp(int id, uint32_t *timestamp);
 
 /// Set RTP timestamp for track identified by given id
 /// @param id Track id
@@ -305,7 +328,7 @@ int rtcSetTrackRTPTimestamp(int id, uint32_t timestamp);
 /// Get timestamp of previous RTCP SR
 /// @param id Track id
 /// @param timestamp Pointer for result
-int rtcGetPreviousTrackSenderReportTimestamp(int id, uint32_t * timestamp);
+int rtcGetPreviousTrackSenderReportTimestamp(int id, uint32_t *timestamp);
 
 /// Set `NeedsToReport` flag in RtcpSrReporter handler identified by given track id
 /// @param id Track id

+ 27 - 0
src/capi.cpp

@@ -715,6 +715,33 @@ int rtcGetTrackDescription(int tr, char *buffer, int size) {
 	});
 }
 
+int rtcSetSctpSettings(const rtcSctpSettings *settings) {
+	return wrap([&] {
+		SctpSettings s = {};
+
+		if (settings->recvBufferSize > 0)
+			s.recvBufferSize = size_t(settings->recvBufferSize);
+
+		if (settings->sendBufferSize > 0)
+			s.sendBufferSize = size_t(settings->sendBufferSize);
+
+		if (settings->maxChunksOnQueue > 0)
+			s.maxChunksOnQueue = size_t(settings->maxChunksOnQueue);
+
+		if (settings->initialCongestionWindow > 0)
+			s.initialCongestionWindow = size_t(settings->initialCongestionWindow);
+
+		if (settings->congestionControlModule >= 0)
+			s.congestionControlModule = unsigned(settings->congestionControlModule);
+
+		if (settings->delayedSackTimeMs > 0)
+			s.delayedSackTime = std::chrono::milliseconds(settings->delayedSackTimeMs);
+
+		SetSctpSettings(std::move(s));
+		return RTC_ERR_SUCCESS;
+	});
+}
+
 #if RTC_ENABLE_WEBSOCKET
 int rtcCreateWebSocket(const char *url) {
 	return wrap([&] {

+ 65 - 26
src/impl/sctptransport.cpp

@@ -24,6 +24,7 @@
 #include <chrono>
 #include <exception>
 #include <iostream>
+#include <limits>
 #include <thread>
 #include <vector>
 
@@ -54,6 +55,26 @@
 using namespace std::chrono_literals;
 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 {
 
 static LogCounter COUNTER_UNKNOWN_PPID(plog::warning,
@@ -69,7 +90,8 @@ std::shared_mutex SctpTransport::InstancesMutex;
 
 void SctpTransport::Init() {
 	usrsctp_init(0, &SctpTransport::WriteCallback, nullptr);
-	usrsctp_sysctl_set_sctp_ecn_enable(0);
+	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_init_rtx_max_default(5);
 	usrsctp_sysctl_set_sctp_path_rtx_max_default(5);
 	usrsctp_sysctl_set_sctp_assoc_rtx_max_default(5);              // single path
@@ -78,21 +100,28 @@ void SctpTransport::Init() {
 	usrsctp_sysctl_set_sctp_rto_initial_default(1 * 1000);         // ms
 	usrsctp_sysctl_set_sctp_init_rto_max_default(10 * 1000);       // ms
 	usrsctp_sysctl_set_sctp_heartbeat_interval_default(10 * 1000); // ms
+}
 
-	usrsctp_sysctl_set_sctp_max_chunks_on_queue(10 * 1024);
+void SctpTransport::SetSettings(const SctpSettings &s) {
+	// The send and receive window size of usrsctp is 256KiB, which is too small for realistic RTTs,
+	// therefore we increase it to 1MiB by default for better performance.
+	// See https://bugzilla.mozilla.org/show_bug.cgi?id=1051685
+	usrsctp_sysctl_set_sctp_recvspace(to_uint32(s.recvBufferSize.value_or(1024 * 1024)));
+	usrsctp_sysctl_set_sctp_sendspace(to_uint32(s.sendBufferSize.value_or(1024 * 1024)));
 
-	// Use default congestion control (RFC 4960)
-	// See https://github.com/paullouisageneau/libdatachannel/issues/354
-	usrsctp_sysctl_set_sctp_default_cc_module(0);
+	// Increase maximum chunks number on queue to 10K by default
+	usrsctp_sysctl_set_sctp_max_chunks_on_queue(to_uint32(s.maxChunksOnQueue.value_or(10 * 1024)));
 
-	// Enable Partial Reliability Extension (RFC 3758)
-	usrsctp_sysctl_set_sctp_pr_enable(1);
+	// Increase initial congestion window size to 10 MTUs (RFC 6928) by default
+	usrsctp_sysctl_set_sctp_initial_cwnd(to_uint32(s.initialCongestionWindow.value_or(10)));
 
-	// Increase the initial window size to 10 MTUs (RFC 6928)
-	usrsctp_sysctl_set_sctp_initial_cwnd(10);
+	// Use standard SCTP congestion control (RFC 4960) by default
+	// See https://github.com/paullouisageneau/libdatachannel/issues/354
+	usrsctp_sysctl_set_sctp_default_cc_module(to_uint32(s.congestionControlModule.value_or(0)));
 
-	// Reduce SACK delay from the default 200ms to 20ms
-	usrsctp_sysctl_set_sctp_delayed_sack_time_default(20); // ms
+	// Reduce SACK delay to 20ms by default
+	usrsctp_sysctl_set_sctp_delayed_sack_time_default(
+	    to_uint32(s.delayedSackTime.value_or(20ms).count()));
 }
 
 void SctpTransport::Cleanup() {
@@ -195,7 +224,7 @@ SctpTransport::SctpTransport(shared_ptr<Transport> lower, const Configuration &c
 		// The MTU value provided specifies the space available for chunks in the
 		// packet, so we also subtract the SCTP header size.
 		size_t pmtu = config.mtu.value_or(DEFAULT_MTU) - 12 - 37 - 8 - 40; // SCTP/DTLS/UDP/IPv6
-		spp.spp_pathmtu = uint32_t(pmtu);
+		spp.spp_pathmtu = to_uint32(pmtu);
 		PLOG_VERBOSE << "Path MTU discovery disabled, SCTP MTU set to " << pmtu;
 	}
 
@@ -222,18 +251,28 @@ SctpTransport::SctpTransport(shared_ptr<Transport> lower, const Configuration &c
 		throw std::runtime_error("Could not disable SCTP fragmented interleave, errno=" +
 		                         std::to_string(errno));
 
-	// The default send and receive window size of usrsctp is 256KiB, which is too small for
-	// realistic RTTs, therefore we increase it to at least 1MiB for better performance.
-	// See https://bugzilla.mozilla.org/show_bug.cgi?id=1051685
-	const size_t minBufferSize = 1024 * 1024;
+	int rcvBuf = 0;
+	socklen_t rcvBufLen = sizeof(rcvBuf);
+	if (usrsctp_getsockopt(mSock, SOL_SOCKET, SO_RCVBUF, &rcvBuf, &rcvBufLen))
+		throw std::runtime_error("Could not get SCTP recv buffer size, errno=" +
+		                         std::to_string(errno));
+	int sndBuf = 0;
+	socklen_t sndBufLen = sizeof(sndBuf);
+	if (usrsctp_getsockopt(mSock, SOL_SOCKET, SO_SNDBUF, &rcvBuf, &sndBufLen))
+		throw std::runtime_error("Could not get SCTP recv buffer size, errno=" +
+		                         std::to_string(errno));
 
 	// Ensure the buffer is also large enough to accomodate the largest messages
 	const size_t maxMessageSize = config.maxMessageSize.value_or(DEFAULT_LOCAL_MAX_MESSAGE_SIZE);
-	const int bufferSize = int(std::max(minBufferSize, maxMessageSize * 2)); // usrsctp reads as int
-	if (usrsctp_setsockopt(mSock, SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize)))
+	const int minBuf = int(std::min(maxMessageSize, size_t(std::numeric_limits<int>::max())));
+	rcvBuf = std::max(rcvBuf, minBuf);
+	sndBuf = std::max(sndBuf, minBuf);
+
+	if (usrsctp_setsockopt(mSock, SOL_SOCKET, SO_RCVBUF, &rcvBuf, sizeof(rcvBuf)))
 		throw std::runtime_error("Could not set SCTP recv buffer size, errno=" +
 		                         std::to_string(errno));
-	if (usrsctp_setsockopt(mSock, SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize)))
+
+	if (usrsctp_setsockopt(mSock, SOL_SOCKET, SO_SNDBUF, &sndBuf, sizeof(sndBuf)))
 		throw std::runtime_error("Could not set SCTP send buffer size, errno=" +
 		                         std::to_string(errno));
 }
@@ -336,7 +375,7 @@ bool SctpTransport::send(message_ptr message) {
 		return true;
 
 	mSendQueue.push(message);
-	updateBufferedAmount(uint16_t(message->stream), long(message_size_func(message)));
+	updateBufferedAmount(to_uint16(message->stream), ptrdiff_t(message_size_func(message)));
 	return false;
 }
 
@@ -353,7 +392,7 @@ bool SctpTransport::flush() {
 }
 
 void SctpTransport::closeStream(unsigned int stream) {
-	send(make_message(0, Message::Reset, uint16_t(stream)));
+	send(make_message(0, Message::Reset, to_uint16(stream)));
 }
 
 void SctpTransport::incoming(message_ptr message) {
@@ -458,7 +497,7 @@ bool SctpTransport::trySendQueue() {
 		if (!trySendMessage(message))
 			return false;
 		mSendQueue.pop();
-		updateBufferedAmount(uint16_t(message->stream), -long(message_size_func(message)));
+		updateBufferedAmount(to_uint16(message->stream), -ptrdiff_t(message_size_func(message)));
 	}
 	return true;
 }
@@ -511,12 +550,12 @@ bool SctpTransport::trySendMessage(message_ptr message) {
 	case Reliability::Type::Rexmit:
 		spa.sendv_flags |= SCTP_SEND_PRINFO_VALID;
 		spa.sendv_prinfo.pr_policy = SCTP_PR_SCTP_RTX;
-		spa.sendv_prinfo.pr_value = uint32_t(std::get<int>(reliability.rexmit));
+		spa.sendv_prinfo.pr_value = to_uint32(std::get<int>(reliability.rexmit));
 		break;
 	case Reliability::Type::Timed:
 		spa.sendv_flags |= SCTP_SEND_PRINFO_VALID;
 		spa.sendv_prinfo.pr_policy = SCTP_PR_SCTP_TTL;
-		spa.sendv_prinfo.pr_value = uint32_t(std::get<milliseconds>(reliability.rexmit).count());
+		spa.sendv_prinfo.pr_value = to_uint32(std::get<milliseconds>(reliability.rexmit).count());
 		break;
 	default:
 		spa.sendv_prinfo.pr_policy = SCTP_PR_SCTP_NONE;
@@ -548,10 +587,10 @@ bool SctpTransport::trySendMessage(message_ptr message) {
 	return true;
 }
 
-void SctpTransport::updateBufferedAmount(uint16_t streamId, long delta) {
+void SctpTransport::updateBufferedAmount(uint16_t streamId, ptrdiff_t delta) {
 	// Requires mSendMutex to be locked
 	auto it = mBufferedAmount.insert(std::make_pair(streamId, 0)).first;
-	size_t amount = size_t(std::max(long(it->second) + delta, long(0)));
+	size_t amount = size_t(std::max(ptrdiff_t(it->second) + delta, ptrdiff_t(0)));
 	if (amount == 0)
 		mBufferedAmount.erase(it);
 	else

+ 2 - 1
src/impl/sctptransport.hpp

@@ -39,6 +39,7 @@ namespace rtc::impl {
 class SctpTransport final : public Transport {
 public:
 	static void Init();
+	static void SetSettings(const SctpSettings &s);
 	static void Cleanup();
 
 	using amount_callback = std::function<void(uint16_t streamId, size_t amount)>;
@@ -83,7 +84,7 @@ private:
 	void doFlush();
 	bool trySendQueue();
 	bool trySendMessage(message_ptr message);
-	void updateBufferedAmount(uint16_t streamId, long delta);
+	void updateBufferedAmount(uint16_t streamId, ptrdiff_t delta);
 	void triggerBufferedAmount(uint16_t streamId, size_t amount);
 	void sendReset(uint16_t streamId);
 

+ 11 - 1
src/init.cpp

@@ -92,6 +92,7 @@ void doCleanup() {
 weak_ptr<void> Init::Weak;
 shared_ptr<void> *Init::Global = nullptr;
 bool Init::Initialized = false;
+SctpSettings Init::CurrentSctpSettings = {};
 std::recursive_mutex Init::Mutex;
 
 init_token Init::Token() {
@@ -118,10 +119,19 @@ void Init::Cleanup() {
 	Global = nullptr;
 }
 
+void Init::SetSctpSettings(SctpSettings s) {
+	auto token = Token();
+	std::unique_lock lock(Mutex);
+	impl::SctpTransport::SetSettings(s);
+	CurrentSctpSettings = std::move(s); // store for next init
+}
+
 Init::Init() {
 	// Mutex is locked by Token() here
-	if (!std::exchange(Initialized, true))
+	if (!std::exchange(Initialized, true)) {
 		doInit();
+		impl::SctpTransport::SetSettings(CurrentSctpSettings);
+	}
 }
 
 Init::~Init() {