/* **************************************************************************** * Copyright 2019 Open Systems Development BV * * * * Permission is hereby granted, free of charge, to any person obtaining a * * copy of this software and associated documentation files (the "Software"), * * to deal in the Software without restriction, including without limitation * * the rights to use, copy, modify, merge, publish, distribute, sublicense, * * and/or sell copies of the Software, and to permit persons to whom the * * Software is furnished to do so, subject to the following conditions: * * * * The above copyright notice and this permission notice shall be included in * * all copies or substantial portions of the Software. * * * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * * DEALINGS IN THE SOFTWARE. * * ***************************************************************************/ #include "tcpinterface.h" #include "log.h" #include #include #include #include namespace osdev { namespace components { TcpInterface::TcpInterface(const QString& hostName, int port, bool i_bServer) : m_bServer( i_bServer ), m_active(false), m_tcpServer( nullptr ), m_tcpSocket( nullptr ), m_clientConnection( nullptr ), m_blockSize( 0 ), m_dataList() { QHostAddress hostAddress(hostName); if (m_bServer) { // This interface is a server m_tcpServer = new QTcpServer(this); connect(m_tcpServer, SIGNAL(newConnection()), this, SLOT(newConnection())); m_active = m_tcpServer->listen(hostAddress, static_cast(port)); if (!m_active) { LogWarning("interfaceplugin", "Unable to start the server: " + m_tcpServer->errorString()); } } else { // This interface is a client m_tcpSocket = new QTcpSocket(this); m_tcpSocket->connectToHost(hostAddress, static_cast(port)); m_active = m_tcpSocket->waitForConnected(1000); if (m_active) { connect(m_tcpSocket, SIGNAL(readyRead()), this, SLOT(readData())); } } } TcpInterface::~TcpInterface() { } QString TcpInterface::getData() { QString qsResult; if(!m_dataList.isEmpty()) { qsResult = m_dataList.takeFirst(); } return qsResult; } void TcpInterface::readData() { QTcpSocket* pSocket = nullptr; /* Retrieve the correct Socket, depending on connection-type */ if (m_bServer) { pSocket = m_clientConnection; } else { pSocket = m_tcpSocket; } /* Construct a DataStream from the Socket */ QDataStream in(pSocket); in.setVersion(QDataStream::Qt_5_4); // Process while there is a following message in this same buffer. do { LogDebug("TcpInterface", "read bytes"); /* The size of the message in bytes is required */ if (m_blockSize == 0) { /* * The size of the message should be available as the first four * blocks of the message; i.e. (sizeof(quint32)) */ if (pSocket->bytesAvailable() < static_cast(sizeof(quint32))) { return; } /* Retrieve the blocksize if it is fully available from the socket */ in >> m_blockSize; LogDebug("TcpInterface", QString("block size is %1").arg(m_blockSize)); } if (pSocket->bytesAvailable() < m_blockSize) { return; } /* * Retrieve the message if it is completely available from the socket. * I.e.: The number of available bytes must be at least the retrieved * message-size. */ QByteArray pDataStore; /* * Using an empty QByteArray the operator>> can be used, because it then * reads in everything until the first '\0' character. * It is then required that all messages are ended by a '\0'. This is * standard when sending QByteArrays. */ in >> pDataStore; /* * An entire message is stored in a new QByteArray and must be pushed on * the stack of available messages */ m_dataList.append( pDataStore ); m_blockSize = 0; // reset blocksize for next read emit dataPresent(); } while (pSocket->bytesAvailable() > 0); } void TcpInterface::sendData(const QString& i_qsData) { QByteArray block; QDataStream out(&block, QIODevice::WriteOnly); out.setVersion(QDataStream::Qt_5_4); out << block.size(); out << i_qsData.toLatin1(); if (m_bServer) { m_clientConnection->write(block); m_clientConnection->flush(); } else { m_tcpSocket->write(block); m_tcpSocket->flush(); } } void TcpInterface::newConnection() { m_clientConnection = m_tcpServer->nextPendingConnection(); connect(m_clientConnection, SIGNAL(readyRead()), this, SLOT(readData())); } } }