123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804 |
- /**
- * Copyright (c) 2020 Paul-Louis Ageneau
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at https://mozilla.org/MPL/2.0/.
- */
- #include "tlstransport.hpp"
- #include "httpproxytransport.hpp"
- #include "tcptransport.hpp"
- #include "threadpool.hpp"
- #if RTC_ENABLE_WEBSOCKET
- #include <algorithm>
- #include <chrono>
- #include <cstring>
- #include <exception>
- using namespace std::chrono;
- namespace rtc::impl {
- void TlsTransport::enqueueRecv() {
- if (mPendingRecvCount > 0)
- return;
- if (auto shared_this = weak_from_this().lock()) {
- ++mPendingRecvCount;
- ThreadPool::Instance().enqueue(&TlsTransport::doRecv, std::move(shared_this));
- }
- }
- #if USE_GNUTLS
- namespace {
- gnutls_certificate_credentials_t default_certificate_credentials() {
- static std::mutex mutex;
- static shared_ptr<gnutls_certificate_credentials_t> creds;
- std::lock_guard lock(mutex);
- if (!creds) {
- creds = shared_ptr<gnutls_certificate_credentials_t>(gnutls::new_credentials(),
- gnutls::free_credentials);
- gnutls::check(gnutls_certificate_set_x509_system_trust(*creds));
- }
- return *creds;
- }
- } // namespace
- void TlsTransport::Init() {
- // Nothing to do
- }
- void TlsTransport::Cleanup() {
- // Nothing to do
- }
- TlsTransport::TlsTransport(variant<shared_ptr<TcpTransport>, shared_ptr<HttpProxyTransport>> lower,
- optional<string> host, certificate_ptr certificate,
- state_callback callback)
- : Transport(std::visit([](auto l) { return std::static_pointer_cast<Transport>(l); }, lower),
- std::move(callback)),
- mHost(std::move(host)), mIsClient(std::visit([](auto l) { return l->isActive(); }, lower)),
- mIncomingQueue(RECV_QUEUE_LIMIT, message_size_func) {
- PLOG_DEBUG << "Initializing TLS transport (GnuTLS)";
- unsigned int flags = GNUTLS_NONBLOCK | (mIsClient ? GNUTLS_CLIENT : GNUTLS_SERVER);
- gnutls::check(gnutls_init(&mSession, flags));
- try {
- const char *priorities = "SECURE128:-VERS-SSL3.0:-ARCFOUR-128";
- const char *err_pos = NULL;
- gnutls::check(gnutls_priority_set_direct(mSession, priorities, &err_pos),
- "Failed to set TLS priorities");
- gnutls::check(gnutls_credentials_set(mSession, GNUTLS_CRD_CERTIFICATE,
- certificate ? certificate->credentials()
- : default_certificate_credentials()));
- if (mIsClient && mHost) {
- PLOG_VERBOSE << "Server Name Indication: " << *mHost;
- gnutls_server_name_set(mSession, GNUTLS_NAME_DNS, mHost->data(), mHost->size());
- }
- gnutls_session_set_ptr(mSession, this);
- gnutls_transport_set_ptr(mSession, this);
- gnutls_transport_set_push_function(mSession, WriteCallback);
- gnutls_transport_set_pull_function(mSession, ReadCallback);
- gnutls_transport_set_pull_timeout_function(mSession, TimeoutCallback);
- } catch (...) {
- gnutls_deinit(mSession);
- throw;
- }
- }
- TlsTransport::~TlsTransport() {
- stop();
- gnutls_deinit(mSession);
- }
- void TlsTransport::start() {
- PLOG_DEBUG << "Starting TLS transport";
- registerIncoming();
- changeState(State::Connecting);
- enqueueRecv(); // to initiate the handshake
- }
- void TlsTransport::stop() {
- PLOG_DEBUG << "Stopping TLS transport";
- unregisterIncoming();
- mIncomingQueue.stop();
- enqueueRecv();
- }
- bool TlsTransport::send(message_ptr message) {
- if (state() != State::Connected)
- throw std::runtime_error("TLS is not open");
- if (!message || message->size() == 0)
- return outgoing(message); // pass through
- PLOG_VERBOSE << "Send size=" << message->size();
- ssize_t ret;
- do {
- ret = gnutls_record_send(mSession, message->data(), message->size());
- } while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN);
- if (!gnutls::check(ret))
- throw std::runtime_error("TLS send failed");
- return mOutgoingResult;
- }
- void TlsTransport::incoming(message_ptr message) {
- if (!message) {
- mIncomingQueue.stop();
- enqueueRecv();
- return;
- }
- PLOG_VERBOSE << "Incoming size=" << message->size();
- mIncomingQueue.push(message);
- enqueueRecv();
- }
- bool TlsTransport::outgoing(message_ptr message) {
- bool result = Transport::outgoing(std::move(message));
- mOutgoingResult = result;
- return result;
- }
- void TlsTransport::postHandshake() {
- // Dummy
- }
- void TlsTransport::doRecv() {
- std::lock_guard lock(mRecvMutex);
- --mPendingRecvCount;
- const size_t bufferSize = 4096;
- char buffer[bufferSize];
- try {
- // Handle handshake if connecting
- if (state() == State::Connecting) {
- int ret;
- do {
- ret = gnutls_handshake(mSession);
- if (ret == GNUTLS_E_AGAIN)
- return;
- } while (!gnutls::check(ret, "Handshake failed")); // Re-call on non-fatal error
- PLOG_INFO << "TLS handshake finished";
- changeState(State::Connected);
- postHandshake();
- }
- if (state() == State::Connected) {
- while (true) {
- ssize_t ret = gnutls_record_recv(mSession, buffer, bufferSize);
- if (ret == GNUTLS_E_AGAIN)
- return;
- // Consider premature termination as remote closing
- if (ret == GNUTLS_E_PREMATURE_TERMINATION) {
- PLOG_DEBUG << "TLS connection terminated";
- break;
- }
- if (gnutls::check(ret)) {
- if (ret == 0) {
- // Closed
- PLOG_DEBUG << "TLS connection cleanly closed";
- break;
- }
- auto *b = reinterpret_cast<byte *>(buffer);
- recv(make_message(b, b + ret));
- }
- }
- }
- } catch (const std::exception &e) {
- PLOG_ERROR << "TLS recv: " << e.what();
- }
- gnutls_bye(mSession, GNUTLS_SHUT_WR);
- if (state() == State::Connected) {
- PLOG_INFO << "TLS closed";
- changeState(State::Disconnected);
- recv(nullptr);
- } else {
- PLOG_ERROR << "TLS handshake failed";
- changeState(State::Failed);
- }
- }
- ssize_t TlsTransport::WriteCallback(gnutls_transport_ptr_t ptr, const void *data, size_t len) {
- TlsTransport *t = static_cast<TlsTransport *>(ptr);
- try {
- if (len > 0) {
- auto b = reinterpret_cast<const byte *>(data);
- t->outgoing(make_message(b, b + len));
- }
- gnutls_transport_set_errno(t->mSession, 0);
- return ssize_t(len);
- } catch (const std::exception &e) {
- PLOG_WARNING << e.what();
- gnutls_transport_set_errno(t->mSession, ECONNRESET);
- return -1;
- }
- }
- ssize_t TlsTransport::ReadCallback(gnutls_transport_ptr_t ptr, void *data, size_t maxlen) {
- TlsTransport *t = static_cast<TlsTransport *>(ptr);
- try {
- message_ptr &message = t->mIncomingMessage;
- size_t &position = t->mIncomingMessagePosition;
- if (message && position >= message->size())
- message.reset();
- if (!message) {
- position = 0;
- while (auto next = t->mIncomingQueue.pop()) {
- message = *next;
- if (message->size() > 0)
- break;
- else
- t->recv(message); // Pass zero-sized messages through
- }
- }
- if (message) {
- size_t available = message->size() - position;
- ssize_t len = std::min(maxlen, available);
- std::memcpy(data, message->data() + position, len);
- position += len;
- gnutls_transport_set_errno(t->mSession, 0);
- return len;
- } else if (t->mIncomingQueue.running()) {
- gnutls_transport_set_errno(t->mSession, EAGAIN);
- return -1;
- } else {
- // Closed
- gnutls_transport_set_errno(t->mSession, 0);
- return 0;
- }
- } catch (const std::exception &e) {
- PLOG_WARNING << e.what();
- gnutls_transport_set_errno(t->mSession, ECONNRESET);
- return -1;
- }
- }
- int TlsTransport::TimeoutCallback(gnutls_transport_ptr_t ptr, unsigned int /* ms */) {
- TlsTransport *t = static_cast<TlsTransport *>(ptr);
- try {
- message_ptr &message = t->mIncomingMessage;
- size_t &position = t->mIncomingMessagePosition;
- if (message && position < message->size())
- return 1;
- return !t->mIncomingQueue.empty() ? 1 : 0;
- } catch (const std::exception &e) {
- PLOG_WARNING << e.what();
- return 1;
- }
- }
- #elif USE_MBEDTLS
- void TlsTransport::Init() {
- // Nothing to do
- }
- void TlsTransport::Cleanup() {
- // Nothing to do
- }
- TlsTransport::TlsTransport(variant<shared_ptr<TcpTransport>, shared_ptr<HttpProxyTransport>> lower,
- optional<string> host, certificate_ptr certificate,
- state_callback callback)
- : Transport(std::visit([](auto l) { return std::static_pointer_cast<Transport>(l); }, lower),
- std::move(callback)),
- mHost(std::move(host)), mIsClient(std::visit([](auto l) { return l->isActive(); }, lower)),
- mIncomingQueue(RECV_QUEUE_LIMIT, message_size_func) {
- PLOG_DEBUG << "Initializing TLS transport (MbedTLS)";
- mbedtls_entropy_init(&mEntropy);
- mbedtls_ctr_drbg_init(&mDrbg);
- mbedtls_ssl_init(&mSsl);
- mbedtls_ssl_config_init(&mConf);
- mbedtls_ctr_drbg_set_prediction_resistance(&mDrbg, MBEDTLS_CTR_DRBG_PR_ON);
- try {
- mbedtls::check(mbedtls_ctr_drbg_seed(&mDrbg, mbedtls_entropy_func, &mEntropy, NULL, 0));
- mbedtls::check(mbedtls_ssl_config_defaults(
- &mConf, mIsClient ? MBEDTLS_SSL_IS_CLIENT : MBEDTLS_SSL_IS_SERVER,
- MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT));
- mbedtls_ssl_conf_authmode(&mConf, MBEDTLS_SSL_VERIFY_OPTIONAL);
- mbedtls_ssl_conf_rng(&mConf, mbedtls_ctr_drbg_random, &mDrbg);
- if (certificate) {
- auto [crt, pk] = certificate->credentials();
- mbedtls::check(mbedtls_ssl_conf_own_cert(&mConf, crt.get(), pk.get()));
- }
- mbedtls::check(mbedtls_ssl_setup(&mSsl, &mConf));
- mbedtls_ssl_set_bio(&mSsl, static_cast<void *>(this), WriteCallback, ReadCallback, NULL);
- } catch (...) {
- mbedtls_entropy_free(&mEntropy);
- mbedtls_ctr_drbg_free(&mDrbg);
- mbedtls_ssl_free(&mSsl);
- mbedtls_ssl_config_free(&mConf);
- throw;
- }
- }
- TlsTransport::~TlsTransport() {}
- void TlsTransport::start() {
- PLOG_DEBUG << "Starting TLS transport";
- registerIncoming();
- changeState(State::Connecting);
- enqueueRecv(); // to initiate the handshake
- }
- void TlsTransport::stop() {
- PLOG_DEBUG << "Stopping TLS transport";
- unregisterIncoming();
- mIncomingQueue.stop();
- enqueueRecv();
- }
- bool TlsTransport::send(message_ptr message) {
- if (state() != State::Connected)
- throw std::runtime_error("TLS is not open");
- if (!message || message->size() == 0)
- return outgoing(message); // pass through
- PLOG_VERBOSE << "Send size=" << message->size();
- int ret;
- do {
- std::lock_guard lock(mSslMutex);
- ret = mbedtls_ssl_write(&mSsl, reinterpret_cast<const unsigned char *>(message->data()),
- int(message->size()));
- } while (ret == MBEDTLS_ERR_SSL_WANT_WRITE);
- mbedtls::check(ret);
- return mOutgoingResult;
- }
- void TlsTransport::incoming(message_ptr message) {
- if (!message) {
- mIncomingQueue.stop();
- enqueueRecv();
- return;
- }
- PLOG_VERBOSE << "Incoming size=" << message->size();
- mIncomingQueue.push(message);
- enqueueRecv();
- }
- bool TlsTransport::outgoing(message_ptr message) {
- bool result = Transport::outgoing(std::move(message));
- mOutgoingResult = result;
- return result;
- }
- void TlsTransport::postHandshake() {
- // Dummy
- }
- void TlsTransport::doRecv() {
- std::lock_guard lock(mRecvMutex);
- --mPendingRecvCount;
- if (state() != State::Connecting && state() != State::Connected)
- return;
- try {
- const size_t bufferSize = 4096;
- char buffer[bufferSize];
- // Handle handshake if connecting
- if (state() == State::Connecting) {
- while (true) {
- int ret;
- {
- std::lock_guard lock(mSslMutex);
- ret = mbedtls_ssl_handshake(&mSsl);
- }
- if (ret == MBEDTLS_ERR_SSL_WANT_READ) {
- return;
- }
- if (mbedtls::check(ret, "Handshake failed")) {
- PLOG_INFO << "TLS handshake finished";
- changeState(State::Connected);
- postHandshake();
- break;
- }
- }
- }
- if (state() == State::Connected) {
- while (true) {
- int ret;
- {
- std::lock_guard lock(mSslMutex);
- ret = mbedtls_ssl_read(&mSsl, reinterpret_cast<unsigned char *>(buffer),
- bufferSize);
- }
- if (ret == MBEDTLS_ERR_SSL_WANT_READ) {
- return;
- }
- if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) {
- PLOG_DEBUG << "TLS connection cleanly closed";
- break;
- }
- if (mbedtls::check(ret)) {
- if (ret == 0) {
- PLOG_DEBUG << "TLS connection terminated";
- break;
- }
- auto *b = reinterpret_cast<byte *>(buffer);
- recv(make_message(b, b + ret));
- }
- }
- }
- } catch (const std::exception &e) {
- PLOG_ERROR << "TLS recv: " << e.what();
- }
- if (state() == State::Connected) {
- PLOG_INFO << "TLS closed";
- changeState(State::Disconnected);
- recv(nullptr);
- } else {
- PLOG_ERROR << "TLS handshake failed";
- changeState(State::Failed);
- }
- }
- int TlsTransport::WriteCallback(void *ctx, const unsigned char *buf, size_t len) {
- auto *t = static_cast<TlsTransport *>(ctx);
- auto *b = reinterpret_cast<const byte *>(buf);
- t->outgoing(make_message(b, b + len));
- return int(len);
- }
- int TlsTransport::ReadCallback(void *ctx, unsigned char *buf, size_t len) {
- TlsTransport *t = static_cast<TlsTransport *>(ctx);
- try {
- message_ptr &message = t->mIncomingMessage;
- size_t &position = t->mIncomingMessagePosition;
- if (message && position >= message->size())
- message.reset();
- if (!message) {
- position = 0;
- while (auto next = t->mIncomingQueue.pop()) {
- message = *next;
- if (message->size() > 0)
- break;
- else
- t->recv(message); // Pass zero-sized messages through
- }
- }
- if (message) {
- size_t available = message->size() - position;
- size_t writeLen = std::min(len, available);
- std::memcpy(buf, message->data() + position, writeLen);
- position += writeLen;
- return int(writeLen);
- } else if (t->mIncomingQueue.running()) {
- return MBEDTLS_ERR_SSL_WANT_READ;
- } else {
- return MBEDTLS_ERR_SSL_CONN_EOF;
- }
- } catch (const std::exception &e) {
- PLOG_WARNING << e.what();
- return MBEDTLS_ERR_SSL_INTERNAL_ERROR;
- }
- }
- #else
- int TlsTransport::TransportExIndex = -1;
- void TlsTransport::Init() {
- openssl::init();
- if (TransportExIndex < 0) {
- TransportExIndex = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL);
- }
- }
- void TlsTransport::Cleanup() {
- // Nothing to do
- }
- TlsTransport::TlsTransport(variant<shared_ptr<TcpTransport>, shared_ptr<HttpProxyTransport>> lower,
- optional<string> host, certificate_ptr certificate,
- state_callback callback)
- : Transport(std::visit([](auto l) { return std::static_pointer_cast<Transport>(l); }, lower),
- std::move(callback)),
- mHost(std::move(host)), mIsClient(std::visit([](auto l) { return l->isActive(); }, lower)),
- mIncomingQueue(RECV_QUEUE_LIMIT, message_size_func) {
- PLOG_DEBUG << "Initializing TLS transport (OpenSSL)";
- try {
- if (!(mCtx = SSL_CTX_new(SSLv23_method()))) // version-flexible
- throw std::runtime_error("Failed to create SSL context");
- openssl::check(SSL_CTX_set_cipher_list(mCtx, "ALL:!LOW:!EXP:!RC4:!MD5:@STRENGTH"),
- "Failed to set SSL priorities");
- #if OPENSSL_VERSION_NUMBER >= 0x30000000
- openssl::check(SSL_CTX_set1_groups_list(mCtx, "P-256"), "Failed to set SSL groups");
- #else
- auto ecdh = unique_ptr<EC_KEY, decltype(&EC_KEY_free)>(
- EC_KEY_new_by_curve_name(NID_X9_62_prime256v1), EC_KEY_free);
- SSL_CTX_set_tmp_ecdh(mCtx, ecdh.get());
- SSL_CTX_set_options(mCtx, SSL_OP_SINGLE_ECDH_USE);
- #endif
- if (certificate) {
- auto [x509, pkey] = certificate->credentials();
- SSL_CTX_use_certificate(mCtx, x509);
- SSL_CTX_use_PrivateKey(mCtx, pkey);
- } else {
- if (!SSL_CTX_set_default_verify_paths(mCtx)) {
- PLOG_WARNING << "SSL root CA certificates unavailable";
- }
- }
- SSL_CTX_set_options(mCtx, SSL_OP_NO_SSLv3);
- SSL_CTX_set_min_proto_version(mCtx, TLS1_VERSION);
- SSL_CTX_set_read_ahead(mCtx, 1);
- SSL_CTX_set_quiet_shutdown(mCtx, 1);
- SSL_CTX_set_info_callback(mCtx, InfoCallback);
- SSL_CTX_set_verify(mCtx, SSL_VERIFY_NONE, NULL);
- if (!(mSsl = SSL_new(mCtx)))
- throw std::runtime_error("Failed to create SSL instance");
- SSL_set_ex_data(mSsl, TransportExIndex, this);
- if (mIsClient && mHost) {
- SSL_set_hostflags(mSsl, 0);
- openssl::check(SSL_set1_host(mSsl, mHost->c_str()), "Failed to set SSL host");
- PLOG_VERBOSE << "Server Name Indication: " << *mHost;
- SSL_set_tlsext_host_name(mSsl, mHost->c_str());
- }
- if (mIsClient)
- SSL_set_connect_state(mSsl);
- else
- SSL_set_accept_state(mSsl);
- if (!(mInBio = BIO_new(BIO_s_mem())) || !(mOutBio = BIO_new(BIO_s_mem())))
- throw std::runtime_error("Failed to create BIO");
- BIO_set_mem_eof_return(mInBio, BIO_EOF);
- BIO_set_mem_eof_return(mOutBio, BIO_EOF);
- SSL_set_bio(mSsl, mInBio, mOutBio);
- } catch (...) {
- if (mSsl)
- SSL_free(mSsl);
- if (mCtx)
- SSL_CTX_free(mCtx);
- throw;
- }
- }
- TlsTransport::~TlsTransport() {
- stop();
- SSL_free(mSsl);
- SSL_CTX_free(mCtx);
- }
- void TlsTransport::start() {
- PLOG_DEBUG << "Starting TLS transport";
- registerIncoming();
- changeState(State::Connecting);
- // Initiate the handshake
- std::lock_guard lock(mSslMutex);
- int ret = SSL_do_handshake(mSsl);
- openssl::check(mSsl, ret, "Handshake initiation failed");
- flushOutput();
- }
- void TlsTransport::stop() {
- PLOG_DEBUG << "Stopping TLS transport";
- unregisterIncoming();
- mIncomingQueue.stop();
- enqueueRecv();
- }
- bool TlsTransport::send(message_ptr message) {
- if (state() != State::Connected)
- throw std::runtime_error("TLS is not open");
- if (!message || message->size() == 0)
- return outgoing(message); // pass through
- PLOG_VERBOSE << "Send size=" << message->size();
- std::lock_guard lock(mSslMutex);
- int ret = SSL_write(mSsl, message->data(), int(message->size()));
- if (!openssl::check(mSsl, ret))
- throw std::runtime_error("TLS send failed");
- return flushOutput();
- }
- void TlsTransport::incoming(message_ptr message) {
- if (!message) {
- mIncomingQueue.stop();
- enqueueRecv();
- return;
- }
- PLOG_VERBOSE << "Incoming size=" << message->size();
- mIncomingQueue.push(message);
- enqueueRecv();
- }
- bool TlsTransport::outgoing(message_ptr message) { return Transport::outgoing(std::move(message)); }
- void TlsTransport::postHandshake() {
- // Dummy
- }
- void TlsTransport::doRecv() {
- std::lock_guard lock(mRecvMutex);
- --mPendingRecvCount;
- if (state() != State::Connecting && state() != State::Connected)
- return;
- try {
- const size_t bufferSize = 4096;
- byte buffer[bufferSize];
- // Process incoming messages
- while (mIncomingQueue.running()) {
- auto next = mIncomingQueue.pop();
- if (!next)
- return;
- message_ptr message = std::move(*next);
- if (message->size() > 0)
- BIO_write(mInBio, message->data(), int(message->size())); // Input
- else
- recv(message); // Pass zero-sized messages through
- if (state() == State::Connecting) {
- // Continue the handshake
- bool finished;
- {
- std::lock_guard lock(mSslMutex);
- int ret = SSL_do_handshake(mSsl);
- if (!openssl::check(mSsl, ret, "Handshake failed"))
- break;
- flushOutput();
- finished = (SSL_is_init_finished(mSsl) != 0);
- }
- if (finished) {
- PLOG_INFO << "TLS handshake finished";
- changeState(State::Connected);
- postHandshake();
- }
- }
- if (state() == State::Connected) {
- int ret;
- while (true) {
- {
- std::lock_guard lock(mSslMutex);
- ret = SSL_read(mSsl, buffer, bufferSize);
- }
- if (ret > 0)
- recv(make_message(buffer, buffer + ret));
- else
- break;
- }
- {
- std::lock_guard lock(mSslMutex);
- if (!openssl::check(mSsl, ret))
- break;
- flushOutput(); // SSL_read() can also cause write operations
- }
- }
- }
- } catch (const std::exception &e) {
- PLOG_ERROR << "TLS recv: " << e.what();
- }
- if (state() == State::Connected) {
- PLOG_INFO << "TLS closed";
- changeState(State::Disconnected);
- recv(nullptr);
- } else {
- PLOG_ERROR << "TLS handshake failed";
- changeState(State::Failed);
- }
- {
- std::lock_guard lock(mSslMutex);
- SSL_shutdown(mSsl);
- }
- }
- bool TlsTransport::flushOutput() {
- // Requires mSslMutex to be locked
- bool result = true;
- const size_t bufferSize = 4096;
- byte buffer[bufferSize];
- int len;
- while ((len = BIO_read(mOutBio, buffer, bufferSize)) > 0)
- result = outgoing(make_message(buffer, buffer + len));
- return result;
- }
- void TlsTransport::InfoCallback(const SSL *ssl, int where, int ret) {
- TlsTransport *t =
- static_cast<TlsTransport *>(SSL_get_ex_data(ssl, TlsTransport::TransportExIndex));
- if (where & SSL_CB_ALERT) {
- if (ret != 256) { // Close Notify
- PLOG_ERROR << "TLS alert: " << SSL_alert_desc_string_long(ret);
- }
- t->mIncomingQueue.stop(); // Close the connection
- }
- }
- #endif
- } // namespace rtc::impl
- #endif
|