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"
namespace {
constexpr int MaxReadBufferSize = 1024;
} // anonymous namespace
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();
connect(clientConnection, &QAbstractSocket::disconnected,
clientConnection, &QObject::deleteLater);
connect(clientConnection, &QAbstractSocket::readyRead,
this, &Server::readData);
}
static bool sendReply(QTcpSocket &clientConnection, const SafeRenderer::QSafeEvent &reply)
{
bool success = false;
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 send reply to client";
}
return success;
}
void Server::handleVerificationRequest(const SafeRenderer::QSafeEvent &request, QTcpSocket &clientConnection)
{
SafeRenderer::QSafeEvent reply;
SafeRenderer::QSafeEventSender::QSafeEventSenderStatus status = m_messageSender.sendEvent(request, reply);
if (status == SafeRenderer::QSafeEventSender::Success) {
sendReply(clientConnection, reply);
} else {
qDebug() << "Failed to send request to renderer.";
}
}
void Server::readData()
{
QTcpSocket *clientConnection = qobject_cast<QTcpSocket *>(QObject::sender());
if (clientConnection) {
quint8 dataBuffer[SafeRenderer::QSafeEvent::messageLength];
char readBuffer[MaxReadBufferSize];
quint32 writePointer = 0;
int bytesRead = 0;
do {
bytesRead = clientConnection->read(&readBuffer[writePointer], MaxReadBufferSize - writePointer);
if (bytesRead == 0) {
// No more data
} else if (bytesRead == -1) {
// Socket closed / disconnected / read error
} else {
writePointer += bytesRead;
}
} while (bytesRead > 0);
// Now handle all the packets received
QByteArray data(readBuffer, writePointer);
quint32 dataLeft = writePointer;
quint32 readPointer = 0;
do {
if (dataLeft >= SafeRenderer::QSafeEvent::messageLength) {
std::copy(data.data() + readPointer, data.data() + readPointer + SafeRenderer::QSafeEvent::messageLength, dataBuffer);
readPointer += SafeRenderer::QSafeEvent::messageLength;
SafeRenderer::QSafeEvent safeEvent(dataBuffer);
if (safeEvent.getEventId() == SafeRenderer::EventId::EventOutputVerificationStatusRequest) {
handleVerificationRequest(safeEvent, *clientConnection);
} else {
m_messageSender.sendEvent(safeEvent);
}
dataLeft -= SafeRenderer::QSafeEvent::messageLength;
} else {
// Partial packet, we can do nothing but discard it.
dataLeft = 0;
}
} while (dataLeft > 0);
}
}