/** * Copyright (c) 2020-2021 Paul-Louis Ageneau * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #if RTC_ENABLE_WEBSOCKET #include "websocketserver.hpp" #include "common.hpp" #include "internals.hpp" #include "threadpool.hpp" namespace rtc::impl { using namespace std::placeholders; const string PemBeginCertificateTag = "-----BEGIN CERTIFICATE-----"; WebSocketServer::WebSocketServer(Configuration config_) : config(std::move(config_)), mStopped(false) { PLOG_VERBOSE << "Creating WebSocketServer"; // Create certificate if (config.enableTls) { if (config.certificatePemFile && config.keyPemFile) { mCertificate = std::make_shared( config.certificatePemFile->find(PemBeginCertificateTag) != string::npos ? Certificate::FromString(*config.certificatePemFile, *config.keyPemFile) : Certificate::FromFile(*config.certificatePemFile, *config.keyPemFile, config.keyPemPass.value_or(""))); } else if (!config.certificatePemFile && !config.keyPemFile) { mCertificate = std::make_shared( Certificate::Generate(CertificateType::Default, "localhost")); } else { throw std::invalid_argument( "Either none or both certificate and key PEM files must be specified"); } } // Create TCP server tcpServer = std::make_unique(config.port); // Create server thread mThread = std::thread(&WebSocketServer::runLoop, this); } WebSocketServer::~WebSocketServer() { PLOG_VERBOSE << "Destroying WebSocketServer"; stop(); } void WebSocketServer::stop() { if (mStopped.exchange(true)) return; PLOG_DEBUG << "Stopping WebSocketServer thread"; tcpServer->close(); mThread.join(); } void WebSocketServer::runLoop() { PLOG_INFO << "Starting WebSocketServer"; try { while (auto incoming = tcpServer->accept()) { try { if (!clientCallback) continue; auto impl = std::make_shared(nullopt, mCertificate); impl->changeState(WebSocket::State::Connecting); impl->setTcpTransport(incoming); clientCallback(std::make_shared(impl)); } catch (const std::exception &e) { PLOG_ERROR << "WebSocketServer: " << e.what(); } } } catch (const std::exception &e) { PLOG_FATAL << "WebSocketServer: " << e.what(); } PLOG_INFO << "Stopped WebSocketServer"; } } // namespace rtc::impl #endif