/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Copyright (C) 2015 Simon Stuerz * * * * This file is part of guh. * * * * Guh is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, version 2 of the License. * * * * Guh 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 General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with guh. If not, see . * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "websocketserver.h" #include "guhsettings.h" #include "loggingcategories.h" #include #include namespace guhserver { WebSocketServer::WebSocketServer(const QSslConfiguration &sslConfiguration, QObject *parent) : TransportInterface(parent), m_server(0), m_sslConfiguration(sslConfiguration), m_useSsl(false), m_enabled(false) { // load webserver settings GuhSettings settings(GuhSettings::SettingsRoleGlobal); qCDebug(dcWebServer) << "Loading webserver settings from" << settings.fileName(); settings.beginGroup("WebSocketServer"); // 4444 Official free according to https://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers m_port = settings.value("port", 4444).toInt(); m_useSsl = settings.value("https", false).toBool(); settings.endGroup(); // check SSL if (m_useSsl && m_sslConfiguration.isNull()) m_useSsl = false; } WebSocketServer::~WebSocketServer() { } void WebSocketServer::sendData(const QUuid &clientId, const QVariantMap &data) { QWebSocket *client = 0; client = m_clientList.value(clientId); if (client) { client->sendTextMessage(QJsonDocument::fromVariant(data).toJson()); } } void WebSocketServer::sendData(const QList &clients, const QVariantMap &data) { foreach (const QUuid &client, clients) { sendData(client, data); } } void WebSocketServer::onClientConnected() { // got a new client connected QWebSocket *client = m_server->nextPendingConnection(); qCDebug(dcConnection) << "Websocket server: new client connected:" << client->peerAddress().toString(); // check websocket version if (client->version() != QWebSocketProtocol::Version13) { qCWarning(dcWebSocketServer) << "Client with invalid protocol version" << client->version() << ". Rejecting."; client->close(QWebSocketProtocol::CloseCodeProtocolError, QString("invalid protocol version: %1 != Supported Version 13").arg(client->version())); delete client; return; } QUuid clientId = QUuid::createUuid(); // append the new client to the client list m_clientList.insert(clientId, client); connect(client, SIGNAL(pong(quint64,QByteArray)), this, SLOT(onPing(quint64,QByteArray))); connect(client, SIGNAL(binaryMessageReceived(QByteArray)), this, SLOT(onBinaryMessageReceived(QByteArray))); connect(client, SIGNAL(textMessageReceived(QString)), this, SLOT(onTextMessageReceived(QString))); connect(client, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onClientError(QAbstractSocket::SocketError))); connect(client, SIGNAL(disconnected()), this, SLOT(onClientDisconnected())); emit clientConnected(clientId); } void WebSocketServer::onClientDisconnected() { QWebSocket *client = qobject_cast(sender()); qCDebug(dcConnection) << "Websocket server: client disconnected:" << client->peerAddress().toString(); QUuid clientId = m_clientList.key(client); m_clientList.take(clientId)->deleteLater(); } void WebSocketServer::onBinaryMessageReceived(const QByteArray &data) { QWebSocket *client = qobject_cast(sender()); qCDebug(dcWebSocketServer) << "Binary message from" << client->peerAddress().toString() << ":" << data; } void WebSocketServer::onTextMessageReceived(const QString &message) { QWebSocket *client = qobject_cast(sender()); qCDebug(dcWebSocketServer) << "Text message from" << client->peerAddress().toString() << ":" << message; validateMessage(m_clientList.key(client), message.toUtf8()); } void WebSocketServer::onClientError(QAbstractSocket::SocketError error) { QWebSocket *client = qobject_cast(sender()); qCWarning(dcConnection) << "Websocket client error:" << error << client->errorString(); } void WebSocketServer::onServerError(QAbstractSocket::SocketError error) { qCWarning(dcConnection) << "Websocket server error:" << error << m_server->errorString(); } void WebSocketServer::onPing(quint64 elapsedTime, const QByteArray &payload) { QWebSocket *client = qobject_cast(sender()); qCDebug(dcWebSocketServer) << "ping response" << client->peerAddress() << elapsedTime << payload; } bool WebSocketServer::startServer() { if (m_server) { qCWarning(dcConnection) << "There is allready a websocket server instance. This should never happen!!! Please report this bug!"; return false; } if (m_useSsl) { m_server = new QWebSocketServer("guh", QWebSocketServer::SecureMode, this); m_server->setSslConfiguration(m_sslConfiguration); } else { m_server = new QWebSocketServer("guh", QWebSocketServer::NonSecureMode, this); } connect (m_server, &QWebSocketServer::newConnection, this, &WebSocketServer::onClientConnected); connect (m_server, &QWebSocketServer::acceptError, this, &WebSocketServer::onServerError); if (!m_server->listen(QHostAddress::Any, m_port)) { qCWarning(dcConnection) << "Websocket server" << m_server->serverName() << QString("could not listen on %1:%2").arg(m_server->serverAddress().toString()).arg(m_port); return false; } if (m_server->secureMode() == QWebSocketServer::NonSecureMode) { qCDebug(dcConnection) << "Started websocket server" << m_server->serverName() << QString("on ws://%1:%2").arg(m_server->serverAddress().toString()).arg(m_port); } else { qCDebug(dcConnection) << "Started websocket server" << m_server->serverName() << QString("on wss://%1:%2").arg(m_server->serverAddress().toString()).arg(m_port); } return true; } bool WebSocketServer::stopServer() { qCDebug(dcConnection) << "Stopping websocket server"; m_server->close(); delete m_server; m_server = 0; return false; } }