|
@@ -9,6 +9,7 @@
|
|
|
#include "dtlstransport.hpp"
|
|
|
#include "icetransport.hpp"
|
|
|
#include "internals.hpp"
|
|
|
+#include "threadpool.hpp"
|
|
|
|
|
|
#include <algorithm>
|
|
|
#include <chrono>
|
|
@@ -27,6 +28,16 @@ using namespace std::chrono;
|
|
|
|
|
|
namespace rtc::impl {
|
|
|
|
|
|
+void DtlsTransport::enqueueRecv() {
|
|
|
+ if (mPendingRecvCount > 0)
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (auto shared_this = weak_from_this().lock()) {
|
|
|
+ ++mPendingRecvCount;
|
|
|
+ ThreadPool::Instance().enqueue(&DtlsTransport::doRecv, std::move(shared_this));
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
#if USE_GNUTLS
|
|
|
|
|
|
void DtlsTransport::Init() {
|
|
@@ -50,7 +61,8 @@ DtlsTransport::DtlsTransport(shared_ptr<IceTransport> lower, certificate_ptr cer
|
|
|
gnutls_certificate_credentials_t creds = mCertificate->credentials();
|
|
|
gnutls_certificate_set_verify_function(creds, CertificateCallback);
|
|
|
|
|
|
- unsigned int flags = GNUTLS_DATAGRAM | (mIsClient ? GNUTLS_CLIENT : GNUTLS_SERVER);
|
|
|
+ unsigned int flags =
|
|
|
+ GNUTLS_DATAGRAM | GNUTLS_NONBLOCK | (mIsClient ? GNUTLS_CLIENT : GNUTLS_SERVER);
|
|
|
gnutls::check(gnutls_init(&mSession, flags));
|
|
|
|
|
|
try {
|
|
@@ -98,22 +110,22 @@ DtlsTransport::~DtlsTransport() {
|
|
|
}
|
|
|
|
|
|
void DtlsTransport::start() {
|
|
|
- if(mStarted.exchange(true))
|
|
|
- return;
|
|
|
-
|
|
|
- PLOG_DEBUG << "Starting DTLS recv thread";
|
|
|
+ PLOG_DEBUG << "Starting DTLS transport";
|
|
|
registerIncoming();
|
|
|
- mRecvThread = std::thread(&DtlsTransport::runRecvLoop, this);
|
|
|
+ changeState(State::Connecting);
|
|
|
+
|
|
|
+ size_t mtu = mMtu.value_or(DEFAULT_MTU) - 8 - 40; // UDP/IPv6
|
|
|
+ gnutls_dtls_set_mtu(mSession, static_cast<unsigned int>(mtu));
|
|
|
+ PLOG_VERBOSE << "DTLS MTU set to " << mtu;
|
|
|
+
|
|
|
+ enqueueRecv(); // to initiate the handshake
|
|
|
}
|
|
|
|
|
|
void DtlsTransport::stop() {
|
|
|
- if(!mStarted.exchange(false))
|
|
|
- return;
|
|
|
-
|
|
|
- PLOG_DEBUG << "Stopping DTLS recv thread";
|
|
|
+ PLOG_DEBUG << "Stopping DTLS transport";
|
|
|
unregisterIncoming();
|
|
|
mIncomingQueue.stop();
|
|
|
- mRecvThread.join();
|
|
|
+ enqueueRecv();
|
|
|
}
|
|
|
|
|
|
bool DtlsTransport::send(message_ptr message) {
|
|
@@ -122,7 +134,6 @@ bool DtlsTransport::send(message_ptr message) {
|
|
|
|
|
|
PLOG_VERBOSE << "Send size=" << message->size();
|
|
|
|
|
|
-
|
|
|
ssize_t ret;
|
|
|
do {
|
|
|
std::lock_guard lock(mSendMutex);
|
|
@@ -147,6 +158,7 @@ void DtlsTransport::incoming(message_ptr message) {
|
|
|
|
|
|
PLOG_VERBOSE << "Incoming size=" << message->size();
|
|
|
mIncomingQueue.push(message);
|
|
|
+ enqueueRecv();
|
|
|
}
|
|
|
|
|
|
bool DtlsTransport::outgoing(message_ptr message) {
|
|
@@ -166,79 +178,85 @@ void DtlsTransport::postHandshake() {
|
|
|
// Dummy
|
|
|
}
|
|
|
|
|
|
-void DtlsTransport::runRecvLoop() {
|
|
|
- const size_t bufferSize = 4096;
|
|
|
+void DtlsTransport::doRecv() {
|
|
|
+ std::lock_guard lock(mRecvMutex);
|
|
|
+ --mPendingRecvCount;
|
|
|
|
|
|
- // Handshake loop
|
|
|
- try {
|
|
|
- changeState(State::Connecting);
|
|
|
-
|
|
|
- size_t mtu = mMtu.value_or(DEFAULT_MTU) - 8 - 40; // UDP/IPv6
|
|
|
- gnutls_dtls_set_mtu(mSession, static_cast<unsigned int>(mtu));
|
|
|
- PLOG_VERBOSE << "SSL MTU set to " << mtu;
|
|
|
+ if (state() != State::Connecting && state() != State::Connected)
|
|
|
+ return;
|
|
|
|
|
|
- int ret;
|
|
|
- do {
|
|
|
- ret = gnutls_handshake(mSession);
|
|
|
+ try {
|
|
|
+ const size_t bufferSize = 4096;
|
|
|
+ char buffer[bufferSize];
|
|
|
|
|
|
- if (ret == GNUTLS_E_LARGE_PACKET)
|
|
|
- throw std::runtime_error("MTU is too low");
|
|
|
+ // Handle handshake if connecting
|
|
|
+ if (state() == State::Connecting) {
|
|
|
+ int ret;
|
|
|
+ do {
|
|
|
+ ret = gnutls_handshake(mSession);
|
|
|
+
|
|
|
+ if (ret == GNUTLS_E_AGAIN) {
|
|
|
+ // Schedule next call on timeout and return
|
|
|
+ auto timeout = milliseconds(gnutls_dtls_get_timeout(mSession));
|
|
|
+ ThreadPool::Instance().schedule(timeout, [weak_this = weak_from_this()]() {
|
|
|
+ if (auto locked = weak_this.lock())
|
|
|
+ locked->doRecv();
|
|
|
+ });
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- } while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN ||
|
|
|
- !gnutls::check(ret, "DTLS handshake failed"));
|
|
|
+ if (ret == GNUTLS_E_LARGE_PACKET) {
|
|
|
+ throw std::runtime_error("MTU is too low");
|
|
|
+ }
|
|
|
|
|
|
- // RFC 8261: DTLS MUST support sending messages larger than the current path MTU
|
|
|
- // See https://www.rfc-editor.org/rfc/rfc8261.html#section-5
|
|
|
- gnutls_dtls_set_mtu(mSession, bufferSize + 1);
|
|
|
+ } while (!gnutls::check(ret, "DTLS handshake failed")); // Re-call on non-fatal error
|
|
|
|
|
|
- } catch (const std::exception &e) {
|
|
|
- PLOG_ERROR << "DTLS handshake: " << e.what();
|
|
|
- changeState(State::Failed);
|
|
|
- return;
|
|
|
- }
|
|
|
+ // RFC 8261: DTLS MUST support sending messages larger than the current path MTU
|
|
|
+ // See https://www.rfc-editor.org/rfc/rfc8261.html#section-5
|
|
|
+ gnutls_dtls_set_mtu(mSession, bufferSize + 1);
|
|
|
|
|
|
- // Receive loop
|
|
|
- try {
|
|
|
- PLOG_INFO << "DTLS handshake finished";
|
|
|
- postHandshake();
|
|
|
- changeState(State::Connected);
|
|
|
+ PLOG_INFO << "DTLS handshake finished";
|
|
|
+ changeState(State::Connected);
|
|
|
+ postHandshake();
|
|
|
+ }
|
|
|
|
|
|
- char buffer[bufferSize];
|
|
|
+ if (state() == State::Connected) {
|
|
|
+ while (true) {
|
|
|
+ ssize_t ret = gnutls_record_recv(mSession, buffer, bufferSize);
|
|
|
|
|
|
- while (true) {
|
|
|
- ssize_t ret;
|
|
|
- do {
|
|
|
- ret = gnutls_record_recv(mSession, buffer, bufferSize);
|
|
|
- } while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN);
|
|
|
-
|
|
|
- // RFC 8827: Implementations MUST NOT implement DTLS renegotiation and MUST reject it
|
|
|
- // with a "no_renegotiation" alert if offered.
|
|
|
- // See https://www.rfc-editor.org/rfc/rfc8827.html#section-6.5
|
|
|
- if (ret == GNUTLS_E_REHANDSHAKE) {
|
|
|
- do {
|
|
|
- std::lock_guard lock(mSendMutex);
|
|
|
- ret = gnutls_alert_send(mSession, GNUTLS_AL_WARNING, GNUTLS_A_NO_RENEGOTIATION);
|
|
|
- } while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN);
|
|
|
- continue;
|
|
|
- }
|
|
|
+ if (ret == GNUTLS_E_AGAIN) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- // Consider premature termination as remote closing
|
|
|
- if (ret == GNUTLS_E_PREMATURE_TERMINATION) {
|
|
|
- PLOG_DEBUG << "DTLS connection terminated";
|
|
|
- break;
|
|
|
- }
|
|
|
+ // RFC 8827: Implementations MUST NOT implement DTLS renegotiation and MUST reject
|
|
|
+ // it with a "no_renegotiation" alert if offered. See
|
|
|
+ // https://www.rfc-editor.org/rfc/rfc8827.html#section-6.5
|
|
|
+ if (ret == GNUTLS_E_REHANDSHAKE) {
|
|
|
+ do {
|
|
|
+ std::lock_guard lock(mSendMutex);
|
|
|
+ ret = gnutls_alert_send(mSession, GNUTLS_AL_WARNING,
|
|
|
+ GNUTLS_A_NO_RENEGOTIATION);
|
|
|
+ } while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
|
|
|
- if (gnutls::check(ret)) {
|
|
|
- if (ret == 0) {
|
|
|
- // Closed
|
|
|
- PLOG_DEBUG << "DTLS connection cleanly closed";
|
|
|
+ // Consider premature termination as remote closing
|
|
|
+ if (ret == GNUTLS_E_PREMATURE_TERMINATION) {
|
|
|
+ PLOG_DEBUG << "DTLS connection terminated";
|
|
|
break;
|
|
|
}
|
|
|
- auto *b = reinterpret_cast<byte *>(buffer);
|
|
|
- recv(make_message(b, b + ret));
|
|
|
+
|
|
|
+ if (gnutls::check(ret)) {
|
|
|
+ if (ret == 0) {
|
|
|
+ // Closed
|
|
|
+ PLOG_DEBUG << "DTLS connection cleanly closed";
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ auto *b = reinterpret_cast<byte *>(buffer);
|
|
|
+ recv(make_message(b, b + ret));
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
} catch (const std::exception &e) {
|
|
|
PLOG_ERROR << "DTLS recv: " << e.what();
|
|
|
}
|
|
@@ -303,7 +321,13 @@ ssize_t DtlsTransport::WriteCallback(gnutls_transport_ptr_t ptr, const void *dat
|
|
|
ssize_t DtlsTransport::ReadCallback(gnutls_transport_ptr_t ptr, void *data, size_t maxlen) {
|
|
|
DtlsTransport *t = static_cast<DtlsTransport *>(ptr);
|
|
|
try {
|
|
|
- while (auto next = t->mIncomingQueue.pop()) {
|
|
|
+ while (t->mIncomingQueue.running()) {
|
|
|
+ auto next = t->mIncomingQueue.pop();
|
|
|
+ if (!next) {
|
|
|
+ gnutls_transport_set_errno(t->mSession, EAGAIN);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
message_ptr message = std::move(*next);
|
|
|
if (t->demuxMessage(message))
|
|
|
continue;
|
|
@@ -325,12 +349,10 @@ ssize_t DtlsTransport::ReadCallback(gnutls_transport_ptr_t ptr, void *data, size
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-int DtlsTransport::TimeoutCallback(gnutls_transport_ptr_t ptr, unsigned int ms) {
|
|
|
+int DtlsTransport::TimeoutCallback(gnutls_transport_ptr_t ptr, unsigned int /* ms */) {
|
|
|
DtlsTransport *t = static_cast<DtlsTransport *>(ptr);
|
|
|
try {
|
|
|
- bool isReadable = t->mIncomingQueue.wait(
|
|
|
- ms != GNUTLS_INDEFINITE_TIMEOUT ? std::make_optional(milliseconds(ms)) : nullopt);
|
|
|
- return isReadable ? 1 : 0;
|
|
|
+ return !t->mIncomingQueue.empty() ? 1 : 0;
|
|
|
|
|
|
} catch (const std::exception &e) {
|
|
|
PLOG_WARNING << e.what();
|
|
@@ -438,11 +460,13 @@ DtlsTransport::DtlsTransport(shared_ptr<IceTransport> lower, certificate_ptr cer
|
|
|
// See https://www.rfc-editor.org/rfc/rfc8827.html#section-6.5 Warning:
|
|
|
// SSL_set_tlsext_use_srtp() returns 0 on success and 1 on error
|
|
|
// Try to use GCM suite
|
|
|
- if (SSL_set_tlsext_use_srtp(mSsl, "SRTP_AEAD_AES_256_GCM:SRTP_AEAD_AES_128_GCM:SRTP_AES128_CM_SHA1_80")) {
|
|
|
+ if (SSL_set_tlsext_use_srtp(
|
|
|
+ mSsl, "SRTP_AEAD_AES_256_GCM:SRTP_AEAD_AES_128_GCM:SRTP_AES128_CM_SHA1_80")) {
|
|
|
if (SSL_set_tlsext_use_srtp(mSsl, "SRTP_AES128_CM_SHA1_80"))
|
|
|
throw std::runtime_error("Failed to set SRTP profile: " +
|
|
|
- openssl::error_string(ERR_get_error()));
|
|
|
+ openssl::error_string(ERR_get_error()));
|
|
|
}
|
|
|
+
|
|
|
} catch (...) {
|
|
|
if (mSsl)
|
|
|
SSL_free(mSsl);
|
|
@@ -465,23 +489,26 @@ DtlsTransport::~DtlsTransport() {
|
|
|
}
|
|
|
|
|
|
void DtlsTransport::start() {
|
|
|
- if(mStarted.exchange(true))
|
|
|
- return;
|
|
|
-
|
|
|
- PLOG_DEBUG << "Starting DTLS recv thread";
|
|
|
+ PLOG_DEBUG << "Starting DTLS transport";
|
|
|
registerIncoming();
|
|
|
- mRecvThread = std::thread(&DtlsTransport::runRecvLoop, this);
|
|
|
+ changeState(State::Connecting);
|
|
|
+
|
|
|
+ size_t mtu = mMtu.value_or(DEFAULT_MTU) - 8 - 40; // UDP/IPv6
|
|
|
+ SSL_set_mtu(mSsl, static_cast<unsigned int>(mtu));
|
|
|
+ PLOG_VERBOSE << "DTLS MTU set to " << mtu;
|
|
|
+
|
|
|
+ // Initiate the handshake
|
|
|
+ int ret = SSL_do_handshake(mSsl);
|
|
|
+ openssl::check(mSsl, ret, "Handshake initiation failed");
|
|
|
+
|
|
|
+ handleTimeout();
|
|
|
}
|
|
|
|
|
|
void DtlsTransport::stop() {
|
|
|
- if(!mStarted.exchange(false))
|
|
|
- return;
|
|
|
-
|
|
|
- PLOG_DEBUG << "Stopping DTLS recv thread";
|
|
|
+ PLOG_DEBUG << "Stopping DTLS transport";
|
|
|
unregisterIncoming();
|
|
|
mIncomingQueue.stop();
|
|
|
- mRecvThread.join();
|
|
|
- SSL_shutdown(mSsl);
|
|
|
+ enqueueRecv();
|
|
|
}
|
|
|
|
|
|
bool DtlsTransport::send(message_ptr message) {
|
|
@@ -501,11 +528,13 @@ bool DtlsTransport::send(message_ptr message) {
|
|
|
void DtlsTransport::incoming(message_ptr message) {
|
|
|
if (!message) {
|
|
|
mIncomingQueue.stop();
|
|
|
+ enqueueRecv();
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
PLOG_VERBOSE << "Incoming size=" << message->size();
|
|
|
mIncomingQueue.push(message);
|
|
|
+ enqueueRecv();
|
|
|
}
|
|
|
|
|
|
bool DtlsTransport::outgoing(message_ptr message) {
|
|
@@ -525,86 +554,65 @@ void DtlsTransport::postHandshake() {
|
|
|
// Dummy
|
|
|
}
|
|
|
|
|
|
-void DtlsTransport::runRecvLoop() {
|
|
|
- const size_t bufferSize = 4096;
|
|
|
- try {
|
|
|
- changeState(State::Connecting);
|
|
|
-
|
|
|
- size_t mtu = mMtu.value_or(DEFAULT_MTU) - 8 - 40; // UDP/IPv6
|
|
|
- SSL_set_mtu(mSsl, static_cast<unsigned int>(mtu));
|
|
|
- PLOG_VERBOSE << "SSL MTU set to " << mtu;
|
|
|
+void DtlsTransport::doRecv() {
|
|
|
+ std::lock_guard lock(mRecvMutex);
|
|
|
+ --mPendingRecvCount;
|
|
|
|
|
|
- // Initiate the handshake
|
|
|
- int ret = SSL_do_handshake(mSsl);
|
|
|
- openssl::check(mSsl, ret, "Handshake failed");
|
|
|
+ if (state() != State::Connecting && state() != State::Connected)
|
|
|
+ return;
|
|
|
|
|
|
+ try {
|
|
|
+ const size_t bufferSize = 4096;
|
|
|
byte buffer[bufferSize];
|
|
|
+
|
|
|
+ // Process pending messages
|
|
|
while (mIncomingQueue.running()) {
|
|
|
- // Process pending messages
|
|
|
- while (auto next = mIncomingQueue.tryPop()) {
|
|
|
- message_ptr message = std::move(*next);
|
|
|
- if (demuxMessage(message))
|
|
|
- continue;
|
|
|
+ auto next = mIncomingQueue.pop();
|
|
|
+ if (!next) {
|
|
|
+ // No more messages pending, handle timeout if connecting
|
|
|
+ if (state() == State::Connecting)
|
|
|
+ handleTimeout();
|
|
|
|
|
|
- BIO_write(mInBio, message->data(), int(message->size()));
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- if (state() == State::Connecting) {
|
|
|
- // Continue the handshake
|
|
|
- ret = SSL_do_handshake(mSsl);
|
|
|
- if (!openssl::check(mSsl, ret, "Handshake failed"))
|
|
|
- break;
|
|
|
+ message_ptr message = std::move(*next);
|
|
|
+ if (demuxMessage(message))
|
|
|
+ continue;
|
|
|
|
|
|
- if (SSL_is_init_finished(mSsl)) {
|
|
|
- // RFC 8261: DTLS MUST support sending messages larger than the current path
|
|
|
- // MTU See https://www.rfc-editor.org/rfc/rfc8261.html#section-5
|
|
|
- SSL_set_mtu(mSsl, bufferSize + 1);
|
|
|
+ BIO_write(mInBio, message->data(), int(message->size()));
|
|
|
|
|
|
- PLOG_INFO << "DTLS handshake finished";
|
|
|
- postHandshake();
|
|
|
- changeState(State::Connected);
|
|
|
- }
|
|
|
- } else {
|
|
|
- ret = SSL_read(mSsl, buffer, bufferSize);
|
|
|
- if (!openssl::check(mSsl, ret))
|
|
|
- break;
|
|
|
+ if (state() == State::Connecting) {
|
|
|
+ // Continue the handshake
|
|
|
+ int ret = SSL_do_handshake(mSsl);
|
|
|
+ if (!openssl::check(mSsl, ret, "Handshake failed"))
|
|
|
+ break;
|
|
|
|
|
|
- if (ret > 0)
|
|
|
- recv(make_message(buffer, buffer + ret));
|
|
|
- }
|
|
|
- }
|
|
|
+ if (SSL_is_init_finished(mSsl)) {
|
|
|
+ // RFC 8261: DTLS MUST support sending messages larger than the current path
|
|
|
+ // MTU See https://www.rfc-editor.org/rfc/rfc8261.html#section-5
|
|
|
+ SSL_set_mtu(mSsl, bufferSize + 1);
|
|
|
|
|
|
- // No more messages pending, retransmit and rearm timeout if connecting
|
|
|
- optional<milliseconds> duration;
|
|
|
- if (state() == State::Connecting) {
|
|
|
- // Warning: This function breaks the usual return value convention
|
|
|
- ret = DTLSv1_handle_timeout(mSsl);
|
|
|
- if (ret < 0) {
|
|
|
- throw std::runtime_error("Handshake timeout"); // write BIO can't fail
|
|
|
- } else if (ret > 0) {
|
|
|
- LOG_VERBOSE << "OpenSSL did DTLS retransmit";
|
|
|
+ PLOG_INFO << "DTLS handshake finished";
|
|
|
+ postHandshake();
|
|
|
+ changeState(State::Connected);
|
|
|
}
|
|
|
+ } else {
|
|
|
+ int ret = SSL_read(mSsl, buffer, bufferSize);
|
|
|
+ if (!openssl::check(mSsl, ret))
|
|
|
+ break;
|
|
|
|
|
|
- struct timeval timeout = {};
|
|
|
- if (state() == State::Connecting && DTLSv1_get_timeout(mSsl, &timeout)) {
|
|
|
- duration = milliseconds(timeout.tv_sec * 1000 + timeout.tv_usec / 1000);
|
|
|
- // Also handle handshake timeout manually because OpenSSL actually doesn't...
|
|
|
- // OpenSSL backs off exponentially in base 2 starting from the recommended 1s
|
|
|
- // so this allows for 5 retransmissions and fails after roughly 30s.
|
|
|
- if (duration > 30s) {
|
|
|
- throw std::runtime_error("Handshake timeout");
|
|
|
- } else {
|
|
|
- LOG_VERBOSE << "OpenSSL DTLS retransmit timeout is " << duration->count()
|
|
|
- << "ms";
|
|
|
- }
|
|
|
- }
|
|
|
+ if (ret > 0)
|
|
|
+ recv(make_message(buffer, buffer + ret));
|
|
|
}
|
|
|
-
|
|
|
- mIncomingQueue.wait(duration);
|
|
|
}
|
|
|
+
|
|
|
} catch (const std::exception &e) {
|
|
|
PLOG_ERROR << "DTLS recv: " << e.what();
|
|
|
}
|
|
|
|
|
|
+ SSL_shutdown(mSsl);
|
|
|
+
|
|
|
if (state() == State::Connected) {
|
|
|
PLOG_INFO << "DTLS closed";
|
|
|
changeState(State::Disconnected);
|
|
@@ -615,6 +623,33 @@ void DtlsTransport::runRecvLoop() {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+void DtlsTransport::handleTimeout() {
|
|
|
+ // Warning: This function breaks the usual return value convention
|
|
|
+ int ret = DTLSv1_handle_timeout(mSsl);
|
|
|
+ if (ret < 0) {
|
|
|
+ throw std::runtime_error("Handshake timeout"); // write BIO can't fail
|
|
|
+ } else if (ret > 0) {
|
|
|
+ LOG_VERBOSE << "DTLS retransmit done";
|
|
|
+ }
|
|
|
+
|
|
|
+ struct timeval tv = {};
|
|
|
+ if (DTLSv1_get_timeout(mSsl, &tv)) {
|
|
|
+ auto timeout = milliseconds(tv.tv_sec * 1000 + tv.tv_usec / 1000);
|
|
|
+ // Also handle handshake timeout manually because OpenSSL actually
|
|
|
+ // doesn't... OpenSSL backs off exponentially in base 2 starting from the
|
|
|
+ // recommended 1s so this allows for 5 retransmissions and fails after
|
|
|
+ // roughly 30s.
|
|
|
+ if (timeout > 30s)
|
|
|
+ throw std::runtime_error("Handshake timeout");
|
|
|
+
|
|
|
+ LOG_VERBOSE << "DTLS retransmit timeout is " << timeout.count() << "ms";
|
|
|
+ ThreadPool::Instance().schedule(timeout, [weak_this = weak_from_this()]() {
|
|
|
+ if (auto locked = weak_this.lock())
|
|
|
+ locked->doRecv();
|
|
|
+ });
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
int DtlsTransport::CertificateCallback(int /*preverify_ok*/, X509_STORE_CTX *ctx) {
|
|
|
SSL *ssl =
|
|
|
static_cast<SSL *>(X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx()));
|