C
Message Proxy: Testing Qt Safe Renderer Messaging Interface
// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial
// This file is part of the Qt Safe Renderer module
#include <QtNetwork/QTcpSocket>
#include <QtSafeRenderer/qsafeevent.h>
#include <qsafeeventsender.h>
#include "server.h"
Server::Server(const quint16 port, QObject *parent)
: QObject(parent)
{
runServer(port);
}
void Server::runServer(const quint16 port)
{
m_tcpServer = new QTcpServer(this);
if (!m_tcpServer->listen(QHostAddress::Any, port)) {
qCritical() << "Unable to start the server: " << m_tcpServer->errorString();
return;
}
connect(m_tcpServer, &QTcpServer::newConnection, this, &Server::newConnection);
QString ipAddress;
QList<QHostAddress> ipAddressesList = QNetworkInterface::allAddresses();
// use the first non-localhost IPv4 address
for (int i = 0U; i < ipAddressesList.size(); ++i) {
if (ipAddressesList.at(i) != QHostAddress::LocalHost &&
ipAddressesList.at(i).toIPv4Address()) {
ipAddress = ipAddressesList.at(i).toString();
break;
}
}
// if we did not find one, use IPv4 localhost
if (ipAddress.isEmpty())
ipAddress = QHostAddress(QHostAddress::LocalHost).toString();
qDebug() << "The server is running on: " << ipAddress << ":" << m_tcpServer->serverPort();
}
void Server::newConnection()
{
QTcpSocket *clientConnection = m_tcpServer->nextPendingConnection();
// Initialize buffer for this client
m_clientBuffers[clientConnection] = QByteArray();
connect(clientConnection, &QAbstractSocket::disconnected,
this, &Server::clientDisconnected);
connect(clientConnection, &QAbstractSocket::disconnected,
clientConnection, &QObject::deleteLater);
connect(clientConnection, &QAbstractSocket::readyRead,
this, &Server::readData);
}
void Server::clientDisconnected()
{
QTcpSocket *clientConnection = qobject_cast<QTcpSocket *>(QObject::sender());
if (clientConnection) {
// Clean up the buffer for this client
m_clientBuffers.remove(clientConnection);
}
}
static bool sendReply(QTcpSocket &clientConnection, const SafeRenderer::QSafeEvent &reply)
{
bool success = false;
// Check if socket is still connected before attempting to write
if (clientConnection.state() == QAbstractSocket::ConnectedState) {
const quint64 bytesWritten = clientConnection.write(reinterpret_cast<const char*>(reply.rawData()), SafeRenderer::QSafeEvent::messageLength);
if (bytesWritten == SafeRenderer::QSafeEvent::messageLength) {
success = true;
} else {
qDebug() << "Failed to write reply to client"
<< ", error:" << clientConnection.errorString();
}
}
return success;
}
void Server::handleVerificationRequest(const SafeRenderer::QSafeEvent &request, QTcpSocket &clientConnection)
{
bool success = false;
SafeRenderer::QSafeEvent reply;
SafeRenderer::QSafeEventSender::QSafeEventSenderStatus status = m_messageSender.sendEvent(request, reply);
if (status == SafeRenderer::QSafeEventSender::Success) {
if (sendReply(clientConnection, reply)) {
success = true;
}
}
if (!success) {
qDebug() << "Failed to send request to renderer.";
}
}
void Server::readData()
{
QTcpSocket *clientConnection = qobject_cast<QTcpSocket *>(QObject::sender());
if (clientConnection) {
// Read all available data and append to client's buffer
QByteArray newData = clientConnection->readAll();
if (newData.size() > 0) {
// Append to the existing buffer for this client
m_clientBuffers[clientConnection].append(newData);
QByteArray &buffer = m_clientBuffers[clientConnection];
// Process all complete messages in the buffer
quint8 dataBuffer[SafeRenderer::QSafeEvent::messageLength];
while (buffer.size() >= SafeRenderer::QSafeEvent::messageLength) {
// Copy one complete message
std::copy(buffer.data(), buffer.data() + SafeRenderer::QSafeEvent::messageLength, dataBuffer);
SafeRenderer::QSafeEvent safeEvent(dataBuffer);
if (safeEvent.getEventId() == SafeRenderer::EventId::EventOutputVerificationStatusRequest) {
handleVerificationRequest(safeEvent, *clientConnection);
} else {
m_messageSender.sendEvent(safeEvent);
}
// Remove the processed message from the buffer
buffer.remove(0, SafeRenderer::QSafeEvent::messageLength);
}
}
}
}