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 "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().data()), SafeRenderer::SafeMessageLength);
    if (bytesWritten == SafeRenderer::SafeMessageLength) {
        success = true;
    } else {
        qDebug() << "Failed to send reply to client";
    }
    return success;
}

void Server::readData()
{
    QTcpSocket *clientConnection = qobject_cast<QTcpSocket *>(QObject::sender());
    if (clientConnection) {
        SafeRenderer::QSafeEvent::SafeMessageData dataBuffer;

        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::SafeMessageLength) {
                std::copy(data.data() + readPointer, data.data() + readPointer + SafeRenderer::SafeMessageLength, dataBuffer.begin());
                readPointer += SafeRenderer::SafeMessageLength;

                SafeRenderer::QSafeEvent safeEvent(dataBuffer);
                SafeRenderer::QSafeEvent reply;
                SafeRenderer::SafeEventSenderStatus status = m_messageSender.sendEvent(safeEvent, reply);
                if (status == SafeRenderer::SafeEventSenderStatus::Success) {
                    sendReply(*clientConnection, reply);
                } else {
                    qDebug() << "Failed to send request to renderer.";
                }

                dataLeft -= SafeRenderer::SafeMessageLength;
            } else {
                // Partial packet, we can do nothing but discard it.
                dataLeft = 0;
            }
        } while (dataLeft > 0);
    }
}