181 lines
6.0 KiB
C++
181 lines
6.0 KiB
C++
#include "websocketserver.h"
|
|
#include "loggingcategories.h"
|
|
|
|
#include <QCoreApplication>
|
|
|
|
namespace remoteproxy {
|
|
|
|
WebSocketServer::WebSocketServer(const QSslConfiguration &sslConfiguration, QObject *parent) :
|
|
TransportInterface(parent),
|
|
m_sslConfiguration(sslConfiguration)
|
|
{
|
|
m_serverName = "Websocket server";
|
|
}
|
|
|
|
WebSocketServer::~WebSocketServer()
|
|
{
|
|
stopServer();
|
|
}
|
|
|
|
QUrl WebSocketServer::serverUrl() const
|
|
{
|
|
return m_serverUrl;
|
|
}
|
|
|
|
void WebSocketServer::setServerUrl(const QUrl &serverUrl)
|
|
{
|
|
m_serverUrl = serverUrl;
|
|
}
|
|
|
|
bool WebSocketServer::running() const
|
|
{
|
|
if (!m_server)
|
|
return false;
|
|
|
|
return m_server->isListening();
|
|
}
|
|
|
|
QSslConfiguration WebSocketServer::sslConfiguration() const
|
|
{
|
|
return m_sslConfiguration;
|
|
}
|
|
|
|
void WebSocketServer::sendData(const QUuid &clientId, const QByteArray &data)
|
|
{
|
|
QWebSocket *client = nullptr;
|
|
client = m_clientList.value(clientId);
|
|
if (client) {
|
|
qCDebug(dcWebSocketServerTraffic()) << "--> Sending data to client:" << data;
|
|
client->sendTextMessage(data);
|
|
} else {
|
|
qCWarning(dcWebSocketServer()) << "Client" << clientId << "unknown to this transport";
|
|
}
|
|
}
|
|
|
|
void WebSocketServer::sendData(const QList<QUuid> &clients, const QByteArray &data)
|
|
{
|
|
foreach (const QUuid &client, clients) {
|
|
sendData(client, data);
|
|
}
|
|
}
|
|
|
|
void WebSocketServer::killClientConnection(const QUuid &clientId, const QString &killReason)
|
|
{
|
|
QWebSocket *client = m_clientList.value(clientId);
|
|
if (!client)
|
|
return;
|
|
|
|
qCWarning(dcWebSocketServer()) << "Kill client connection" << clientId.toString() << "Reason:" << killReason;
|
|
client->close(QWebSocketProtocol::CloseCodeBadOperation, killReason);
|
|
}
|
|
|
|
void WebSocketServer::onClientConnected()
|
|
{
|
|
// Got a new client connected
|
|
QWebSocket *client = m_server->nextPendingConnection();
|
|
|
|
// 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;
|
|
}
|
|
|
|
// Create new uuid for this connection
|
|
QUuid clientId = QUuid::createUuid();
|
|
qCDebug(dcWebSocketServer()) << "New client connected:" << client << client->peerAddress().toString() << clientId.toString();
|
|
|
|
// 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 = static_cast<QWebSocket *>(sender());
|
|
QUuid clientId = m_clientList.key(client);
|
|
|
|
qCDebug(dcWebSocketServer()) << "Client disconnected:" << client << client->peerAddress().toString() << clientId.toString() << client->closeReason();
|
|
|
|
m_clientList.take(clientId)->deleteLater();
|
|
emit clientDisconnected(clientId);
|
|
}
|
|
|
|
void WebSocketServer::onBinaryMessageReceived(const QByteArray &data)
|
|
{
|
|
QWebSocket *client = static_cast<QWebSocket *>(sender());
|
|
qCDebug(dcWebSocketServerTraffic()) << "<-- Binary message from" << client->peerAddress().toString() << ":" << data;
|
|
}
|
|
|
|
void WebSocketServer::onTextMessageReceived(const QString &message)
|
|
{
|
|
QWebSocket *client = static_cast<QWebSocket *>(sender());
|
|
qCDebug(dcWebSocketServerTraffic()) << "Text message from" << client->peerAddress().toString() << ":" << message;
|
|
emit dataAvailable(m_clientList.key(client), message.toUtf8());
|
|
}
|
|
|
|
void WebSocketServer::onClientError(QAbstractSocket::SocketError error)
|
|
{
|
|
QWebSocket *client = static_cast<QWebSocket *>(sender());
|
|
qCWarning(dcWebSocketServer()) << "Client error occured:" << error << client->errorString();
|
|
}
|
|
|
|
void WebSocketServer::onServerError(QAbstractSocket::SocketError error)
|
|
{
|
|
qCWarning(dcWebSocketServer()) << "Server error occured:" << error << m_server->errorString();
|
|
}
|
|
|
|
void WebSocketServer::onPing(quint64 elapsedTime, const QByteArray &payload)
|
|
{
|
|
QWebSocket *client = static_cast<QWebSocket *>(sender());
|
|
qCDebug(dcWebSocketServer) << "ping response" << client->peerAddress() << elapsedTime << payload;
|
|
}
|
|
|
|
bool WebSocketServer::startServer()
|
|
{
|
|
m_server = new QWebSocketServer(QCoreApplication::applicationName(), QWebSocketServer::SecureMode, this);
|
|
m_server->setSslConfiguration(sslConfiguration());
|
|
|
|
connect (m_server, &QWebSocketServer::newConnection, this, &WebSocketServer::onClientConnected);
|
|
connect (m_server, &QWebSocketServer::acceptError, this, &WebSocketServer::onServerError);
|
|
|
|
qCDebug(dcWebSocketServer()) << "Starting server" << m_server->serverName() << serverUrl().toString();
|
|
if (!m_server->listen(QHostAddress(m_serverUrl.host()), static_cast<quint16>(serverUrl().port()))) {
|
|
qCWarning(dcWebSocketServer()) << "Server" << m_server->serverName() << "could not listen on" << serverUrl().toString();
|
|
delete m_server;
|
|
m_server = nullptr;
|
|
return false;
|
|
}
|
|
|
|
qCDebug(dcWebSocketServer()) << "Server started successfully.";
|
|
return true;
|
|
}
|
|
|
|
bool WebSocketServer::stopServer()
|
|
{
|
|
// Clean up client connections
|
|
foreach (QWebSocket *client, m_clientList.values()) {
|
|
client->close(QWebSocketProtocol::CloseCodeNormal, "Stop server");
|
|
}
|
|
|
|
// Delete the server object
|
|
if (m_server) {
|
|
qCDebug(dcWebSocketServer()) << "Stop server" << m_server->serverName() << serverUrl().toString();
|
|
m_server->close();
|
|
delete m_server;
|
|
m_server = nullptr;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
}
|