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 <QTcpSocket>
#include <QtCore>
#include <QtSafeRenderer/qsafeevent.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();
    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()), reply.messageLength);
    if (bytesWritten == reply.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) {
        unsigned char dataBuffer[SafeRenderer::QSafeEvent::messageLength];
        quint32 datalength = 0U;
        do {
            QByteArray data = clientConnection->read(SafeRenderer::QSafeEvent::messageLength);
            datalength = data.length();
            if (datalength == SafeRenderer::QSafeEvent::messageLength) {
                memcpy (&dataBuffer[0], data.data(), SafeRenderer::QSafeEvent::messageLength);
                SafeRenderer::QSafeEvent event(dataBuffer);
                if (event.getEventId() == SafeRenderer::EventOutputVerificationStatusRequest) {
                    handleVerificationRequest(event, *clientConnection);
                } else {
                    m_messageSender.sendEvent(event);
                }
            }
        } while (datalength > 0U);
    }
}