tcpsocket.cpp 5.7 KB
/* ****************************************************************************
 * 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 "tcpsocket.h"

#include "log.h"

#include <QHostAddress>
#include <QTcpSocket>
#include <QTimer>
#include <QDataStream>

namespace osdev  {
namespace components {

TcpSocket::TcpSocket( const QString& ipAddress, int portNumber )
    : m_pSocket(new QTcpSocket(this))
    , m_blockSize(0)
    , m_dataBuffer()
    , m_pTimer( new QTimer() )
{
    // First we connect the timer to this class
    connect(m_pTimer.get(), SIGNAL(timeout()), this, SLOT(chkSendBuffer()));

    this->connectSocketSignals();

    m_pSocket->connectToHost( QHostAddress( ipAddress ), static_cast<quint16>(portNumber) );
    if( !m_pSocket->waitForConnected( 3000 ) )
    {
        LogDebug("interfaceplugin", "Socket failed to connect.");
        LogObject("interfaceplugin", this);
    }
    else
    {
        LogDebug("interfaceplugin", "Client connected : ");
        LogObject("interfaceplugin", m_pSocket);
    }
}

TcpSocket::TcpSocket(QTcpSocket *pSocket)
    : m_pSocket(pSocket)
    , m_blockSize(0)
    , m_dataBuffer()
    , m_pTimer( new QTimer() )
{
    Q_ASSERT(pSocket);

    connect(m_pTimer.get(), SIGNAL(timeout()), this, SLOT(chkSendBuffer()));

    this->connectSocketSignals();
}

TcpSocket::~TcpSocket()
{
    // Implicitly deletes m_pSocket if this object is its parent
}

void TcpSocket::slotReadyRead()
{
    // Let the poolmanager know we are busy receiving data at the moment and are
    // unavailable for anything else.
    emit signalReceivingData( this );

    QDataStream in( m_pSocket );
    in.setVersion( QDataStream::Qt_5_4 );

    if( m_blockSize == 0 )
    {
        if( m_pSocket->bytesAvailable() < static_cast<int>(sizeof( quint32 ) ) )
        {
            return;
        }

        in >> m_blockSize;
    }

    if( m_pSocket->bytesAvailable() < m_blockSize )
    {
        return;
    }

    in >> m_dataBuffer;

    emit signalDataReceived( m_dataBuffer, this );

    m_blockSize = 0;            // Reset the blockSize for next read.
    m_dataBuffer.clear();       // Reset the buffer for the next read.
}

void TcpSocket::slotSendData( const QString &sData, TcpSocket *pSocket )
{
    if( pSocket != this || sData.isNull() ) {
        return;
    }

    QByteArray  block;
    QDataStream out( &block, QIODevice::WriteOnly );

    out.setVersion( QDataStream::Qt_5_4 );
    out << block.size();
    out << sData;

    m_pSocket->write( block );
    chkSendBuffer();
}

void TcpSocket::slotSetSocket(QTcpSocket* pSocket )
{
    if(m_pSocket) {
        disconnectSocketSignals();
    }
    m_pSocket = pSocket;
    connectSocketSignals();
}

void TcpSocket::chkSendBuffer()
{
    m_pTimer->stop();

    if( m_pSocket->bytesToWrite() > 0 )
    {
        m_pSocket->flush();
        m_pTimer->start( 500 );
    }
    else
    {
        emit signalDataSent( this );
    }
}

void TcpSocket::slotConnected()
{
    emit signalConnected( this );
}

void TcpSocket::slotDisconnected()
{
    emit signalDisconnected( this );
}

QString TcpSocket::showError()
{
    if( m_pSocket )
    {
        return m_pSocket->errorString();
    }
    else
    {
        return "No socket available";
    }
}

void TcpSocket::connectSocketSignals()
{
    Q_ASSERT(m_pSocket);
    // Connect the required signals and slots to gain control.
    // First for receiving data.
    connect( m_pSocket, SIGNAL( readyRead() ),
             this, SLOT( slotReadyRead() ) );

    connect( m_pSocket, SIGNAL( connected() ),
             this, SLOT( slotConnected() ) );

    connect( m_pSocket, SIGNAL( disconnected() ),
             this, SLOT( slotDisconnected() ) );
}

void TcpSocket::disconnectSocketSignals()
{
    Q_ASSERT(m_pSocket);
    // Connect the required signals and slots to gain control.
    // First for receiving data.
    disconnect( m_pSocket, SIGNAL( readyRead() ),
                this, SLOT( slotReadyRead() ) );

    disconnect( m_pSocket, SIGNAL( connected() ),
                this, SLOT( slotConnected() ) );

    disconnect( m_pSocket, SIGNAL( disconnected() ),
                this, SLOT( slotDisconnected() ) );
}

bool TcpSocket::isConnected()
{
    return m_pSocket && m_pSocket->state() == QTcpSocket::ConnectedState;
}

}
}