From 16bc68f2f94d1bcfd21e5124537081d76859ea89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Lepin?= Date: Mon, 31 Dec 2018 17:05:23 +0100 Subject: [PATCH 01/19] server: import websockets++ server from master --- .gitmodules | 6 ++ CMakeLists.txt | 34 ++++--- src/WSServer.cpp | 249 +++++++++++++++++++++++++++-------------------- src/WSServer.h | 51 ++++++---- 4 files changed, 203 insertions(+), 137 deletions(-) create mode 100644 .gitmodules diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..3e9749f0 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,6 @@ +[submodule "deps/websocketpp"] + path = deps/websocketpp + url = https://github.com/zaphoyd/websocketpp.git +[submodule "deps/asio"] + path = deps/asio + url = https://github.com/chriskohlhoff/asio.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 50d81520..e8897f28 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,14 +6,26 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTOUIC ON) +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED ON) if (WIN32 OR APPLE) include(external/FindLibObs.cmake) endif() +add_definitions(-DASIO_STANDALONE) + +if (UNIX) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") +endif() + +if (WIN32 OR APPLE) + include(external/FindLibObs.cmake) +endif() + find_package(LibObs REQUIRED) find_package(Qt5Core REQUIRED) -find_package(Qt5WebSockets REQUIRED) find_package(Qt5Widgets REQUIRED) +find_package(Boost REQUIRED) set(obs-websocket_SOURCES src/obs-websocket.cpp @@ -52,13 +64,14 @@ add_library(obs-websocket MODULE include_directories( "${LIBOBS_INCLUDE_DIR}/../UI/obs-frontend-api" ${Qt5Core_INCLUDES} - ${Qt5WebSockets_INCLUDES} - ${Qt5Widgets_INCLUDES}) + ${Qt5Widgets_INCLUDES} + ${Boost_INCLUDE_DIRS} + "${CMAKE_SOURCE_DIR}/deps/asio/asio/include" + "${CMAKE_SOURCE_DIR}/deps/websocketpp") target_link_libraries(obs-websocket libobs Qt5::Core - Qt5::WebSockets Qt5::Widgets) # --- End of section --- @@ -70,6 +83,8 @@ if(WIN32) message(FATAL_ERROR "Could not find OBS Frontend API's library !") endif() + add_definitions(-D_WEBSOCKETPP_CPP11_STL_) + if(CMAKE_SIZEOF_VOID_P EQUAL 8) set(ARCH_NAME "64bit") set(OBS_BUILDDIR_ARCH "build64") @@ -102,8 +117,6 @@ if(WIN32) COMMAND if $==1 ("${CMAKE_COMMAND}" -E copy "$" - "${QTDIR}/bin/Qt5WebSockets.dll" - "${QTDIR}/bin/Qt5Network.dll" "${RELEASE_DIR}/obs-plugins/${ARCH_NAME}") # If config is RelWithDebInfo, package release files @@ -118,8 +131,6 @@ if(WIN32) COMMAND if $==1 ("${CMAKE_COMMAND}" -E copy "$" - "${QTDIR}/bin/Qt5WebSockets.dll" - "${QTDIR}/bin/Qt5Network.dll" "${RELEASE_DIR}/obs-plugins/${ARCH_NAME}") COMMAND if $==1 ("${CMAKE_COMMAND}" -E copy @@ -130,8 +141,6 @@ if(WIN32) COMMAND if $==1 ( "${CMAKE_COMMAND}" -E copy "$" - "${QTDIR}/bin/Qt5WebSocketsd.dll" - "${QTDIR}/bin/Qt5Networkd.dll" "${LIBOBS_INCLUDE_DIR}/../${OBS_BUILDDIR_ARCH}/rundir/$/obs-plugins/${ARCH_NAME}") COMMAND if $==1 ( @@ -155,11 +164,8 @@ endif() # --- Linux-specific build settings and tasks --- if(UNIX AND NOT APPLE) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") - set_target_properties(obs-websocket PROPERTIES PREFIX "") - target_link_libraries(obs-websocket - obs-frontend-api) + target_link_libraries(obs-websocket obs-frontend-api) file(GLOB locale_files data/locale/*.ini) diff --git a/src/WSServer.cpp b/src/WSServer.cpp index 4ca45823..d7f52cc3 100644 --- a/src/WSServer.cpp +++ b/src/WSServer.cpp @@ -16,11 +16,11 @@ You should have received a copy of the GNU General Public License along with this program. If not, see */ -#include #include #include #include #include +#include #include #include "WSServer.h" @@ -30,139 +30,178 @@ with this program. If not, see QT_USE_NAMESPACE +using websocketpp::lib::placeholders::_1; +using websocketpp::lib::placeholders::_2; +using websocketpp::lib::bind; + WSServer* WSServer::Instance = nullptr; +QString decodeBase64(const QString& source) +{ + return QString::fromUtf8( + QByteArray::fromBase64( + source.toUtf8() + ) + ); +} + WSServer::WSServer(QObject* parent) : QObject(parent), - _wsServer(Q_NULLPTR), - _clients(), + _connections(), _clMutex(QMutex::Recursive) { - _wsServer = new QWebSocketServer( - QStringLiteral("obs-websocket"), - QWebSocketServer::NonSecureMode); + _server.init_asio(); + + _server.set_validate_handler(bind(&WSServer::validateConnection, this, ::_1)); + _server.set_open_handler(bind(&WSServer::onOpen, this, ::_1)); + _server.set_close_handler(bind(&WSServer::onClose, this, ::_1)); + _server.set_message_handler(bind(&WSServer::onMessage, this, ::_1, ::_2)); } -WSServer::~WSServer() { - Stop(); +WSServer::~WSServer() +{ + stop(); } -void WSServer::Start(quint16 port) { - if (port == _wsServer->serverPort()) +void WSServer::start(quint16 port) +{ + if (_server.is_listening() && port == _serverPort) { + blog(LOG_INFO, "WebSocketsServer::start: server already on this port. no restart needed"); return; - - if(_wsServer->isListening()) - Stop(); - - bool serverStarted = _wsServer->listen(QHostAddress::Any, port); - if (serverStarted) { - blog(LOG_INFO, "server started successfully on TCP port %d", port); - - connect(_wsServer, SIGNAL(newConnection()), - this, SLOT(onNewConnection())); } - else { - QString errorString = _wsServer->errorString(); - blog(LOG_ERROR, - "error: failed to start server on TCP port %d: %s", - port, errorString.toUtf8().constData()); - QMainWindow* mainWindow = (QMainWindow*)obs_frontend_get_main_window(); - - obs_frontend_push_ui_translation(obs_module_get_string); - QString title = tr("OBSWebsocket.Server.StartFailed.Title"); - QString msg = tr("OBSWebsocket.Server.StartFailed.Message").arg(port); - obs_frontend_pop_ui_translation(); - - QMessageBox::warning(mainWindow, title, msg); + if (_server.is_listening()) { + stop(); } + + _serverPort = port; + + _server.listen(_serverPort); + _server.start_accept(); + + QtConcurrent::run([=]() { + _server.run(); + }); + + blog(LOG_INFO, "server started successfully on port %d", _serverPort); } -void WSServer::Stop() { - QMutexLocker locker(&_clMutex); - for(QWebSocket* pClient : _clients) { - pClient->close(); - } - locker.unlock(); - - _wsServer->close(); - +void WSServer::stop() +{ + _server.stop(); + _server.stop_listening(); blog(LOG_INFO, "server stopped successfully"); } -void WSServer::broadcast(QString message) { +void WSServer::broadcast(QString message) +{ QMutexLocker locker(&_clMutex); - for(QWebSocket* pClient : _clients) { - if (Config::Current()->AuthRequired - && (pClient->property(PROP_AUTHENTICATED).toBool() == false)) { - // Skip this client if unauthenticated - continue; + for (connection_hdl hdl : _connections) { + _server.send(hdl, message.toStdString(), websocketpp::frame::opcode::text); + } +} + +bool WSServer::validateConnection(connection_hdl hdl) +{ + // TODO enforce subprotocol + + Config* config = Config::Current(); + if (config->AuthRequired) { + auto conn = _server.get_con_from_hdl(hdl); + + QString authorization = + QString::fromStdString(conn->get_request_header("Authorization")); + if (!authorization.isNull() && !authorization.isEmpty()) { + const QStringList& parts = authorization.split(" ", QString::SplitBehavior::SkipEmptyParts); + if (parts.length() >= 2) { + const QString& authType = parts.at(0); + const QString& authValue = parts.at(1); + + if (authType == "Basic") { + const QStringList& decodedParts = + decodeBase64(authValue).split(":", QString::SplitBehavior::SkipEmptyParts); + if (decodedParts.length() >= 2) { + const QString& username = decodedParts.at(0); + const QString& password = decodedParts.at(1); + + // TODO time-constant string comparison + if (password == config->AuthPassword) { + return true; + } + } + } + } } - pClient->sendTextMessage(message); + + conn->set_status(websocketpp::http::status_code::unauthorized); + conn->append_header("WWW-Authenticate", "Basic charset=\"UTF-8\""); + return false; } + + return true; } -void WSServer::onNewConnection() { - QWebSocket* pSocket = _wsServer->nextPendingConnection(); - if (pSocket) { - connect(pSocket, SIGNAL(textMessageReceived(const QString&)), - this, SLOT(onTextMessageReceived(QString))); - connect(pSocket, SIGNAL(disconnected()), - this, SLOT(onSocketDisconnected())); +void WSServer::onOpen(connection_hdl hdl) +{ + QMutexLocker locker(&_clMutex); + _connections.insert(hdl); + locker.unlock(); - pSocket->setProperty(PROP_AUTHENTICATED, false); - - QMutexLocker locker(&_clMutex); - _clients << pSocket; - locker.unlock(); - - QHostAddress clientAddr = pSocket->peerAddress(); - QString clientIp = Utils::FormatIPAddress(clientAddr); - - blog(LOG_INFO, "new client connection from %s:%d", - clientIp.toUtf8().constData(), pSocket->peerPort()); - - obs_frontend_push_ui_translation(obs_module_get_string); - QString title = tr("OBSWebsocket.NotifyConnect.Title"); - QString msg = tr("OBSWebsocket.NotifyConnect.Message") - .arg(Utils::FormatIPAddress(clientAddr)); - obs_frontend_pop_ui_translation(); - - Utils::SysTrayNotify(msg, QSystemTrayIcon::Information, title); - } + QString clientIp = getRemoteEndpoint(hdl); + notifyConnection(clientIp); + blog(LOG_INFO, "new client connection from %s", clientIp.toUtf8().constData()); } -void WSServer::onTextMessageReceived(QString message) { - QWebSocket* pSocket = qobject_cast(sender()); - if (pSocket) { - WSRequestHandler handler(pSocket); - handler.processIncomingMessage(message); +void WSServer::onMessage(connection_hdl hdl, server::message_ptr message) +{ + auto opcode = message->get_opcode(); + if (opcode != websocketpp::frame::opcode::text) { + return; } + + QString payload = QString::fromStdString(message->get_payload()); + + // TODO refactor handler + WSRequestHandler handler; + handler.processIncomingMessage(payload); + std::string response = handler.getResponse().toStdString(); + + _server.send(hdl, response, websocketpp::frame::opcode::text); } -void WSServer::onSocketDisconnected() { - QWebSocket* pSocket = qobject_cast(sender()); - if (pSocket) { - pSocket->setProperty(PROP_AUTHENTICATED, false); +void WSServer::onClose(connection_hdl hdl) +{ + QMutexLocker locker(&_clMutex); + _connections.erase(hdl); + locker.unlock(); - QMutexLocker locker(&_clMutex); - _clients.removeAll(pSocket); - locker.unlock(); - - pSocket->deleteLater(); - - QHostAddress clientAddr = pSocket->peerAddress(); - QString clientIp = Utils::FormatIPAddress(clientAddr); - - blog(LOG_INFO, "client %s:%d disconnected", - clientIp.toUtf8().constData(), pSocket->peerPort()); - - obs_frontend_push_ui_translation(obs_module_get_string); - QString title = tr("OBSWebsocket.NotifyDisconnect.Title"); - QString msg = tr("OBSWebsocket.NotifyDisconnect.Message") - .arg(Utils::FormatIPAddress(clientAddr)); - obs_frontend_pop_ui_translation(); - - Utils::SysTrayNotify(msg, QSystemTrayIcon::Information, title); - } + QString clientIp = getRemoteEndpoint(hdl); + notifyDisconnection(clientIp); + blog(LOG_INFO, "client %s disconnected", clientIp.toUtf8().constData()); +} + +QString WSServer::getRemoteEndpoint(connection_hdl hdl) +{ + auto conn = _server.get_con_from_hdl(hdl); + return QString::fromStdString(conn->get_remote_endpoint()); +} + +void WSServer::notifyConnection(QString clientIp) +{ + obs_frontend_push_ui_translation(obs_module_get_string); + QString title = tr("OBSWebsocket.NotifyConnect.Title"); + QString msg = tr("OBSWebsocket.NotifyConnect.Message").arg(clientIp); + obs_frontend_pop_ui_translation(); + + Utils::SysTrayNotify(msg, QSystemTrayIcon::Information, title); +} + +void WSServer::notifyDisconnection(QString clientIp) +{ + obs_frontend_push_ui_translation(obs_module_get_string); + QString title = tr("OBSWebsocket.NotifyDisconnect.Title"); + QString msg = tr("OBSWebsocket.NotifyDisconnect.Message").arg(clientIp); + obs_frontend_pop_ui_translation(); + + Utils::SysTrayNotify(msg, QSystemTrayIcon::Information, title); } diff --git a/src/WSServer.h b/src/WSServer.h index 3d33532a..c1e7265a 100644 --- a/src/WSServer.h +++ b/src/WSServer.h @@ -20,33 +20,48 @@ with this program. If not, see #define WSSERVER_H #include -#include #include +#include +#include +#include + #include "WSRequestHandler.h" QT_FORWARD_DECLARE_CLASS(QWebSocketServer) QT_FORWARD_DECLARE_CLASS(QWebSocket) -class WSServer : public QObject { - Q_OBJECT - public: - explicit WSServer(QObject* parent = Q_NULLPTR); - virtual ~WSServer(); - void Start(quint16 port); - void Stop(); - void broadcast(QString message); - static WSServer* Instance; +using websocketpp::connection_hdl; - private slots: - void onNewConnection(); - void onTextMessageReceived(QString message); - void onSocketDisconnected(); +typedef websocketpp::server server; +typedef std::set> con_list; - private: - QWebSocketServer* _wsServer; - QList _clients; - QMutex _clMutex; +class WSServer : public QObject +{ +Q_OBJECT + +public: + explicit WSServer(QObject* parent = Q_NULLPTR); + virtual ~WSServer(); + void start(quint16 port); + void stop(); + void broadcast(QString message); + static WSServer* Instance; + +private: + bool validateConnection(connection_hdl hdl); + void onOpen(connection_hdl hdl); + void onMessage(connection_hdl hdl, server::message_ptr message); + void onClose(connection_hdl hdl); + + QString getRemoteEndpoint(connection_hdl hdl); + void notifyConnection(QString clientIp); + void notifyDisconnection(QString clientIp); + + server _server; + quint16 _serverPort; + con_list _connections; + QMutex _clMutex; }; #endif // WSSERVER_H From 7e6b53311d9ef6014b74a46ecd1c83552007e5ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Lepin?= Date: Mon, 31 Dec 2018 17:18:07 +0100 Subject: [PATCH 02/19] import more changes from master --- CI/build-macos.sh | 1 + CI/generate-docs.sh | 2 +- CI/install-dependencies-xenial.sh | 3 +- CI/macos/obs-websocket.pkgproj | 119 +----------------------------- CI/package-macos.sh | 32 -------- CI/package-xenial.sh | 2 +- src/Utils.cpp | 9 --- src/Utils.h | 3 - src/WSRequestHandler.cpp | 23 +++--- src/WSRequestHandler.h | 9 ++- src/WSRequestHandler_General.cpp | 16 ++-- 11 files changed, 30 insertions(+), 189 deletions(-) diff --git a/CI/build-macos.sh b/CI/build-macos.sh index f528ce2e..c41ebaf6 100755 --- a/CI/build-macos.sh +++ b/CI/build-macos.sh @@ -20,6 +20,7 @@ echo "[obs-websocket] Building 'obs-websocket' for macOS." mkdir -p build && cd build cmake .. \ -DQTDIR=/usr/local/opt/qt \ + -DBOOST_ROOT=/usr/local/opt/boost \ -DLIBOBS_INCLUDE_DIR=../../obs-studio/libobs \ -DLIBOBS_LIB=../../obs-studio/libobs \ -DOBS_FRONTEND_LIB="$(pwd)/../../obs-studio/build/UI/obs-frontend-api/libobs-frontend-api.dylib" \ diff --git a/CI/generate-docs.sh b/CI/generate-docs.sh index 5e7d6d01..34350520 100755 --- a/CI/generate-docs.sh +++ b/CI/generate-docs.sh @@ -15,7 +15,7 @@ if git diff --quiet; then exit 0 fi -if [ "$TRAVIS_PULL_REQUEST" != "false" -o "$TRAVIS_BRANCH" != "4.x-current" ]; then +if [ "$TRAVIS_PULL_REQUEST" != "false" -o "$TRAVIS_BRANCH" != "master" ]; then echo "-- Skipping documentation deployment because this is either a pull request or a non-master branch." exit 0 fi diff --git a/CI/install-dependencies-xenial.sh b/CI/install-dependencies-xenial.sh index b6dda1c6..4b4041bd 100755 --- a/CI/install-dependencies-xenial.sh +++ b/CI/install-dependencies-xenial.sh @@ -11,7 +11,8 @@ apt-get install -y \ checkinstall \ cmake \ obs-studio \ - libqt5websockets5-dev + qtbase5-dev \ + libboost-all-dev # Dirty hack wget -O /usr/include/obs/obs-frontend-api.h https://raw.githubusercontent.com/obsproject/obs-studio/master/UI/obs-frontend-api/obs-frontend-api.h diff --git a/CI/macos/obs-websocket.pkgproj b/CI/macos/obs-websocket.pkgproj index b8159920..1006aa7d 100644 --- a/CI/macos/obs-websocket.pkgproj +++ b/CI/macos/obs-websocket.pkgproj @@ -12,123 +12,6 @@ CHILDREN - - CHILDREN - - - CHILDREN - - - CHILDREN - - - CHILDREN - - - CHILDREN - - - CHILDREN - - GID - 80 - PATH - ../../build/QtNetwork - PATH_TYPE - 1 - PERMISSIONS - 292 - TYPE - 3 - UID - 0 - - - CHILDREN - - GID - 80 - PATH - ../../build/QtWebSockets - PATH_TYPE - 1 - PERMISSIONS - 292 - TYPE - 3 - UID - 0 - - - GID - 80 - PATH - bin - PATH_TYPE - 0 - PERMISSIONS - 509 - TYPE - 2 - UID - 0 - - - GID - 80 - PATH - Resources - PATH_TYPE - 0 - PERMISSIONS - 509 - TYPE - 2 - UID - 0 - - - GID - 80 - PATH - Contents - PATH_TYPE - 0 - PERMISSIONS - 509 - TYPE - 2 - UID - 0 - - - GID - 80 - PATH - OBS.app - PATH_TYPE - 0 - PERMISSIONS - 509 - TYPE - 2 - UID - 0 - - - GID - 80 - PATH - Applications - PATH_TYPE - 0 - PERMISSIONS - 509 - TYPE - 1 - UID - 0 - CHILDREN @@ -635,7 +518,7 @@ OVERWRITE_PERMISSIONS VERSION - 4.5.0 + 5.0.0 PROJECT_COMMENTS diff --git a/CI/package-macos.sh b/CI/package-macos.sh index 62bfb622..7fc2e59b 100755 --- a/CI/package-macos.sh +++ b/CI/package-macos.sh @@ -12,9 +12,6 @@ fi echo "[obs-websocket] Preparing package build" export QT_CELLAR_PREFIX="$(/usr/bin/find /usr/local/Cellar/qt -d 1 | sort -t '.' -k 1,1n -k 2,2n -k 3,3n | tail -n 1)" -export WS_LIB="/usr/local/opt/qt/lib/QtWebSockets.framework/QtWebSockets" -export NET_LIB="/usr/local/opt/qt/lib/QtNetwork.framework/QtNetwork" - export GIT_HASH=$(git rev-parse --short HEAD) export VERSION="$GIT_HASH-$TRAVIS_BRANCH" @@ -27,46 +24,17 @@ fi export FILENAME="obs-websocket-$VERSION.pkg" export LATEST_FILENAME="obs-websocket-latest-$LATEST_VERSION.pkg" -echo "[obs-websocket] Copying Qt dependencies" -if [ ! -f ./build/$(basename $WS_LIB) ]; then cp $WS_LIB ./build; fi -if [ ! -f ./build/$(basename $NET_LIB) ]; then cp $NET_LIB ./build; fi - -chmod +rw ./build/QtWebSockets ./build/QtNetwork - -echo "[obs-websocket] Modifying QtNetwork" -install_name_tool \ - -id @rpath/QtNetwork \ - -change /usr/local/opt/qt/lib/QtNetwork.framework/Versions/5/QtNetwork @rpath/QtNetwork \ - -change $QT_CELLAR_PREFIX/lib/QtCore.framework/Versions/5/QtCore @rpath/QtCore \ - ./build/QtNetwork - -echo "[obs-websocket] Modifying QtWebSockets" -install_name_tool \ - -id @rpath/QtWebSockets \ - -change /usr/local/opt/qt/lib/QtWebSockets.framework/Versions/5/QtWebSockets @rpath/QtWebSockets \ - -change $QT_CELLAR_PREFIX/lib/QtNetwork.framework/Versions/5/QtNetwork @rpath/QtNetwork \ - -change $QT_CELLAR_PREFIX/lib/QtCore.framework/Versions/5/QtCore @rpath/QtCore \ - ./build/QtWebSockets - echo "[obs-websocket] Modifying obs-websocket.so" install_name_tool \ - -change /usr/local/opt/qt/lib/QtWebSockets.framework/Versions/5/QtWebSockets @rpath/QtWebSockets \ -change /usr/local/opt/qt/lib/QtWidgets.framework/Versions/5/QtWidgets @rpath/QtWidgets \ - -change /usr/local/opt/qt/lib/QtNetwork.framework/Versions/5/QtNetwork @rpath/QtNetwork \ -change /usr/local/opt/qt/lib/QtGui.framework/Versions/5/QtGui @rpath/QtGui \ -change /usr/local/opt/qt/lib/QtCore.framework/Versions/5/QtCore @rpath/QtCore \ ./build/obs-websocket.so # Check if replacement worked -echo "[obs-websocket] Dependencies for QtNetwork" -otool -L ./build/QtNetwork -echo "[obs-websocket] Dependencies for QtWebSockets" -otool -L ./build/QtWebSockets echo "[obs-websocket] Dependencies for obs-websocket" otool -L ./build/obs-websocket.so -chmod -w ./build/QtWebSockets ./build/QtNetwork - echo "[obs-websocket] Actual package build" packagesbuild ./CI/macos/obs-websocket.pkgproj diff --git a/CI/package-xenial.sh b/CI/package-xenial.sh index b1dda473..dde64929 100755 --- a/CI/package-xenial.sh +++ b/CI/package-xenial.sh @@ -17,7 +17,7 @@ PAGER=cat checkinstall -y --type=debian --fstrans=no --nodoc \ --backup=no --deldoc=yes --install=no \ --pkgname=obs-websocket --pkgversion="$PKG_VERSION" \ --pkglicense="GPLv2.0" --maintainer="contact@slepin.fr" \ - --requires="libqt5websockets5" --pkggroup="video" \ + --pkggroup="video" \ --pkgsource="https://github.com/Palakis/obs-websocket" \ --pakdir="/package" diff --git a/src/Utils.cpp b/src/Utils.cpp index b73ed51c..570e676d 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -376,15 +376,6 @@ void Utils::SysTrayNotify(QString &text, trayIcon->showMessage(title, text, icon); } -QString Utils::FormatIPAddress(QHostAddress &addr) { - QRegExp v4regex("(::ffff:)(((\\d).){3})", Qt::CaseInsensitive); - QString addrString = addr.toString(); - if (addrString.contains(v4regex)) { - addrString = QHostAddress(addr.toIPv4Address()).toString(); - } - return addrString; -} - const char* Utils::GetRecordingFolder() { config_t* profile = obs_frontend_get_profile_config(); QString outputMode = config_get_string(profile, "Output", "Mode"); diff --git a/src/Utils.h b/src/Utils.h index ba97d5cf..651991d6 100644 --- a/src/Utils.h +++ b/src/Utils.h @@ -26,7 +26,6 @@ with this program. If not, see #include #include #include -#include #include #include @@ -70,8 +69,6 @@ class Utils { QSystemTrayIcon::MessageIcon n, QString title = QString("obs-websocket")); - static QString FormatIPAddress(QHostAddress &addr); - static const char* GetRecordingFolder(); static bool SetRecordingFolder(const char* path); diff --git a/src/WSRequestHandler.cpp b/src/WSRequestHandler.cpp index 321fa5a6..0b859b1a 100644 --- a/src/WSRequestHandler.cpp +++ b/src/WSRequestHandler.cpp @@ -128,11 +128,10 @@ QSet WSRequestHandler::authNotRequired { "Authenticate" }; -WSRequestHandler::WSRequestHandler(QWebSocket* client) : +WSRequestHandler::WSRequestHandler() : _messageId(0), _requestType(""), - data(nullptr), - _client(client) + data(nullptr) { } @@ -164,13 +163,13 @@ void WSRequestHandler::processIncomingMessage(QString textMessage) { _requestType = obs_data_get_string(data, "request-type"); _messageId = obs_data_get_string(data, "message-id"); - if (Config::Current()->AuthRequired - && (_client->property(PROP_AUTHENTICATED).toBool() == false) - && (authNotRequired.find(_requestType) == authNotRequired.end())) - { - SendErrorResponse("Not Authenticated"); - return; - } + // if (Config::Current()->AuthRequired + // && (_client->property(PROP_AUTHENTICATED).toBool() == false) + // && (authNotRequired.find(_requestType) == authNotRequired.end())) + // { + // SendErrorResponse("Not Authenticated"); + // return; + // } void (*handlerFunc)(WSRequestHandler*) = (messageMap[_requestType]); @@ -215,8 +214,8 @@ void WSRequestHandler::SendErrorResponse(obs_data_t* additionalFields) { } void WSRequestHandler::SendResponse(obs_data_t* response) { - QString json = obs_data_get_json(response); - _client->sendTextMessage(json); + assert(_response.isNull()); + _response = obs_data_get_json(response); if (Config::Current()->DebugEnabled) blog(LOG_DEBUG, "Response << '%s'", json.toUtf8().constData()); diff --git a/src/WSRequestHandler.h b/src/WSRequestHandler.h index cb259827..be109009 100644 --- a/src/WSRequestHandler.h +++ b/src/WSRequestHandler.h @@ -22,8 +22,6 @@ with this program. If not, see #include #include -#include -#include #include #include @@ -34,15 +32,18 @@ class WSRequestHandler : public QObject { Q_OBJECT public: - explicit WSRequestHandler(QWebSocket* client); + explicit WSRequestHandler(); ~WSRequestHandler(); void processIncomingMessage(QString textMessage); bool hasField(QString name); + QString getResponse() { + return _response; + } private: - QWebSocket* _client; const char* _messageId; const char* _requestType; + QString _response; OBSDataAutoRelease data; void SendOKResponse(obs_data_t* additionalFields = NULL); diff --git a/src/WSRequestHandler_General.cpp b/src/WSRequestHandler_General.cpp index 6e98e519..efe0b9db 100644 --- a/src/WSRequestHandler_General.cpp +++ b/src/WSRequestHandler_General.cpp @@ -91,14 +91,14 @@ void WSRequestHandler::HandleAuthenticate(WSRequestHandler* req) { return; } - if ((req->_client->property(PROP_AUTHENTICATED).toBool() == false) - && Config::Current()->CheckAuth(auth)) - { - req->_client->setProperty(PROP_AUTHENTICATED, true); - req->SendOKResponse(); - } else { - req->SendErrorResponse("Authentication Failed."); - } + // if ((req->_client->property(PROP_AUTHENTICATED).toBool() == false) + // && Config::Current()->CheckAuth(auth)) + // { + // req->_client->setProperty(PROP_AUTHENTICATED, true); + // req->SendOKResponse(); + // } else { + // req->SendErrorResponse("Authentication Failed."); + // } } /** From 5cfefd8b15a131464f4f5894e40a7e532e96b7c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Lepin?= Date: Mon, 31 Dec 2018 17:19:24 +0100 Subject: [PATCH 03/19] ci(docs): revert change --- CI/generate-docs.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CI/generate-docs.sh b/CI/generate-docs.sh index 34350520..5e7d6d01 100755 --- a/CI/generate-docs.sh +++ b/CI/generate-docs.sh @@ -15,7 +15,7 @@ if git diff --quiet; then exit 0 fi -if [ "$TRAVIS_PULL_REQUEST" != "false" -o "$TRAVIS_BRANCH" != "master" ]; then +if [ "$TRAVIS_PULL_REQUEST" != "false" -o "$TRAVIS_BRANCH" != "4.x-current" ]; then echo "-- Skipping documentation deployment because this is either a pull request or a non-master branch." exit 0 fi From ec7f3fa057caff2505687994a60b3996732a32b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Lepin?= Date: Mon, 31 Dec 2018 17:21:29 +0100 Subject: [PATCH 04/19] ci(macos): revert version change --- CI/macos/obs-websocket.pkgproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CI/macos/obs-websocket.pkgproj b/CI/macos/obs-websocket.pkgproj index 1006aa7d..766efa15 100644 --- a/CI/macos/obs-websocket.pkgproj +++ b/CI/macos/obs-websocket.pkgproj @@ -518,7 +518,7 @@ OVERWRITE_PERMISSIONS VERSION - 5.0.0 + 4.5.0 PROJECT_COMMENTS From a8de9ac47284f8d7368cdca200de86d0cdbfdd54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Lepin?= Date: Mon, 31 Dec 2018 17:23:20 +0100 Subject: [PATCH 05/19] server: remove validate handler --- src/WSServer.cpp | 41 ----------------------------------------- src/WSServer.h | 1 - 2 files changed, 42 deletions(-) diff --git a/src/WSServer.cpp b/src/WSServer.cpp index d7f52cc3..d6ca1de0 100644 --- a/src/WSServer.cpp +++ b/src/WSServer.cpp @@ -52,7 +52,6 @@ WSServer::WSServer(QObject* parent) { _server.init_asio(); - _server.set_validate_handler(bind(&WSServer::validateConnection, this, ::_1)); _server.set_open_handler(bind(&WSServer::onOpen, this, ::_1)); _server.set_close_handler(bind(&WSServer::onClose, this, ::_1)); _server.set_message_handler(bind(&WSServer::onMessage, this, ::_1, ::_2)); @@ -101,46 +100,6 @@ void WSServer::broadcast(QString message) } } -bool WSServer::validateConnection(connection_hdl hdl) -{ - // TODO enforce subprotocol - - Config* config = Config::Current(); - if (config->AuthRequired) { - auto conn = _server.get_con_from_hdl(hdl); - - QString authorization = - QString::fromStdString(conn->get_request_header("Authorization")); - if (!authorization.isNull() && !authorization.isEmpty()) { - const QStringList& parts = authorization.split(" ", QString::SplitBehavior::SkipEmptyParts); - if (parts.length() >= 2) { - const QString& authType = parts.at(0); - const QString& authValue = parts.at(1); - - if (authType == "Basic") { - const QStringList& decodedParts = - decodeBase64(authValue).split(":", QString::SplitBehavior::SkipEmptyParts); - if (decodedParts.length() >= 2) { - const QString& username = decodedParts.at(0); - const QString& password = decodedParts.at(1); - - // TODO time-constant string comparison - if (password == config->AuthPassword) { - return true; - } - } - } - } - } - - conn->set_status(websocketpp::http::status_code::unauthorized); - conn->append_header("WWW-Authenticate", "Basic charset=\"UTF-8\""); - return false; - } - - return true; -} - void WSServer::onOpen(connection_hdl hdl) { QMutexLocker locker(&_clMutex); diff --git a/src/WSServer.h b/src/WSServer.h index c1e7265a..2ab4fb06 100644 --- a/src/WSServer.h +++ b/src/WSServer.h @@ -49,7 +49,6 @@ public: static WSServer* Instance; private: - bool validateConnection(connection_hdl hdl); void onOpen(connection_hdl hdl); void onMessage(connection_hdl hdl, server::message_ptr message); void onClose(connection_hdl hdl); From 4f98b9e41b2103b5e534fd5e6616c8cfe9b2c808 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20L?= Date: Mon, 31 Dec 2018 20:23:16 +0100 Subject: [PATCH 06/19] general: submodules --- deps/asio | 1 + deps/websocketpp | 1 + 2 files changed, 2 insertions(+) create mode 160000 deps/asio create mode 160000 deps/websocketpp diff --git a/deps/asio b/deps/asio new file mode 160000 index 00000000..b73dc1d2 --- /dev/null +++ b/deps/asio @@ -0,0 +1 @@ +Subproject commit b73dc1d2c0ecb9452a87c26544d7f71e24342df6 diff --git a/deps/websocketpp b/deps/websocketpp new file mode 160000 index 00000000..c6d7e295 --- /dev/null +++ b/deps/websocketpp @@ -0,0 +1 @@ +Subproject commit c6d7e295bf5a0ab9b5f896720cc1a0e0fdc397a7 From 0391280c13621feb2ec1ed1380ea0fb5d8df443a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20L?= Date: Mon, 31 Dec 2018 20:27:52 +0100 Subject: [PATCH 07/19] fix build issues --- src/WSRequestHandler.cpp | 2 +- src/forms/settings-dialog.cpp | 4 ++-- src/obs-websocket.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/WSRequestHandler.cpp b/src/WSRequestHandler.cpp index 0b859b1a..ad3a38b1 100644 --- a/src/WSRequestHandler.cpp +++ b/src/WSRequestHandler.cpp @@ -218,7 +218,7 @@ void WSRequestHandler::SendResponse(obs_data_t* response) { _response = obs_data_get_json(response); if (Config::Current()->DebugEnabled) - blog(LOG_DEBUG, "Response << '%s'", json.toUtf8().constData()); + blog(LOG_DEBUG, "Response << '%s'", _response.toUtf8().constData()); } bool WSRequestHandler::hasField(QString name) { diff --git a/src/forms/settings-dialog.cpp b/src/forms/settings-dialog.cpp index 9bdaaa39..5378faaf 100644 --- a/src/forms/settings-dialog.cpp +++ b/src/forms/settings-dialog.cpp @@ -94,9 +94,9 @@ void SettingsDialog::FormAccepted() { conf->Save(); if (conf->ServerEnabled) - WSServer::Instance->Start(conf->ServerPort); + WSServer::Instance->start(conf->ServerPort); else - WSServer::Instance->Stop(); + WSServer::Instance->stop(); } SettingsDialog::~SettingsDialog() { diff --git a/src/obs-websocket.cpp b/src/obs-websocket.cpp index fd18af5d..c3fb0826 100644 --- a/src/obs-websocket.cpp +++ b/src/obs-websocket.cpp @@ -52,7 +52,7 @@ bool obs_module_load(void) { WSEvents::Instance = new WSEvents(WSServer::Instance); if (config->ServerEnabled) - WSServer::Instance->Start(config->ServerPort); + WSServer::Instance->start(config->ServerPort); // UI setup QAction* menu_action = (QAction*)obs_frontend_add_tools_menu_qaction( From c074088f2fcf005dc712097b78ab0b8b8d67eda4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20L?= Date: Mon, 31 Dec 2018 20:32:24 +0100 Subject: [PATCH 08/19] fix appveyor builds --- appveyor.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index c12a2501..b75bfd83 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -8,6 +8,7 @@ install: - 7z x dependencies2015.zip -odependencies2015 - set DepsPath32=%CD%\dependencies2015\win32 - set DepsPath64=%CD%\dependencies2015\win64 + - set BoostRoot=C:\Libraries\boost_1_67_0 - call C:\projects\obs-websocket\CI\install-setup-qt.cmd - set build_config=RelWithDebInfo - call C:\projects\obs-websocket\CI\install-build-obs.cmd @@ -15,9 +16,9 @@ install: - mkdir build32 - mkdir build64 - cd ./build32 - - cmake -G "Visual Studio 14 2015" -DQTDIR="%QTDIR32%" -DLibObs_DIR="C:\projects\obs-studio\build32\libobs" -DLIBOBS_INCLUDE_DIR="C:\projects\obs-studio\libobs" -DLIBOBS_LIB="C:\projects\obs-studio\build32\libobs\%build_config%\obs.lib" -DOBS_FRONTEND_LIB="C:\projects\obs-studio\build32\UI\obs-frontend-api\%build_config%\obs-frontend-api.lib" .. + - cmake -G "Visual Studio 14 2015" -DQTDIR="%QTDIR32%" -DBOOST_ROOT="%BoostRoot%" -DLibObs_DIR="C:\projects\obs-studio\build32\libobs" -DLIBOBS_INCLUDE_DIR="C:\projects\obs-studio\libobs" -DLIBOBS_LIB="C:\projects\obs-studio\build32\libobs\%build_config%\obs.lib" -DOBS_FRONTEND_LIB="C:\projects\obs-studio\build32\UI\obs-frontend-api\%build_config%\obs-frontend-api.lib" .. - cd ../build64 - - cmake -G "Visual Studio 14 2015 Win64" -DQTDIR="%QTDIR64%" -DLibObs_DIR="C:\projects\obs-studio\build64\libobs" -DLIBOBS_INCLUDE_DIR="C:\projects\obs-studio\libobs" -DLIBOBS_LIB="C:\projects\obs-studio\build64\libobs\%build_config%\obs.lib" -DOBS_FRONTEND_LIB="C:\projects\obs-studio\build64\UI\obs-frontend-api\%build_config%\obs-frontend-api.lib" .. + - cmake -G "Visual Studio 14 2015 Win64" -DQTDIR="%QTDIR64%" -DBOOST_ROOT="%BoostRoot%" -DLibObs_DIR="C:\projects\obs-studio\build64\libobs" -DLIBOBS_INCLUDE_DIR="C:\projects\obs-studio\libobs" -DLIBOBS_LIB="C:\projects\obs-studio\build64\libobs\%build_config%\obs.lib" -DOBS_FRONTEND_LIB="C:\projects\obs-studio\build64\UI\obs-frontend-api\%build_config%\obs-frontend-api.lib" .. build_script: - call msbuild /m /p:Configuration=%build_config% C:\projects\obs-websocket\build32\obs-websocket.sln /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" From fe1b14ff57fabcd524e3317d5f4a42f19fcf5e1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20L?= Date: Mon, 31 Dec 2018 20:49:15 +0100 Subject: [PATCH 09/19] server: return refactor --- src/WSRequestHandler.cpp | 18 ++++++++---------- src/WSRequestHandler.h | 7 ++----- src/WSServer.cpp | 6 ++---- 3 files changed, 12 insertions(+), 19 deletions(-) diff --git a/src/WSRequestHandler.cpp b/src/WSRequestHandler.cpp index ad3a38b1..5535d3c0 100644 --- a/src/WSRequestHandler.cpp +++ b/src/WSRequestHandler.cpp @@ -135,18 +135,15 @@ WSRequestHandler::WSRequestHandler() : { } -void WSRequestHandler::processIncomingMessage(QString textMessage) { - QByteArray msgData = textMessage.toUtf8(); - const char* msg = msgData.constData(); +std::string WSRequestHandler::processIncomingMessage(std::string& textMessage) { + std::string msgContainer(textMessage); + const char* msg = msgContainer.c_str(); data = obs_data_create_from_json(msg); if (!data) { - if (!msg) - msg = ""; - blog(LOG_ERROR, "invalid JSON payload received for '%s'", msg); SendErrorResponse("invalid JSON payload"); - return; + return _response; } if (Config::Current()->DebugEnabled) { @@ -157,7 +154,7 @@ void WSRequestHandler::processIncomingMessage(QString textMessage) { || !hasField("message-id")) { SendErrorResponse("missing request parameters"); - return; + return _response; } _requestType = obs_data_get_string(data, "request-type"); @@ -177,6 +174,8 @@ void WSRequestHandler::processIncomingMessage(QString textMessage) { handlerFunc(this); else SendErrorResponse("invalid request type"); + + return _response; } WSRequestHandler::~WSRequestHandler() { @@ -214,11 +213,10 @@ void WSRequestHandler::SendErrorResponse(obs_data_t* additionalFields) { } void WSRequestHandler::SendResponse(obs_data_t* response) { - assert(_response.isNull()); _response = obs_data_get_json(response); if (Config::Current()->DebugEnabled) - blog(LOG_DEBUG, "Response << '%s'", _response.toUtf8().constData()); + blog(LOG_DEBUG, "Response << '%s'", _response.c_str()); } bool WSRequestHandler::hasField(QString name) { diff --git a/src/WSRequestHandler.h b/src/WSRequestHandler.h index be109009..8d69693f 100644 --- a/src/WSRequestHandler.h +++ b/src/WSRequestHandler.h @@ -34,16 +34,13 @@ class WSRequestHandler : public QObject { public: explicit WSRequestHandler(); ~WSRequestHandler(); - void processIncomingMessage(QString textMessage); + std::string processIncomingMessage(std::string& textMessage); bool hasField(QString name); - QString getResponse() { - return _response; - } private: const char* _messageId; const char* _requestType; - QString _response; + std::string _response; OBSDataAutoRelease data; void SendOKResponse(obs_data_t* additionalFields = NULL); diff --git a/src/WSServer.cpp b/src/WSServer.cpp index d6ca1de0..b97799f3 100644 --- a/src/WSServer.cpp +++ b/src/WSServer.cpp @@ -118,12 +118,10 @@ void WSServer::onMessage(connection_hdl hdl, server::message_ptr message) return; } - QString payload = QString::fromStdString(message->get_payload()); + std::string payload = message->get_payload(); - // TODO refactor handler WSRequestHandler handler; - handler.processIncomingMessage(payload); - std::string response = handler.getResponse().toStdString(); + std::string response = handler.processIncomingMessage(payload); _server.send(hdl, response, websocketpp::frame::opcode::text); } From 62e4c42aa674728a26eeb8e180f191c1dd1a2a16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20L?= Date: Mon, 31 Dec 2018 21:29:34 +0100 Subject: [PATCH 10/19] server: stop on unload --- src/WSServer.cpp | 2 +- src/WSServer.h | 3 +-- src/obs-websocket.cpp | 9 +++++++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/WSServer.cpp b/src/WSServer.cpp index b97799f3..fc532e9c 100644 --- a/src/WSServer.cpp +++ b/src/WSServer.cpp @@ -87,8 +87,8 @@ void WSServer::start(quint16 port) void WSServer::stop() { - _server.stop(); _server.stop_listening(); + _server.stop(); blog(LOG_INFO, "server stopped successfully"); } diff --git a/src/WSServer.h b/src/WSServer.h index 2ab4fb06..d0f79541 100644 --- a/src/WSServer.h +++ b/src/WSServer.h @@ -34,7 +34,6 @@ QT_FORWARD_DECLARE_CLASS(QWebSocket) using websocketpp::connection_hdl; typedef websocketpp::server server; -typedef std::set> con_list; class WSServer : public QObject { @@ -59,7 +58,7 @@ private: server _server; quint16 _serverPort; - con_list _connections; + std::set> _connections; QMutex _clMutex; }; diff --git a/src/obs-websocket.cpp b/src/obs-websocket.cpp index c3fb0826..7923564b 100644 --- a/src/obs-websocket.cpp +++ b/src/obs-websocket.cpp @@ -51,12 +51,14 @@ bool obs_module_load(void) { WSServer::Instance = new WSServer(); WSEvents::Instance = new WSEvents(WSServer::Instance); - if (config->ServerEnabled) + if (config->ServerEnabled) { WSServer::Instance->start(config->ServerPort); + } // UI setup QAction* menu_action = (QAction*)obs_frontend_add_tools_menu_qaction( - obs_module_text("OBSWebsocket.Menu.SettingsItem")); + obs_module_text("OBSWebsocket.Menu.SettingsItem") + ); obs_frontend_push_ui_translation(obs_module_get_string); QMainWindow* main_window = (QMainWindow*)obs_frontend_get_main_window(); @@ -75,6 +77,9 @@ bool obs_module_load(void) { } void obs_module_unload() { + if (WSServer::Instance) { + WSServer::Instance->stop(); + } blog(LOG_INFO, "goodbye!"); } From 5b0410a207aa02cccdbf05dd2427a4f21ef3ebf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20L?= Date: Tue, 1 Jan 2019 01:07:50 +0100 Subject: [PATCH 11/19] server: per-connection properties --- src/WSRequestHandler.cpp | 19 ++++++++++--------- src/WSRequestHandler.h | 4 +++- src/WSRequestHandler_General.cpp | 20 ++++++++++++-------- src/WSServer.cpp | 7 ++++++- src/WSServer.h | 4 ++++ 5 files changed, 35 insertions(+), 19 deletions(-) diff --git a/src/WSRequestHandler.cpp b/src/WSRequestHandler.cpp index 5535d3c0..a414de69 100644 --- a/src/WSRequestHandler.cpp +++ b/src/WSRequestHandler.cpp @@ -128,10 +128,11 @@ QSet WSRequestHandler::authNotRequired { "Authenticate" }; -WSRequestHandler::WSRequestHandler() : +WSRequestHandler::WSRequestHandler(QVariantHash* connProperties) : _messageId(0), _requestType(""), - data(nullptr) + data(nullptr), + _connProperties(connProperties) { } @@ -160,13 +161,13 @@ std::string WSRequestHandler::processIncomingMessage(std::string& textMessage) { _requestType = obs_data_get_string(data, "request-type"); _messageId = obs_data_get_string(data, "message-id"); - // if (Config::Current()->AuthRequired - // && (_client->property(PROP_AUTHENTICATED).toBool() == false) - // && (authNotRequired.find(_requestType) == authNotRequired.end())) - // { - // SendErrorResponse("Not Authenticated"); - // return; - // } + if (Config::Current()->AuthRequired + && (!authNotRequired.contains(_requestType)) + && (_connProperties->value(PROP_AUTHENTICATED).toBool() == false)) + { + SendErrorResponse("Not Authenticated"); + return _response; + } void (*handlerFunc)(WSRequestHandler*) = (messageMap[_requestType]); diff --git a/src/WSRequestHandler.h b/src/WSRequestHandler.h index 8d69693f..86182056 100644 --- a/src/WSRequestHandler.h +++ b/src/WSRequestHandler.h @@ -22,6 +22,7 @@ with this program. If not, see #include #include +#include #include #include @@ -32,7 +33,7 @@ class WSRequestHandler : public QObject { Q_OBJECT public: - explicit WSRequestHandler(); + explicit WSRequestHandler(QVariantHash* connProperties); ~WSRequestHandler(); std::string processIncomingMessage(std::string& textMessage); bool hasField(QString name); @@ -41,6 +42,7 @@ class WSRequestHandler : public QObject { const char* _messageId; const char* _requestType; std::string _response; + QVariantHash* _connProperties; OBSDataAutoRelease data; void SendOKResponse(obs_data_t* additionalFields = NULL); diff --git a/src/WSRequestHandler_General.cpp b/src/WSRequestHandler_General.cpp index efe0b9db..76f1ca01 100644 --- a/src/WSRequestHandler_General.cpp +++ b/src/WSRequestHandler_General.cpp @@ -85,20 +85,24 @@ void WSRequestHandler::HandleAuthenticate(WSRequestHandler* req) { return; } + if (req->_connProperties->value(PROP_AUTHENTICATED).toBool() == true) { + req->SendErrorResponse("already authenticated"); + return; + } + QString auth = obs_data_get_string(req->data, "auth"); if (auth.isEmpty()) { req->SendErrorResponse("auth not specified!"); return; } - // if ((req->_client->property(PROP_AUTHENTICATED).toBool() == false) - // && Config::Current()->CheckAuth(auth)) - // { - // req->_client->setProperty(PROP_AUTHENTICATED, true); - // req->SendOKResponse(); - // } else { - // req->SendErrorResponse("Authentication Failed."); - // } + if (Config::Current()->CheckAuth(auth) == false) { + req->SendErrorResponse("Authentication Failed."); + return; + } + + req->_connProperties->insert(PROP_AUTHENTICATED, true); + req->SendOKResponse(); } /** diff --git a/src/WSServer.cpp b/src/WSServer.cpp index fc532e9c..d15e39fc 100644 --- a/src/WSServer.cpp +++ b/src/WSServer.cpp @@ -118,11 +118,15 @@ void WSServer::onMessage(connection_hdl hdl, server::message_ptr message) return; } + QVariantHash connProperties = _connectionProperties[hdl]; + std::string payload = message->get_payload(); - WSRequestHandler handler; + WSRequestHandler handler(&connProperties); std::string response = handler.processIncomingMessage(payload); + _connectionProperties[hdl] = connProperties; + _server.send(hdl, response, websocketpp::frame::opcode::text); } @@ -130,6 +134,7 @@ void WSServer::onClose(connection_hdl hdl) { QMutexLocker locker(&_clMutex); _connections.erase(hdl); + _connectionProperties.erase(hdl); locker.unlock(); QString clientIp = getRemoteEndpoint(hdl); diff --git a/src/WSServer.h b/src/WSServer.h index d0f79541..8c243700 100644 --- a/src/WSServer.h +++ b/src/WSServer.h @@ -21,8 +21,11 @@ with this program. If not, see #include #include +#include +#include #include + #include #include @@ -59,6 +62,7 @@ private: server _server; quint16 _serverPort; std::set> _connections; + std::map> _connectionProperties; QMutex _clMutex; }; From c245c247520c3a3d18b5b046e5c75c86bfed9c59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20L?= Date: Tue, 1 Jan 2019 01:18:23 +0100 Subject: [PATCH 12/19] server: broadcast to authenticated only + use references in handler --- src/WSRequestHandler.cpp | 4 ++-- src/WSRequestHandler.h | 4 ++-- src/WSRequestHandler_General.cpp | 4 ++-- src/WSServer.cpp | 16 +++++++++++++--- 4 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/WSRequestHandler.cpp b/src/WSRequestHandler.cpp index a414de69..e9c49138 100644 --- a/src/WSRequestHandler.cpp +++ b/src/WSRequestHandler.cpp @@ -128,7 +128,7 @@ QSet WSRequestHandler::authNotRequired { "Authenticate" }; -WSRequestHandler::WSRequestHandler(QVariantHash* connProperties) : +WSRequestHandler::WSRequestHandler(QVariantHash& connProperties) : _messageId(0), _requestType(""), data(nullptr), @@ -163,7 +163,7 @@ std::string WSRequestHandler::processIncomingMessage(std::string& textMessage) { if (Config::Current()->AuthRequired && (!authNotRequired.contains(_requestType)) - && (_connProperties->value(PROP_AUTHENTICATED).toBool() == false)) + && (_connProperties.value(PROP_AUTHENTICATED).toBool() == false)) { SendErrorResponse("Not Authenticated"); return _response; diff --git a/src/WSRequestHandler.h b/src/WSRequestHandler.h index 86182056..9fab30e4 100644 --- a/src/WSRequestHandler.h +++ b/src/WSRequestHandler.h @@ -33,7 +33,7 @@ class WSRequestHandler : public QObject { Q_OBJECT public: - explicit WSRequestHandler(QVariantHash* connProperties); + explicit WSRequestHandler(QVariantHash& connProperties); ~WSRequestHandler(); std::string processIncomingMessage(std::string& textMessage); bool hasField(QString name); @@ -42,7 +42,7 @@ class WSRequestHandler : public QObject { const char* _messageId; const char* _requestType; std::string _response; - QVariantHash* _connProperties; + QVariantHash& _connProperties; OBSDataAutoRelease data; void SendOKResponse(obs_data_t* additionalFields = NULL); diff --git a/src/WSRequestHandler_General.cpp b/src/WSRequestHandler_General.cpp index 76f1ca01..c88abb35 100644 --- a/src/WSRequestHandler_General.cpp +++ b/src/WSRequestHandler_General.cpp @@ -85,7 +85,7 @@ void WSRequestHandler::HandleAuthenticate(WSRequestHandler* req) { return; } - if (req->_connProperties->value(PROP_AUTHENTICATED).toBool() == true) { + if (req->_connProperties.value(PROP_AUTHENTICATED).toBool() == true) { req->SendErrorResponse("already authenticated"); return; } @@ -101,7 +101,7 @@ void WSRequestHandler::HandleAuthenticate(WSRequestHandler* req) { return; } - req->_connProperties->insert(PROP_AUTHENTICATED, true); + req->_connProperties.insert(PROP_AUTHENTICATED, true); req->SendOKResponse(); } diff --git a/src/WSServer.cpp b/src/WSServer.cpp index d15e39fc..a7098d64 100644 --- a/src/WSServer.cpp +++ b/src/WSServer.cpp @@ -96,6 +96,12 @@ void WSServer::broadcast(QString message) { QMutexLocker locker(&_clMutex); for (connection_hdl hdl : _connections) { + if (Config::Current()->AuthRequired) { + bool authenticated = _connectionProperties[hdl].value(PROP_AUTHENTICATED).toBool(); + if (!authenticated) { + continue; + } + } _server.send(hdl, message.toStdString(), websocketpp::frame::opcode::text); } } @@ -118,16 +124,20 @@ void WSServer::onMessage(connection_hdl hdl, server::message_ptr message) return; } + QMutexLocker locker(&_clMutex); QVariantHash connProperties = _connectionProperties[hdl]; + locker.unlock(); std::string payload = message->get_payload(); - WSRequestHandler handler(&connProperties); + WSRequestHandler handler(connProperties); std::string response = handler.processIncomingMessage(payload); - _connectionProperties[hdl] = connProperties; - _server.send(hdl, response, websocketpp::frame::opcode::text); + + locker.relock(); + _connectionProperties[hdl] = connProperties; + locker.unlock(); } void WSServer::onClose(connection_hdl hdl) From 7d1f0e2a69c50ea76f66c03b640f927cd1ae33e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20L?= Date: Tue, 1 Jan 2019 04:55:15 +0100 Subject: [PATCH 13/19] server: refactored singleton with QSharedPointer --- src/WSEvents.cpp | 2 +- src/WSEvents.h | 4 ++-- src/WSServer.cpp | 21 +++++++++++++++++---- src/WSServer.h | 12 ++++++++++-- src/forms/settings-dialog.cpp | 4 ++-- src/obs-websocket.cpp | 9 +++------ 6 files changed, 35 insertions(+), 17 deletions(-) diff --git a/src/WSEvents.cpp b/src/WSEvents.cpp index 7bf30dc7..4fbd1d73 100644 --- a/src/WSEvents.cpp +++ b/src/WSEvents.cpp @@ -64,7 +64,7 @@ void* calldata_get_ptr(const calldata_t* data, const char* name) { WSEvents* WSEvents::Instance = nullptr; -WSEvents::WSEvents(WSServer* srv) { +WSEvents::WSEvents(WSServerPtr srv) { _srv = srv; obs_frontend_add_event_callback(WSEvents::FrontendEventHandler, this); diff --git a/src/WSEvents.h b/src/WSEvents.h index 7b7cf95e..086d8a4f 100644 --- a/src/WSEvents.h +++ b/src/WSEvents.h @@ -28,7 +28,7 @@ with this program. If not, see class WSEvents : public QObject { Q_OBJECT public: - explicit WSEvents(WSServer* srv); + explicit WSEvents(WSServerPtr srv); ~WSEvents(); static void FrontendEventHandler( enum obs_frontend_event event, void* privateData); @@ -51,7 +51,7 @@ class WSEvents : public QObject { void TransitionDurationChanged(int ms); private: - WSServer* _srv; + WSServerPtr _srv; OBSSource currentScene; bool pulse; diff --git a/src/WSServer.cpp b/src/WSServer.cpp index a7098d64..0c1fe7e7 100644 --- a/src/WSServer.cpp +++ b/src/WSServer.cpp @@ -34,8 +34,6 @@ using websocketpp::lib::placeholders::_1; using websocketpp::lib::placeholders::_2; using websocketpp::lib::bind; -WSServer* WSServer::Instance = nullptr; - QString decodeBase64(const QString& source) { return QString::fromUtf8( @@ -45,8 +43,23 @@ QString decodeBase64(const QString& source) ); } -WSServer::WSServer(QObject* parent) - : QObject(parent), +WSServerPtr WSServer::_instance = WSServerPtr(nullptr); + +WSServerPtr WSServer::Current() +{ + if (!_instance) { + ResetCurrent(); + } + return _instance; +} + +void WSServer::ResetCurrent() +{ + _instance = WSServerPtr(new WSServer()); +} + +WSServer::WSServer() + : QObject(nullptr), _connections(), _clMutex(QMutex::Recursive) { diff --git a/src/WSServer.h b/src/WSServer.h index 8c243700..6cfd120b 100644 --- a/src/WSServer.h +++ b/src/WSServer.h @@ -21,6 +21,7 @@ with this program. If not, see #include #include +#include #include #include @@ -38,19 +39,26 @@ using websocketpp::connection_hdl; typedef websocketpp::server server; +class WSServer; +typedef QSharedPointer WSServerPtr; + class WSServer : public QObject { Q_OBJECT public: - explicit WSServer(QObject* parent = Q_NULLPTR); + static WSServerPtr Current(); + static void ResetCurrent(); + + explicit WSServer(); virtual ~WSServer(); void start(quint16 port); void stop(); void broadcast(QString message); - static WSServer* Instance; private: + static WSServerPtr _instance; + void onOpen(connection_hdl hdl); void onMessage(connection_hdl hdl, server::message_ptr message); void onClose(connection_hdl hdl); diff --git a/src/forms/settings-dialog.cpp b/src/forms/settings-dialog.cpp index 5378faaf..b0c78116 100644 --- a/src/forms/settings-dialog.cpp +++ b/src/forms/settings-dialog.cpp @@ -94,9 +94,9 @@ void SettingsDialog::FormAccepted() { conf->Save(); if (conf->ServerEnabled) - WSServer::Instance->start(conf->ServerPort); + WSServer::Current()->start(conf->ServerPort); else - WSServer::Instance->stop(); + WSServer::Current()->stop(); } SettingsDialog::~SettingsDialog() { diff --git a/src/obs-websocket.cpp b/src/obs-websocket.cpp index 7923564b..69bfc2c7 100644 --- a/src/obs-websocket.cpp +++ b/src/obs-websocket.cpp @@ -48,11 +48,10 @@ bool obs_module_load(void) { Config* config = Config::Current(); config->Load(); - WSServer::Instance = new WSServer(); - WSEvents::Instance = new WSEvents(WSServer::Instance); + WSEvents::Instance = new WSEvents(WSServer::Current()); if (config->ServerEnabled) { - WSServer::Instance->start(config->ServerPort); + WSServer::Current()->start(config->ServerPort); } // UI setup @@ -77,9 +76,7 @@ bool obs_module_load(void) { } void obs_module_unload() { - if (WSServer::Instance) { - WSServer::Instance->stop(); - } + WSServer::Current()->stop(); blog(LOG_INFO, "goodbye!"); } From 9405b17e14e90b927d2760b4e3c6ebfa7ceb13d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20L?= Date: Tue, 1 Jan 2019 05:00:43 +0100 Subject: [PATCH 14/19] config: singleton shared pointer refactor --- src/Config.cpp | 12 ++++++------ src/Config.h | 10 +++++++--- src/forms/settings-dialog.cpp | 4 ++-- src/obs-websocket.cpp | 2 +- 4 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/Config.cpp b/src/Config.cpp index 43ea8d99..c38bd1ad 100644 --- a/src/Config.cpp +++ b/src/Config.cpp @@ -36,7 +36,12 @@ with this program. If not, see #define QT_TO_UTF8(str) str.toUtf8().constData() -Config* Config::_instance = new Config(); +ConfigPtr Config::_instance = ConfigPtr(new Config()); + +ConfigPtr Config::Current() +{ + return _instance; +} Config::Config() : ServerEnabled(true), @@ -179,8 +184,3 @@ bool Config::CheckAuth(QString response) return authSuccess; } - -Config* Config::Current() -{ - return _instance; -} diff --git a/src/Config.h b/src/Config.h index 80f3c0cd..8966f2d0 100644 --- a/src/Config.h +++ b/src/Config.h @@ -20,9 +20,15 @@ with this program. If not, see #define CONFIG_H #include +#include + +class Config; +typedef QSharedPointer ConfigPtr; class Config { public: + static ConfigPtr Current(); + Config(); ~Config(); void Load(); @@ -46,10 +52,8 @@ class Config { QString SessionChallenge; bool SettingsLoaded; - static Config* Current(); - private: - static Config* _instance; + static ConfigPtr _instance; }; #endif // CONFIG_H diff --git a/src/forms/settings-dialog.cpp b/src/forms/settings-dialog.cpp index b0c78116..5778aa4e 100644 --- a/src/forms/settings-dialog.cpp +++ b/src/forms/settings-dialog.cpp @@ -41,7 +41,7 @@ SettingsDialog::SettingsDialog(QWidget* parent) : } void SettingsDialog::showEvent(QShowEvent* event) { - Config* conf = Config::Current(); + auto conf = Config::Current(); ui->serverEnabled->setChecked(conf->ServerEnabled); ui->serverPort->setValue(conf->ServerPort); @@ -68,7 +68,7 @@ void SettingsDialog::AuthCheckboxChanged() { } void SettingsDialog::FormAccepted() { - Config* conf = Config::Current(); + auto conf = Config::Current(); conf->ServerEnabled = ui->serverEnabled->isChecked(); conf->ServerPort = ui->serverPort->value(); diff --git a/src/obs-websocket.cpp b/src/obs-websocket.cpp index 69bfc2c7..e04f0809 100644 --- a/src/obs-websocket.cpp +++ b/src/obs-websocket.cpp @@ -45,7 +45,7 @@ bool obs_module_load(void) { QT_VERSION_STR, qVersion()); // Core setup - Config* config = Config::Current(); + auto config = Config::Current(); config->Load(); WSEvents::Instance = new WSEvents(WSServer::Current()); From 2e5b903eaecdd32c75852aa0b9e6c64e618df622 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20L?= Date: Tue, 1 Jan 2019 05:07:55 +0100 Subject: [PATCH 15/19] events: singleton shared pointer refactor --- src/WSEvents.cpp | 10 +++++++++- src/WSEvents.h | 24 ++++++++++++++++++------ src/WSRequestHandler_General.cpp | 8 ++++---- src/WSRequestHandler_Streaming.cpp | 6 ++++-- src/obs-websocket.cpp | 2 +- 5 files changed, 36 insertions(+), 14 deletions(-) diff --git a/src/WSEvents.cpp b/src/WSEvents.cpp index 4fbd1d73..85404737 100644 --- a/src/WSEvents.cpp +++ b/src/WSEvents.cpp @@ -62,7 +62,15 @@ void* calldata_get_ptr(const calldata_t* data, const char* name) { return ptr; } -WSEvents* WSEvents::Instance = nullptr; +WSEventsPtr WSEvents::_instance = WSEventsPtr(nullptr); + +WSEventsPtr WSEvents::Current() { + return _instance; +} + +void WSEvents::ResetCurrent(WSServerPtr srv) { + _instance = WSEventsPtr(new WSEvents(srv)); +} WSEvents::WSEvents(WSServerPtr srv) { _srv = srv; diff --git a/src/WSEvents.h b/src/WSEvents.h index 086d8a4f..97187404 100644 --- a/src/WSEvents.h +++ b/src/WSEvents.h @@ -22,17 +22,27 @@ with this program. If not, see #include #include + #include +#include + #include "WSServer.h" -class WSEvents : public QObject { - Q_OBJECT - public: +class WSEvents; +typedef QSharedPointer WSEventsPtr; + +class WSEvents : public QObject +{ +Q_OBJECT + +public: + static WSEventsPtr Current(); + static void ResetCurrent(WSServerPtr srv); + explicit WSEvents(WSServerPtr srv); ~WSEvents(); static void FrontendEventHandler( enum obs_frontend_event event, void* privateData); - static WSEvents* Instance; void connectSceneSignals(obs_source_t* scene); void hookTransitionBeginEvent(); @@ -44,13 +54,15 @@ class WSEvents : public QObject { bool HeartbeatIsActive; - private slots: +private slots: void deferredInitOperations(); void StreamStatus(); void Heartbeat(); void TransitionDurationChanged(int ms); - private: +private: + static WSEventsPtr _instance; + WSServerPtr _srv; OBSSource currentScene; diff --git a/src/WSRequestHandler_General.cpp b/src/WSRequestHandler_General.cpp index c88abb35..10dd999b 100644 --- a/src/WSRequestHandler_General.cpp +++ b/src/WSRequestHandler_General.cpp @@ -121,12 +121,12 @@ void WSRequestHandler::HandleAuthenticate(WSRequestHandler* req) { return; } - WSEvents::Instance->HeartbeatIsActive = - obs_data_get_bool(req->data, "enable"); + auto events = WSEvents::Current(); + + events->HeartbeatIsActive = obs_data_get_bool(req->data, "enable"); OBSDataAutoRelease response = obs_data_create(); - obs_data_set_bool(response, "enable", - WSEvents::Instance->HeartbeatIsActive); + obs_data_set_bool(response, "enable", events->HeartbeatIsActive); req->SendOKResponse(response); } diff --git a/src/WSRequestHandler_Streaming.cpp b/src/WSRequestHandler_Streaming.cpp index cca33cee..fc3d660d 100644 --- a/src/WSRequestHandler_Streaming.cpp +++ b/src/WSRequestHandler_Streaming.cpp @@ -21,6 +21,8 @@ * @since 0.3 */ void WSRequestHandler::HandleGetStreamingStatus(WSRequestHandler* req) { + auto events = WSEvents::Current(); + OBSDataAutoRelease data = obs_data_create(); obs_data_set_bool(data, "streaming", obs_frontend_streaming_active()); obs_data_set_bool(data, "recording", obs_frontend_recording_active()); @@ -28,13 +30,13 @@ const char* tc = nullptr; if (obs_frontend_streaming_active()) { - tc = WSEvents::Instance->GetStreamingTimecode(); + tc = events->GetStreamingTimecode(); obs_data_set_string(data, "stream-timecode", tc); bfree((void*)tc); } if (obs_frontend_recording_active()) { - tc = WSEvents::Instance->GetRecordingTimecode(); + tc = events->GetRecordingTimecode(); obs_data_set_string(data, "rec-timecode", tc); bfree((void*)tc); } diff --git a/src/obs-websocket.cpp b/src/obs-websocket.cpp index e04f0809..9939f8da 100644 --- a/src/obs-websocket.cpp +++ b/src/obs-websocket.cpp @@ -48,7 +48,7 @@ bool obs_module_load(void) { auto config = Config::Current(); config->Load(); - WSEvents::Instance = new WSEvents(WSServer::Current()); + WSEvents::ResetCurrent(WSServer::Current()); if (config->ServerEnabled) { WSServer::Current()->start(config->ServerPort); From 5748c4d0ec9170a5ca16d4bef56878e465607749 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20L?= Date: Tue, 1 Jan 2019 05:13:08 +0100 Subject: [PATCH 16/19] general: fix crash on exit --- src/WSServer.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/WSServer.cpp b/src/WSServer.cpp index 0c1fe7e7..e604c8f9 100644 --- a/src/WSServer.cpp +++ b/src/WSServer.cpp @@ -100,6 +100,10 @@ void WSServer::start(quint16 port) void WSServer::stop() { + if (!_server.is_listening()) { + return; + } + _server.stop_listening(); _server.stop(); blog(LOG_INFO, "server stopped successfully"); From 11617eea9933ee73a83f337283efd122f62640d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20L?= Date: Tue, 1 Jan 2019 05:16:57 +0100 Subject: [PATCH 17/19] server: remove useless base64 helper --- src/WSServer.cpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/WSServer.cpp b/src/WSServer.cpp index e604c8f9..6230258b 100644 --- a/src/WSServer.cpp +++ b/src/WSServer.cpp @@ -34,15 +34,6 @@ using websocketpp::lib::placeholders::_1; using websocketpp::lib::placeholders::_2; using websocketpp::lib::bind; -QString decodeBase64(const QString& source) -{ - return QString::fromUtf8( - QByteArray::fromBase64( - source.toUtf8() - ) - ); -} - WSServerPtr WSServer::_instance = WSServerPtr(nullptr); WSServerPtr WSServer::Current() From 40e2d410dd40a6adbab55efbdc7a223433a3b68c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20L?= Date: Tue, 1 Jan 2019 05:29:51 +0100 Subject: [PATCH 18/19] server: use std::string in broadcast --- src/WSEvents.cpp | 2 +- src/WSServer.cpp | 4 ++-- src/WSServer.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/WSEvents.cpp b/src/WSEvents.cpp index 85404737..29aa8428 100644 --- a/src/WSEvents.cpp +++ b/src/WSEvents.cpp @@ -222,7 +222,7 @@ void WSEvents::broadcastUpdate(const char* updateType, obs_data_apply(update, additionalFields); QString json = obs_data_get_json(update); - _srv->broadcast(json); + _srv->broadcast(json.toStdString()); if (Config::Current()->DebugEnabled) blog(LOG_DEBUG, "Update << '%s'", json.toUtf8().constData()); diff --git a/src/WSServer.cpp b/src/WSServer.cpp index 6230258b..885cc59f 100644 --- a/src/WSServer.cpp +++ b/src/WSServer.cpp @@ -100,7 +100,7 @@ void WSServer::stop() blog(LOG_INFO, "server stopped successfully"); } -void WSServer::broadcast(QString message) +void WSServer::broadcast(std::string message) { QMutexLocker locker(&_clMutex); for (connection_hdl hdl : _connections) { @@ -110,7 +110,7 @@ void WSServer::broadcast(QString message) continue; } } - _server.send(hdl, message.toStdString(), websocketpp::frame::opcode::text); + _server.send(hdl, message, websocketpp::frame::opcode::text); } } diff --git a/src/WSServer.h b/src/WSServer.h index 6cfd120b..eee056d8 100644 --- a/src/WSServer.h +++ b/src/WSServer.h @@ -54,7 +54,7 @@ public: virtual ~WSServer(); void start(quint16 port); void stop(); - void broadcast(QString message); + void broadcast(std::string message); private: static WSServerPtr _instance; From baac1b1d80474da879f93c1440b25d60fae80f68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20L?= Date: Tue, 1 Jan 2019 15:57:29 +0100 Subject: [PATCH 19/19] server: clarifying things --- src/WSServer.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/WSServer.cpp b/src/WSServer.cpp index 885cc59f..b3dc834e 100644 --- a/src/WSServer.cpp +++ b/src/WSServer.cpp @@ -132,18 +132,22 @@ void WSServer::onMessage(connection_hdl hdl, server::message_ptr message) return; } + std::string payload = message->get_payload(); + QMutexLocker locker(&_clMutex); QVariantHash connProperties = _connectionProperties[hdl]; locker.unlock(); - std::string payload = message->get_payload(); - WSRequestHandler handler(connProperties); std::string response = handler.processIncomingMessage(payload); _server.send(hdl, response, websocketpp::frame::opcode::text); locker.relock(); + // In multithreaded processing this would be problematic to put back + // a copy of the connection properties, because there might conflicts + // between several simultaneous handlers. + // In our case, it's fine because all messages are processed in one thread. _connectionProperties[hdl] = connProperties; locker.unlock(); }