/* **************************************************************************** * 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 "poolmanager.h" #include "log.h" #include namespace osdev { namespace components { PoolManager::PoolManager(bool bServer, const QString& ipAddress, int portNumber, int maxTcpConnections, int maxUdpConnections, QObject *_parent ) : QObject( _parent ) , m_pServer( nullptr ) , m_pSocketContainer( new SocketContainer() ) , m_pSocket( nullptr ) , m_inputBuffer() , m_outputBuffer() , m_bServer( bServer ) , m_ipAddress( ipAddress ) , m_portNumber( portNumber ) , m_maxTcpConnections( maxTcpConnections ) , m_maxUdpConnections( maxUdpConnections ) { } PoolManager::~PoolManager() { delete m_pSocketContainer; m_pSocketContainer = nullptr; } /*************************************************************************** * Server Section ***************************************************************************/ void PoolManager::slotNewConnection() { // Create the socket, pass the pendingconnection and add it to our channelList. QTcpSocket* nextConnection = m_pServer->nextPendingConnection(); if( nextConnection ) { m_pSocket = new TcpSocket( nextConnection ); m_pSocketContainer->addSocket( m_pSocket ); // Connect the socket to the poolmanager this->connectSocketSignals( m_pSocket ); } } bool PoolManager::startNetworkLayer() { bool bResult = false; if( m_bServer ) { m_pServer = new QTcpServer; // Create our server object connect( m_pServer, SIGNAL( newConnection() ), this, SLOT( slotNewConnection() ) ); m_pServer->setMaxPendingConnections( m_maxTcpConnections ); bResult = m_pServer->listen( QHostAddress(m_ipAddress), static_cast(m_portNumber) ); if( bResult ) { LogDebug("interfaceplugin", "Server started"); } else { LogError("interfaceplugin", "Server error : " + m_pServer->errorString()); } } else { // Here we start a couple of client connections. for( int nCounter = 0; nCounter < m_maxTcpConnections; nCounter++ ) { m_pSocket = new TcpSocket( m_ipAddress, m_portNumber ); bResult = m_pSocket->isConnected(); if( bResult ) { m_pSocketContainer->addSocket( m_pSocket ); this->connectSocketSignals( m_pSocket ); emit message( 0, 0, osdev::components::gEventConnectionEstablished, 0 ); } else { LogDebug("[PoolManager::startNetworkLayer()]", QString( "Socket Error : %1" ).arg( m_pSocket->showError() ) ); delete m_pSocket; } } } return bResult; } void PoolManager::slotDataSent( TcpSocket *pSocket ) { m_pSocketContainer->setChannelFree( pSocket ); // Check for delayed messages and send the first one. this->resendDelayedMessages(); } void PoolManager::slotReceivingData( TcpSocket *pSocket ) { m_pSocketContainer->setChannelBusy( pSocket ); } void PoolManager::slotDataReceived( const QString &sData, TcpSocket *pSocket ) { // Create a unique ticket QString l_sTicket = createBufferTicket(); // Store the dat with the ticket as key m_outputBuffer.insert( l_sTicket, sData ); // Free the channel. m_pSocketContainer->setChannelFree( pSocket ); // Signal the upper layer we have new data available. emit dataPresent( l_sTicket ); // Resend first delayed messages if there are any. this->resendDelayedMessages(); } void PoolManager::sendData( const QString &sData ) { // Get a free channel and signal the data we want to send. TcpSocket *pSocket = m_pSocketContainer->getFreeSocket(); if( pSocket ) { m_pSocketContainer->setChannelBusy( pSocket ); emit signalSendData( sData, pSocket ); QCoreApplication::processEvents(); } else { LogError("NetworkInterface", QString("No free channel available. Storing for delayed send. Message number: %1").arg(m_inputBuffer.size() + 1)); m_inputBuffer.append( sData ); } } QString PoolManager::createBufferTicket() { return QUuid::createUuid().toString(); } QString PoolManager::getData(const QString& sTicket ) { if( m_outputBuffer.contains( sTicket ) ) { return m_outputBuffer.take( sTicket ); } else { return QString( "[ERROR : ] No data present in outputbuffer under ticket : %1 " ).arg( sTicket ); } } void PoolManager::connectSocketSignals( TcpSocket* l_pSocket) { // First we connect the socket -> poolmanager connect( l_pSocket, SIGNAL( signalDataReceived( const QString&, TcpSocket* ) ), this, SLOT( slotDataReceived( const QString&, TcpSocket* ) ) ); connect( l_pSocket, SIGNAL( signalDataSent( TcpSocket* ) ), this, SLOT( slotDataSent( TcpSocket* ) ) ); connect( l_pSocket, SIGNAL( signalReceivingData( TcpSocket* ) ), this, SLOT( slotReceivingData( TcpSocket* ) ) ); connect( l_pSocket, SIGNAL( signalConnected( TcpSocket* ) ), this, SLOT( slotConnected( TcpSocket* ) ) ); connect( l_pSocket, SIGNAL( signalDisconnected( TcpSocket* ) ), this, SLOT( slotDisconnected( TcpSocket* ) ) ); // And now the poolmanager -> socket connect( this, SIGNAL( signalSendData( const QString&, TcpSocket* ) ), l_pSocket, SLOT( slotSendData( const QString&, TcpSocket* ) ) ); } void PoolManager::resendDelayedMessages() { while( m_inputBuffer.size() > 0 ) // Check for delayed messages { if( m_pSocketContainer->getFreeSocket() ) // Check if there is a free channel { // Always send the first available message (FIFO) this->sendData( m_inputBuffer.takeFirst() ); LogDebug("[PoolManager::resendDelayedMessages]", QString( "Number of queued messages : %1 ").arg( m_inputBuffer.size() ) ); } else { // Warn if there is a socket available.... LogDebug( "[PoolManager::resendDelayedMessages]", QString( "No free Socket Available (yet)" ) ); } } } void PoolManager::slotConnected( TcpSocket *pSocket ) { Q_UNUSED( pSocket ); emit message( 0, 0, osdev::components::gEventConnectionEstablished, 0 ); } void PoolManager::slotDisconnected( TcpSocket *pSocket ) { LogError("NetworkInterface", "Socket disconnected unexpectantly."); LogError("NetworkInterface", pSocket->showError()); // emit message( 0, 0, gEventConnectionLost, 0 ); m_pSocketContainer->removeSocket( pSocket ); delete pSocket; } } /* End namespace components */ } /* End namespace osdev */