Commit 99048c1cbf0e97b4906a75462ece3f7db4979387

Authored by Steven de Ridder
0 parents

Initial commit. dependencies not resolved yet.

.gitignore 0 → 100644
  1 +++ a/.gitignore
  1 +build/
  2 +CMakeLists.txt.user
CMakeLists.txt 0 → 100644
  1 +++ a/CMakeLists.txt
  1 +cmake_minimum_required(VERSION 3.0)
  2 +
  3 +# Check to see where cmake is located.
  4 +if( IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/cmake )
  5 + LIST(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
  6 +elseif( IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../cmake )
  7 + LIST(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../cmake)
  8 +else()
  9 + return()
  10 +endif()
  11 +
  12 +# Check to see if there is versioning information available
  13 +if(IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/osdev_versioning/cmake)
  14 + LIST(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/osdev_versioning/cmake)
  15 + include(osdevversion)
  16 +endif()
  17 +
  18 +include(projectheader)
  19 +project_header(osdev_network)
  20 +
  21 +add_subdirectory(src)
  22 +add_subdirectory(tests)
  23 +
  24 +# include(packaging)
  25 +# package_component()
README.md 0 → 100644
  1 +++ a/README.md
src/CMakeLists.txt 0 → 100644
  1 +++ a/src/CMakeLists.txt
  1 +cmake_minimum_required(VERSION 3.0)
  2 +LIST(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake)
  3 +include(projectheader)
  4 +project_header(network)
  5 +
  6 +find_package( Qt5Core REQUIRED )
  7 +find_package( Qt5Network REQUIRED )
  8 +
  9 +include_directories( SYSTEM
  10 + ${Qt5Core_INCLUDE_DIRS}
  11 + ${Qt5Network_INCLUDE_DIRS}
  12 +)
  13 +
  14 +include(compiler)
  15 +
  16 +include_directories(
  17 + ${CMAKE_CURRENT_SOURCE_DIR}/../config
  18 + ${CMAKE_CURRENT_SOURCE_DIR}/../global
  19 + ${CMAKE_CURRENT_SOURCE_DIR}/../logutils
  20 + ${CMAKE_CURRENT_SOURCE_DIR}/../datatypes
  21 +)
  22 +
  23 +set(SRC_LIST
  24 + ${CMAKE_CURRENT_SOURCE_DIR}/poolmanager.cpp
  25 + ${CMAKE_CURRENT_SOURCE_DIR}/socketcontainer.cpp
  26 + ${CMAKE_CURRENT_SOURCE_DIR}/tcpinterface.cpp
  27 + ${CMAKE_CURRENT_SOURCE_DIR}/tcpsocket.cpp
  28 +
  29 +)
  30 +
  31 +include(qtmoc)
  32 +create_mocs( SRC_LIST MOC_LIST
  33 + ${CMAKE_CURRENT_SOURCE_DIR}/poolmanager.h
  34 + ${CMAKE_CURRENT_SOURCE_DIR}/tcpinterface.h
  35 + ${CMAKE_CURRENT_SOURCE_DIR}/tcpsocket.h
  36 +)
  37 +
  38 +link_directories(
  39 + ${CMAKE_BINARY_DIR}/lib
  40 +)
  41 +
  42 +include(library)
  43 +add_libraries(
  44 + ${Qt5Core_LIBRARIES}
  45 + ${Qt5Network_LIBRARIES}
  46 + global
  47 + logutils
  48 + datatypes
  49 +)
  50 +
  51 +include(installation)
  52 +install_component()
src/msgparser.cpp 0 → 100644
  1 +++ a/src/msgparser.cpp
  1 +/* ****************************************************************************
  2 + * Copyright 2019 Open Systems Development BV *
  3 + * *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a *
  5 + * copy of this software and associated documentation files (the "Software"), *
  6 + * to deal in the Software without restriction, including without limitation *
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
  8 + * and/or sell copies of the Software, and to permit persons to whom the *
  9 + * Software is furnished to do so, subject to the following conditions: *
  10 + * *
  11 + * The above copyright notice and this permission notice shall be included in *
  12 + * all copies or substantial portions of the Software. *
  13 + * *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
  20 + * DEALINGS IN THE SOFTWARE. *
  21 + * ***************************************************************************/
  22 +#include "msgparser.h"
  23 +
  24 +namespace osdev {
  25 +namespace components {
  26 +
  27 +const QString MsgParser::s_messageElementTag = "message";
  28 +const QString MsgParser::s_sourceElementTag = "source";
  29 +const QString MsgParser::s_destElementTag = "dest";
  30 +const QString MsgParser::s_actionElementTag = "action";
  31 +const QString MsgParser::s_dataElementTag = "data";
  32 +const QString MsgParser::s_idAttributeTag = "id";
  33 +
  34 +MsgParser::MsgParser(QObject* _parent)
  35 + : QObject(_parent)
  36 + , m_message()
  37 + , m_sourceId()
  38 + , m_destId()
  39 + , m_actionId(-1)
  40 + , m_actionData()
  41 +{
  42 +}
  43 +
  44 +MsgParser::~MsgParser()
  45 +{
  46 +}
  47 +
  48 +void MsgParser::createMsg(const QString& sourceId, const QString& destId,
  49 + int actionId, const QString& actionData)
  50 +{
  51 + static const QString xmlVar("<%1 %2='%3'/>");
  52 + static const QString xmlData("<%1>%2</%1>");
  53 + static const QString xmlMessage("<%1>%2 %3 %4 %5</%1>");
  54 +
  55 + QString src = xmlVar.arg(s_sourceElementTag).arg(s_idAttributeTag).arg(sourceId);
  56 + QString dst = xmlVar.arg(s_destElementTag).arg(s_idAttributeTag).arg(destId);
  57 + QString action = xmlVar.arg(s_actionElementTag).arg(s_idAttributeTag).arg(actionId);
  58 + QString data = xmlData.arg(s_dataElementTag).arg(actionData);
  59 +
  60 + m_message = xmlMessage.arg(s_messageElementTag).arg(src).arg(dst).arg(action).arg(data);
  61 +}
  62 +
  63 +void MsgParser::createMsg(const QString& sourceId, const QString& destId,
  64 + int actionId, xercesc_2_7::DOMDocument* actionData)
  65 +{
  66 + QString msgData;
  67 +
  68 + CXmlParser* pSerializer = new CXmlParser();
  69 + // Store the complete message.
  70 + msgData = pSerializer->serialize(actionData);
  71 + delete pSerializer;
  72 +
  73 + static const QString xmlVar("<%1 %2='%3'/>");
  74 + static const QString xmlData("<%1>%2</%1>");
  75 + static const QString xmlMessage("<%1>%2 %3 %4 %5</%1>");
  76 +
  77 + QString src = xmlVar.arg(s_sourceElementTag).arg(s_idAttributeTag).arg(sourceId);
  78 + QString dst = xmlVar.arg(s_destElementTag).arg(s_idAttributeTag).arg(destId);
  79 + QString action = xmlVar.arg(s_actionElementTag).arg(s_idAttributeTag).arg(actionId);
  80 + QString data = xmlData.arg(s_dataElementTag).arg(msgData);
  81 +
  82 + m_message = xmlMessage.arg(s_messageElementTag).arg(src).arg(dst).arg(action).arg(data);
  83 +}
  84 +
  85 +void MsgParser::parseMsg(const QString& msg)
  86 +{
  87 + CXmlParser parser;
  88 +
  89 + DOMDocument* domDocument = parser.parse(msg);
  90 + DOMNode* rootNode = domDocument->getDocumentElement();
  91 +
  92 + DOMNode* node = rootNode->getFirstChild();
  93 + if (CXerces::nodeName(node) == sourceElementTag)
  94 + {
  95 + m_sourceId = CXerces::getNodeAttribute(node, qPrintable(s_idAttributeTag));
  96 + }
  97 +
  98 + node = node->getNextSibling();
  99 + if (CXerces::nodeName(node) == destElementTag)
  100 + {
  101 + m_destId = CXerces::getNodeAttribute(node, qPrintable(s_idAttributeTag));
  102 + }
  103 +
  104 + node = node->getNextSibling();
  105 + if (CXerces::nodeName(node) == s_actionElementTag)
  106 + {
  107 + m_actionId = CXerces::getNodeAttribute(node, qPrintable(s_idAttributeTag)).toInt();
  108 + }
  109 +
  110 + node = node->getNextSibling();
  111 + if (CXerces::nodeName(node) == s_dataElementTag)
  112 + {
  113 + m_actionData = parser.serialize(node);
  114 + }
  115 +}
  116 +
  117 +QString MsgParser::getMsg() const
  118 +{
  119 + return m_message;
  120 +}
  121 +
  122 +QString MsgParser::getSourceId() const
  123 +{
  124 + return m_sourceId;
  125 +}
  126 +
  127 +QString MsgParser::getDestId() const
  128 +{
  129 + return m_destId;
  130 +}
  131 +
  132 +int MsgParser::getActionId() const
  133 +{
  134 + return m_actionId;
  135 +}
  136 +
  137 +QString MsgParser::getActionData() const
  138 +{
  139 + return m_actionData;
  140 +}
  141 +
  142 +}
  143 +}
src/msgparser.h 0 → 100644
  1 +++ a/src/msgparser.h
  1 +/* ****************************************************************************
  2 + * Copyright 2019 Open Systems Development BV *
  3 + * *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a *
  5 + * copy of this software and associated documentation files (the "Software"), *
  6 + * to deal in the Software without restriction, including without limitation *
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
  8 + * and/or sell copies of the Software, and to permit persons to whom the *
  9 + * Software is furnished to do so, subject to the following conditions: *
  10 + * *
  11 + * The above copyright notice and this permission notice shall be included in *
  12 + * all copies or substantial portions of the Software. *
  13 + * *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
  20 + * DEALINGS IN THE SOFTWARE. *
  21 + * ***************************************************************************/
  22 +//
  23 +// Description :
  24 +// Revision :
  25 +// Confidentiality :
  26 +// Dependencies :
  27 +//
  28 +
  29 +#ifndef OSDEV_COMPONENTS_CMSGPARSER_H
  30 +#define OSDEV_COMPONENTS_CMSGPARSER_H
  31 +
  32 +#include <QObject>
  33 +#include <QString>
  34 +#include <QUuid>
  35 +
  36 +namespace osdev {
  37 +namespace components {
  38 +
  39 +/**
  40 + * @brief The MsgParser class
  41 + */
  42 +class MsgParser : public QObject
  43 +{
  44 + Q_OBJECT
  45 +
  46 +public:
  47 + /**
  48 + * @brief Constructor
  49 + * @param _parent Parent QObject
  50 + */
  51 + MsgParser(QObject* _parent = nullptr);
  52 + /// @brief Destructor
  53 + ~MsgParser();
  54 +
  55 + /**
  56 + * @brief Create a message with the given parameters
  57 + * \param sourceID The source ID of the interface calling this function.
  58 + * \param destID The destination ID of the interface receiving the data.
  59 + * \param actionId The action to be performed on the data.
  60 + * \param actionData The actual data (This must be XML formatted)
  61 + */
  62 + void createMsg(const QString& sourceID, const QString& destID,
  63 + int actionId, const QString& actionData);
  64 +
  65 + /**
  66 + * @brief Retrieve the fields from the specified message
  67 + * @param msg Message to parse
  68 + */
  69 + void parseMsg(const QString& msg);
  70 +
  71 + /// @return Message to parse
  72 + QString getMsg() const;
  73 + /// @return Source ID from the message
  74 + QString getSourceId() const;
  75 + /// @return Destination ID from the message
  76 + QString getDestId() const;
  77 + /// @return Action ID from the message
  78 + int getActionId() const;
  79 + /// @return Action data from the message
  80 + QString getActionData() const;
  81 +
  82 +// void createMsg(const QString& sourceID, const QString& destID,
  83 +// int actionId, xercesc_2_7::DOMDocument* actionData);
  84 +
  85 +private:
  86 + QString m_message; ///< Full message
  87 + QString m_sourceId; ///< Source ID in the message
  88 + QString m_destId; ///< Destination ID in the message
  89 + int m_actionId; ///< Action ID in the message
  90 + QString m_actionData; ///< Action Data in the message
  91 +
  92 + static const QString s_messageElementTag;
  93 + static const QString s_sourceElementTag;
  94 + static const QString s_destElementTag;
  95 + static const QString s_actionElementTag;
  96 + static const QString s_dataElementTag;
  97 + static const QString s_idAttributeTag;
  98 +};
  99 +
  100 +} // End namespace components
  101 +} // End namespace osdev
  102 +
  103 +#endif /* OSDEV_COMPONENTS_CMSGPARSER_H */
src/poolmanager.cpp 0 → 100644
  1 +++ a/src/poolmanager.cpp
  1 +/* ****************************************************************************
  2 + * Copyright 2019 Open Systems Development BV *
  3 + * *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a *
  5 + * copy of this software and associated documentation files (the "Software"), *
  6 + * to deal in the Software without restriction, including without limitation *
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
  8 + * and/or sell copies of the Software, and to permit persons to whom the *
  9 + * Software is furnished to do so, subject to the following conditions: *
  10 + * *
  11 + * The above copyright notice and this permission notice shall be included in *
  12 + * all copies or substantial portions of the Software. *
  13 + * *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
  20 + * DEALINGS IN THE SOFTWARE. *
  21 + * ***************************************************************************/
  22 +#include "poolmanager.h"
  23 +#include "log.h"
  24 +#include <QCoreApplication>
  25 +
  26 +namespace osdev {
  27 +namespace components {
  28 +
  29 +PoolManager::PoolManager(bool bServer,
  30 + const QString& ipAddress,
  31 + int portNumber,
  32 + int maxTcpConnections,
  33 + int maxUdpConnections,
  34 + QObject *_parent )
  35 + : QObject( _parent )
  36 + , m_pServer( nullptr )
  37 + , m_pSocketContainer( new SocketContainer() )
  38 + , m_pSocket( nullptr )
  39 + , m_inputBuffer()
  40 + , m_outputBuffer()
  41 + , m_bServer( bServer )
  42 + , m_ipAddress( ipAddress )
  43 + , m_portNumber( portNumber )
  44 + , m_maxTcpConnections( maxTcpConnections )
  45 + , m_maxUdpConnections( maxUdpConnections )
  46 +{
  47 +}
  48 +
  49 +PoolManager::~PoolManager()
  50 +{
  51 + delete m_pSocketContainer;
  52 + m_pSocketContainer = nullptr;
  53 +}
  54 +/***************************************************************************
  55 + * Server Section
  56 + ***************************************************************************/
  57 +void PoolManager::slotNewConnection()
  58 +{
  59 + // Create the socket, pass the pendingconnection and add it to our channelList.
  60 +
  61 + QTcpSocket* nextConnection = m_pServer->nextPendingConnection();
  62 + if( nextConnection )
  63 + {
  64 + m_pSocket = new TcpSocket( nextConnection );
  65 + m_pSocketContainer->addSocket( m_pSocket );
  66 +
  67 + // Connect the socket to the poolmanager
  68 + this->connectSocketSignals( m_pSocket );
  69 + }
  70 +}
  71 +
  72 +bool PoolManager::startNetworkLayer()
  73 +{
  74 + bool bResult = false;
  75 +
  76 + if( m_bServer )
  77 + {
  78 + m_pServer = new QTcpServer; // Create our server object
  79 +
  80 + connect( m_pServer, SIGNAL( newConnection() ),
  81 + this, SLOT( slotNewConnection() ) );
  82 +
  83 + m_pServer->setMaxPendingConnections( m_maxTcpConnections );
  84 + bResult = m_pServer->listen( QHostAddress(m_ipAddress), static_cast<quint16>(m_portNumber) );
  85 + if( bResult )
  86 + {
  87 + LogDebug("interfaceplugin", "Server started");
  88 + }
  89 + else
  90 + {
  91 + LogError("interfaceplugin", "Server error : " + m_pServer->errorString());
  92 + }
  93 + }
  94 + else
  95 + {
  96 + // Here we start a couple of client connections.
  97 + for( int nCounter = 0; nCounter < m_maxTcpConnections; nCounter++ )
  98 + {
  99 + m_pSocket = new TcpSocket( m_ipAddress, m_portNumber );
  100 + bResult = m_pSocket->isConnected();
  101 + if( bResult )
  102 + {
  103 + m_pSocketContainer->addSocket( m_pSocket );
  104 + this->connectSocketSignals( m_pSocket );
  105 + emit message( 0, 0, osdev::components::gEventConnectionEstablished, 0 );
  106 + }
  107 + else
  108 + {
  109 + LogDebug("[PoolManager::startNetworkLayer()]", QString( "Socket Error : %1" ).arg( m_pSocket->showError() ) );
  110 + delete m_pSocket;
  111 + }
  112 + }
  113 + }
  114 + return bResult;
  115 +}
  116 +
  117 +void PoolManager::slotDataSent( TcpSocket *pSocket )
  118 +{
  119 + m_pSocketContainer->setChannelFree( pSocket );
  120 +
  121 + // Check for delayed messages and send the first one.
  122 + this->resendDelayedMessages();
  123 +}
  124 +
  125 +void PoolManager::slotReceivingData( TcpSocket *pSocket )
  126 +{
  127 + m_pSocketContainer->setChannelBusy( pSocket );
  128 +}
  129 +
  130 +void PoolManager::slotDataReceived( const QString &sData, TcpSocket *pSocket )
  131 +{
  132 + // Create a unique ticket
  133 + QString l_sTicket = createBufferTicket();
  134 +
  135 + // Store the dat with the ticket as key
  136 + m_outputBuffer.insert( l_sTicket, sData );
  137 +
  138 + // Free the channel.
  139 + m_pSocketContainer->setChannelFree( pSocket );
  140 +
  141 + // Signal the upper layer we have new data available.
  142 + emit dataPresent( l_sTicket );
  143 +
  144 + // Resend first delayed messages if there are any.
  145 + this->resendDelayedMessages();
  146 +}
  147 +
  148 +void PoolManager::sendData( const QString &sData )
  149 +{
  150 + // Get a free channel and signal the data we want to send.
  151 + TcpSocket *pSocket = m_pSocketContainer->getFreeSocket();
  152 + if( pSocket )
  153 + {
  154 + m_pSocketContainer->setChannelBusy( pSocket );
  155 + emit signalSendData( sData, pSocket );
  156 + QCoreApplication::processEvents();
  157 + }
  158 + else
  159 + {
  160 + LogError("NetworkInterface", QString("No free channel available. Storing for delayed send. Message number: %1").arg(m_inputBuffer.size() + 1));
  161 + m_inputBuffer.append( sData );
  162 + }
  163 +}
  164 +
  165 +QString PoolManager::createBufferTicket()
  166 +{
  167 + return QUuid::createUuid().toString();
  168 +}
  169 +
  170 +QString PoolManager::getData(const QString& sTicket )
  171 +{
  172 + if( m_outputBuffer.contains( sTicket ) )
  173 + {
  174 + return m_outputBuffer.take( sTicket );
  175 + }
  176 + else
  177 + {
  178 + return QString( "[ERROR : ] No data present in outputbuffer under ticket : %1 " ).arg( sTicket );
  179 + }
  180 +}
  181 +
  182 +void PoolManager::connectSocketSignals( TcpSocket* l_pSocket)
  183 +{
  184 + // First we connect the socket -> poolmanager
  185 + connect( l_pSocket, SIGNAL( signalDataReceived( const QString&, TcpSocket* ) ),
  186 + this, SLOT( slotDataReceived( const QString&, TcpSocket* ) ) );
  187 +
  188 + connect( l_pSocket, SIGNAL( signalDataSent( TcpSocket* ) ),
  189 + this, SLOT( slotDataSent( TcpSocket* ) ) );
  190 +
  191 + connect( l_pSocket, SIGNAL( signalReceivingData( TcpSocket* ) ),
  192 + this, SLOT( slotReceivingData( TcpSocket* ) ) );
  193 +
  194 + connect( l_pSocket, SIGNAL( signalConnected( TcpSocket* ) ),
  195 + this, SLOT( slotConnected( TcpSocket* ) ) );
  196 +
  197 + connect( l_pSocket, SIGNAL( signalDisconnected( TcpSocket* ) ),
  198 + this, SLOT( slotDisconnected( TcpSocket* ) ) );
  199 +
  200 + // And now the poolmanager -> socket
  201 + connect( this, SIGNAL( signalSendData( const QString&, TcpSocket* ) ),
  202 + l_pSocket, SLOT( slotSendData( const QString&, TcpSocket* ) ) );
  203 +
  204 +}
  205 +
  206 +void PoolManager::resendDelayedMessages()
  207 +{
  208 + while( m_inputBuffer.size() > 0 ) // Check for delayed messages
  209 + {
  210 + if( m_pSocketContainer->getFreeSocket() ) // Check if there is a free channel
  211 + {
  212 + // Always send the first available message (FIFO)
  213 + this->sendData( m_inputBuffer.takeFirst() );
  214 + LogDebug("[PoolManager::resendDelayedMessages]", QString( "Number of queued messages : %1 ").arg( m_inputBuffer.size() ) );
  215 + }
  216 + else
  217 + {
  218 + // Warn if there is a socket available....
  219 + LogDebug( "[PoolManager::resendDelayedMessages]", QString( "No free Socket Available (yet)" ) );
  220 + }
  221 + }
  222 +}
  223 +
  224 +void PoolManager::slotConnected( TcpSocket *pSocket )
  225 +{
  226 + Q_UNUSED( pSocket );
  227 +
  228 + emit message( 0, 0, osdev::components::gEventConnectionEstablished, 0 );
  229 +}
  230 +
  231 +void PoolManager::slotDisconnected( TcpSocket *pSocket )
  232 +{
  233 + LogError("NetworkInterface", "Socket disconnected unexpectantly.");
  234 + LogError("NetworkInterface", pSocket->showError());
  235 +
  236 + // emit message( 0, 0, gEventConnectionLost, 0 );
  237 +
  238 + m_pSocketContainer->removeSocket( pSocket );
  239 + delete pSocket;
  240 +}
  241 +
  242 +} /* End namespace components */
  243 +} /* End namespace osdev */
src/poolmanager.h 0 → 100644
  1 +++ a/src/poolmanager.h
  1 +/* ****************************************************************************
  2 + * Copyright 2019 Open Systems Development BV *
  3 + * *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a *
  5 + * copy of this software and associated documentation files (the "Software"), *
  6 + * to deal in the Software without restriction, including without limitation *
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
  8 + * and/or sell copies of the Software, and to permit persons to whom the *
  9 + * Software is furnished to do so, subject to the following conditions: *
  10 + * *
  11 + * The above copyright notice and this permission notice shall be included in *
  12 + * all copies or substantial portions of the Software. *
  13 + * *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
  20 + * DEALINGS IN THE SOFTWARE. *
  21 + * ***************************************************************************/
  22 +#ifndef OSDEV_COMPONENTS_CPOOLMANAGER_H
  23 +#define OSDEV_COMPONENTS_CPOOLMANAGER_H
  24 +
  25 +/***************************************************************************
  26 + * Global Includes
  27 + ***************************************************************************/
  28 +#include <QObject>
  29 +#include <QString>
  30 +#include <QUuid>
  31 +#include <QHash>
  32 +#include <QTcpServer>
  33 +#include <QList>
  34 +
  35 +/***************************************************************************
  36 + * Local Includes
  37 + ***************************************************************************/
  38 +#include "eventcodes.h" // Make the codes known.
  39 +
  40 +#include "socketcontainer.h"
  41 +#include "tcpsocket.h"
  42 +
  43 +namespace osdev {
  44 +namespace components {
  45 +
  46 +/**
  47 + * @brief Handles a pool of network connections
  48 + */
  49 +class PoolManager : public QObject
  50 +{
  51 + Q_OBJECT
  52 +
  53 +public:
  54 + /**
  55 + * @brief Constructor
  56 + * @param bServer True for server-mode, false for client-mode (Server is default).
  57 + * @param ipAddress IP-address to listen at (server-mode) or to connect to
  58 + * (client-mode)
  59 + * @param portNumber Portnumber to listen at (server-mode) or to connect to
  60 + * (server-mode)
  61 + * @param maxTcpConnections Maximum number of TCP connections accepted
  62 + * @param maxUdpConnections Maximum number of UDP connections accepted
  63 + * (currently unused)
  64 + * @param _parent Parent object
  65 + */
  66 + PoolManager(bool bServer = false,
  67 + const QString& ipAddress = "0.0.0.0",
  68 + int portNumber = 3500,
  69 + int maxTcpConnections = 10, // The maximum number of connections we accept.
  70 + int maxUdpConnections = 10,
  71 + QObject *_parent = nullptr );
  72 +
  73 + /// @brief Destructor
  74 + ~PoolManager();
  75 +
  76 + /// Deleted copy-constructor
  77 + PoolManager(const PoolManager&) = delete;
  78 + /// Deleted assignment operator
  79 + PoolManager& operator=(const PoolManager&) = delete;
  80 + /// Deleted move-constructor
  81 + PoolManager(PoolManager&&) = delete;
  82 + /// Deleted move operator
  83 + PoolManager& operator=(PoolManager&&) = delete;
  84 +
  85 + /**
  86 + * @brief Get the data for a specified ticket
  87 + * @param sTicket Ticket ID
  88 + * @return Available data
  89 + */
  90 + QString getData( const QString& sTicket );
  91 +
  92 + /**
  93 + * @brief Start the actual server (server-mode) or build the client
  94 + * connection (client-mode)
  95 + * @return True on success, false on failure
  96 + */
  97 + bool startNetworkLayer();
  98 +
  99 + /**
  100 + * @brief Send data through the interface
  101 + * @param sData Data to send
  102 + */
  103 + void sendData( const QString &sData );
  104 +
  105 +public slots:
  106 + /// @brief Slot called when a new server-connection is available
  107 + void slotNewConnection();
  108 +
  109 + /**
  110 + * @brief Slot called when data was sent through the specified socket
  111 + * @param pSocket Socket through which data was sent
  112 + */
  113 + void slotDataSent( TcpSocket *pSocket );
  114 +
  115 + /**
  116 + * @brief Slot called when data is being received by the specified socket
  117 + * @param pSocket Socket which is receiving data
  118 + */
  119 + void slotReceivingData( TcpSocket *pSocket );
  120 +
  121 + /**
  122 + * @brief Slot called when data was received through the specified socket
  123 + * @param sData Data received
  124 + * @param pSocket Socket through which data was sent
  125 + */
  126 + void slotDataReceived( const QString &sData, TcpSocket *pSocket );
  127 +
  128 + /**
  129 + * @brief Slot called when the specified socket was connected
  130 + * @param pSocket Socket through which data was sent
  131 + */
  132 + void slotConnected( TcpSocket *pSocket );
  133 +
  134 + /**
  135 + * @brief Slot called when the specified socket was disconnected
  136 + * @param pSocket Socket that was disconnected
  137 + *
  138 + * Also removes the socket from the list of known sockets and deletes it
  139 + */
  140 + void slotDisconnected( TcpSocket *pSocket );
  141 +
  142 +signals:
  143 + /**
  144 + * @brief Signal emitted when data is sent through a specified socket
  145 + * @param sData Data to be sent
  146 + * @param pSocket Socket that sends the data
  147 + */
  148 + void signalSendData( const QString &sData, TcpSocket *pSocket );
  149 +
  150 + /**
  151 + * @brief Signal emitted when data is present for the specified ticket
  152 + * @param sTicket Ticket ID
  153 + */
  154 + void dataPresent( const QString &sTicket );
  155 +
  156 + /**
  157 + * @brief Relay the message signal to the eventmanager
  158 + * @todo Check parameter meanings!
  159 + * @param i1 sourceID ?
  160 + * @param i2 DestID ?
  161 + * @param i3 Connection status ?
  162 + * @param i4 data ?
  163 + */
  164 + void message( int i1, int i2, int i3, int i4 );
  165 +
  166 +private:
  167 + /**
  168 + * @brief Create a new unique buffer ticket ID
  169 + * @return New ticket ID
  170 + */
  171 + QString createBufferTicket();
  172 +
  173 + /**
  174 + * @brief Connect all signals and slots for the socket
  175 + * @param l_pSocket Socket to connect
  176 + */
  177 + void connectSocketSignals( TcpSocket *l_pSocket );
  178 +
  179 + /// @brief Resend messages that are still in the buffer
  180 + void resendDelayedMessages();
  181 +
  182 + QTcpServer *m_pServer; ///< The pointer to the server object.
  183 + SocketContainer *m_pSocketContainer; ///< Administration which keeps track of the Sockets.
  184 + TcpSocket *m_pSocket;
  185 +
  186 + QList< QString > m_inputBuffer; ///< Messages that can not be send yet will be stored here.
  187 + QHash< QString, QString > m_outputBuffer; ///< The hashtable we use for databuffering.
  188 +
  189 + bool m_bServer; ///< True for server-mode, false for client-mode
  190 + QString m_ipAddress; ///< The ipAddress the clients are connecting to.
  191 + int m_portNumber; ///< The portnumber our server is listening on.
  192 + int m_maxTcpConnections;///< The number of TCP connections we accept and make.
  193 + int m_maxUdpConnections;///< The number of UDP connections we accept and make.
  194 +};
  195 +
  196 +} // End namespace components
  197 +} // End namespace osdev
  198 +
  199 +#endif /* OSDEV_COMPONENTS_CPOOLMANAGER_H */
src/socketcontainer.cpp 0 → 100644
  1 +++ a/src/socketcontainer.cpp
  1 +/* ****************************************************************************
  2 + * Copyright 2019 Open Systems Development BV *
  3 + * *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a *
  5 + * copy of this software and associated documentation files (the "Software"), *
  6 + * to deal in the Software without restriction, including without limitation *
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
  8 + * and/or sell copies of the Software, and to permit persons to whom the *
  9 + * Software is furnished to do so, subject to the following conditions: *
  10 + * *
  11 + * The above copyright notice and this permission notice shall be included in *
  12 + * all copies or substantial portions of the Software. *
  13 + * *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
  20 + * DEALINGS IN THE SOFTWARE. *
  21 + * ***************************************************************************/
  22 +
  23 +#include "socketcontainer.h"
  24 +
  25 +#include "tcpsocket.h"
  26 +#include "log.h"
  27 +
  28 +namespace osdev {
  29 +namespace components {
  30 +
  31 +SocketContainer::SocketContainer()
  32 + : m_hshFreeBySocket()
  33 +{
  34 +}
  35 +
  36 +SocketContainer::~SocketContainer()
  37 +{
  38 + // qDeleteAll( hshFreeBySocket.begin(), hshFreeBySocket.end() );
  39 +}
  40 +
  41 +void SocketContainer::addSocket( TcpSocket *pSocket )
  42 +{
  43 + if( pSocket )
  44 + {
  45 + // We store a channel in a ready state.
  46 + m_hshFreeBySocket.insert( pSocket, true );
  47 + }
  48 +}
  49 +
  50 +void SocketContainer::removeSocket( TcpSocket *pSocket )
  51 +{
  52 + if( pSocket )
  53 + {
  54 + // Remove the channel from the list.
  55 + m_hshFreeBySocket.remove( pSocket );
  56 + }
  57 +}
  58 +
  59 +void SocketContainer::setChannelFree( TcpSocket *pSocket )
  60 +{
  61 + if( pSocket )
  62 + {
  63 + auto socketIt = m_hshFreeBySocket.find(pSocket);
  64 + if( m_hshFreeBySocket.end() != socketIt )
  65 + {
  66 + socketIt.value() = true;
  67 + }
  68 + }
  69 +}
  70 +
  71 +void SocketContainer::setChannelBusy(TcpSocket *pSocket)
  72 +{
  73 + if( pSocket )
  74 + {
  75 + auto socketIt = m_hshFreeBySocket.find(pSocket);
  76 + if( m_hshFreeBySocket.end() != socketIt )
  77 + {
  78 + socketIt.value() = false;
  79 +
  80 + // printStatus();
  81 + }
  82 + }
  83 +}
  84 +
  85 +TcpSocket* SocketContainer::getFreeSocket() const
  86 +{
  87 + // printStatus();
  88 +
  89 + // Return a random socket with a free channel
  90 + return m_hshFreeBySocket.key( true );
  91 +}
  92 +
  93 +void SocketContainer::printStatus() const
  94 +{
  95 + LogDebug("interfaceplugin", QString("getFreeSocket counts : ") + m_hshFreeBySocket.count());
  96 + LogDebug("interfaceplugin", QString("==========================================================="));
  97 +
  98 + for(auto it = m_hshFreeBySocket.begin(); it != m_hshFreeBySocket.end(); ++it)
  99 + {
  100 + LogDebug("interfaceplugin", it.key()->objectName()+" : "+it.value());
  101 + }
  102 +}
  103 +
  104 +} // End namespace components
  105 +} // End namespace osdev
src/socketcontainer.h 0 → 100644
  1 +++ a/src/socketcontainer.h
  1 +/* ****************************************************************************
  2 + * Copyright 2019 Open Systems Development BV *
  3 + * *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a *
  5 + * copy of this software and associated documentation files (the "Software"), *
  6 + * to deal in the Software without restriction, including without limitation *
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
  8 + * and/or sell copies of the Software, and to permit persons to whom the *
  9 + * Software is furnished to do so, subject to the following conditions: *
  10 + * *
  11 + * The above copyright notice and this permission notice shall be included in *
  12 + * all copies or substantial portions of the Software. *
  13 + * *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
  20 + * DEALINGS IN THE SOFTWARE. *
  21 + * ***************************************************************************/
  22 +
  23 +#ifndef OSDEV_COMPONENTS_CTHREADCONTAINER_H
  24 +#define OSDEV_COMPONENTS_CTHREADCONTAINER_H
  25 +
  26 +/***************************************************************************
  27 + * Global Includes
  28 + ***************************************************************************/
  29 +#include <QHash>
  30 +
  31 +/***************************************************************************
  32 + * Local Includes
  33 + ***************************************************************************/
  34 +
  35 +namespace osdev {
  36 +namespace components {
  37 +
  38 +class TcpSocket;
  39 +
  40 +/**
  41 + * @brief Maintains a collection of sockets
  42 + *
  43 + * @note This class does NOT take ownership of the provided sockets
  44 + */
  45 +class SocketContainer
  46 +{
  47 +public:
  48 + /// Constructor
  49 + SocketContainer();
  50 + /// Destructor
  51 + ~SocketContainer();
  52 +
  53 + /// Deleted copy-constructor
  54 + SocketContainer(const SocketContainer&) = delete;
  55 + /// Deleted assignment operator
  56 + SocketContainer& operator=(const SocketContainer&) = delete;
  57 + /// Deleted move-constructor
  58 + SocketContainer(SocketContainer&&) = delete;
  59 + /// Deleted move operator
  60 + SocketContainer& operator=(SocketContainer&&) = delete;
  61 +
  62 + //! This function will set the given thread to free
  63 + //! \param pSocket Socket to set to free
  64 + void setChannelFree( TcpSocket *pSocket );
  65 +
  66 + //! This function will set the given thread to busy
  67 + //! \param pSocket Socket to set to busy
  68 + void setChannelBusy( TcpSocket *pSocket );
  69 +
  70 + //! This function will add a newly created thread to the container
  71 + //! \param pSocket Add a new socket to the list
  72 + void addSocket( TcpSocket *pSocket );
  73 +
  74 + //! This function removes a thread from the list for whatever reason there might be
  75 + //! \param pSocket Removes the socket from the list
  76 + void removeSocket( TcpSocket *pSocket );
  77 +
  78 + //! @return This function will return the first free thread.
  79 + TcpSocket* getFreeSocket() const;
  80 +
  81 +private:
  82 + /// Dump the status to debug log
  83 + void printStatus() const;
  84 +
  85 + /// Contains all managed sockets
  86 + QHash< TcpSocket*, bool > m_hshFreeBySocket;
  87 +};
  88 +
  89 +} // End namespace components
  90 +} // End namespace osdev
  91 +
  92 +#endif /* OSDEV_COMPONENTS_CTHREADCONTAINER_H */
src/tcpinterface.cpp 0 → 100644
  1 +++ a/src/tcpinterface.cpp
  1 +/* ****************************************************************************
  2 + * Copyright 2019 Open Systems Development BV *
  3 + * *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a *
  5 + * copy of this software and associated documentation files (the "Software"), *
  6 + * to deal in the Software without restriction, including without limitation *
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
  8 + * and/or sell copies of the Software, and to permit persons to whom the *
  9 + * Software is furnished to do so, subject to the following conditions: *
  10 + * *
  11 + * The above copyright notice and this permission notice shall be included in *
  12 + * all copies or substantial portions of the Software. *
  13 + * *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
  20 + * DEALINGS IN THE SOFTWARE. *
  21 + * ***************************************************************************/
  22 +
  23 +#include "tcpinterface.h"
  24 +#include "log.h"
  25 +
  26 +#include <QHostAddress>
  27 +#include <QTcpServer>
  28 +#include <QTcpSocket>
  29 +#include <QDataStream>
  30 +
  31 +namespace osdev {
  32 +namespace components {
  33 +
  34 +TcpInterface::TcpInterface(const QString& hostName, int port, bool i_bServer)
  35 + : m_bServer( i_bServer ),
  36 + m_active(false),
  37 + m_tcpServer( nullptr ),
  38 + m_tcpSocket( nullptr ),
  39 + m_clientConnection( nullptr ),
  40 + m_blockSize( 0 ),
  41 + m_dataList()
  42 +{
  43 + QHostAddress hostAddress(hostName);
  44 +
  45 + if (m_bServer)
  46 + { // This interface is a server
  47 + m_tcpServer = new QTcpServer(this);
  48 + connect(m_tcpServer, SIGNAL(newConnection()), this, SLOT(newConnection()));
  49 + m_active = m_tcpServer->listen(hostAddress, static_cast<quint16>(port));
  50 + if (!m_active)
  51 + {
  52 + LogWarning("interfaceplugin",
  53 + "Unable to start the server: " + m_tcpServer->errorString());
  54 + }
  55 + }
  56 + else
  57 + { // This interface is a client
  58 + m_tcpSocket = new QTcpSocket(this);
  59 + m_tcpSocket->connectToHost(hostAddress, static_cast<quint16>(port));
  60 + m_active = m_tcpSocket->waitForConnected(1000);
  61 + if (m_active)
  62 + {
  63 + connect(m_tcpSocket, SIGNAL(readyRead()), this, SLOT(readData()));
  64 + }
  65 + }
  66 +}
  67 +
  68 +
  69 +TcpInterface::~TcpInterface()
  70 +{
  71 +}
  72 +
  73 +QString TcpInterface::getData()
  74 +{
  75 + QString qsResult;
  76 + if(!m_dataList.isEmpty())
  77 + {
  78 + qsResult = m_dataList.takeFirst();
  79 + }
  80 + return qsResult;
  81 +}
  82 +
  83 +void TcpInterface::readData()
  84 +{
  85 + QTcpSocket* pSocket = nullptr;
  86 + /* Retrieve the correct Socket, depending on connection-type */
  87 + if (m_bServer)
  88 + {
  89 + pSocket = m_clientConnection;
  90 + }
  91 + else
  92 + {
  93 + pSocket = m_tcpSocket;
  94 + }
  95 +
  96 + /* Construct a DataStream from the Socket */
  97 + QDataStream in(pSocket);
  98 + in.setVersion(QDataStream::Qt_5_4);
  99 +
  100 + // Process while there is a following message in this same buffer.
  101 + do {
  102 + LogDebug("TcpInterface", "read bytes");
  103 + /* The size of the message in bytes is required */
  104 + if (m_blockSize == 0)
  105 + {
  106 + /*
  107 + * The size of the message should be available as the first four
  108 + * blocks of the message; i.e. (sizeof(quint32))
  109 + */
  110 + if (pSocket->bytesAvailable() < static_cast<int>(sizeof(quint32)))
  111 + {
  112 + return;
  113 + }
  114 + /* Retrieve the blocksize if it is fully available from the socket */
  115 + in >> m_blockSize;
  116 + LogDebug("TcpInterface", QString("block size is %1").arg(m_blockSize));
  117 + }
  118 +
  119 + if (pSocket->bytesAvailable() < m_blockSize)
  120 + {
  121 + return;
  122 + }
  123 +
  124 + /*
  125 + * Retrieve the message if it is completely available from the socket.
  126 + * I.e.: The number of available bytes must be at least the retrieved
  127 + * message-size.
  128 + */
  129 + QByteArray pDataStore;
  130 + /*
  131 + * Using an empty QByteArray the operator>> can be used, because it then
  132 + * reads in everything until the first '\0' character.
  133 + * It is then required that all messages are ended by a '\0'. This is
  134 + * standard when sending QByteArrays.
  135 + */
  136 + in >> pDataStore;
  137 + /*
  138 + * An entire message is stored in a new QByteArray and must be pushed on
  139 + * the stack of available messages
  140 + */
  141 + m_dataList.append( pDataStore );
  142 + m_blockSize = 0; // reset blocksize for next read
  143 + emit dataPresent();
  144 + } while (pSocket->bytesAvailable() > 0);
  145 +}
  146 +
  147 +void TcpInterface::sendData(const QString& i_qsData)
  148 +{
  149 + QByteArray block;
  150 + QDataStream out(&block, QIODevice::WriteOnly);
  151 +
  152 + out.setVersion(QDataStream::Qt_5_4);
  153 +
  154 + out << block.size();
  155 + out << i_qsData.toLatin1();
  156 +
  157 + if (m_bServer)
  158 + {
  159 + m_clientConnection->write(block);
  160 + m_clientConnection->flush();
  161 + }
  162 + else
  163 + {
  164 + m_tcpSocket->write(block);
  165 + m_tcpSocket->flush();
  166 + }
  167 +}
  168 +
  169 +void TcpInterface::newConnection()
  170 +{
  171 + m_clientConnection = m_tcpServer->nextPendingConnection();
  172 + connect(m_clientConnection, SIGNAL(readyRead()), this, SLOT(readData()));
  173 +}
  174 +
  175 +}
  176 +}
src/tcpinterface.h 0 → 100644
  1 +++ a/src/tcpinterface.h
  1 +/* ****************************************************************************
  2 + * Copyright 2019 Open Systems Development BV *
  3 + * *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a *
  5 + * copy of this software and associated documentation files (the "Software"), *
  6 + * to deal in the Software without restriction, including without limitation *
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
  8 + * and/or sell copies of the Software, and to permit persons to whom the *
  9 + * Software is furnished to do so, subject to the following conditions: *
  10 + * *
  11 + * The above copyright notice and this permission notice shall be included in *
  12 + * all copies or substantial portions of the Software. *
  13 + * *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
  20 + * DEALINGS IN THE SOFTWARE. *
  21 + * ***************************************************************************/
  22 +
  23 +#ifndef OSDEV_COMPONENTS_CTCPINTERFACE_H
  24 +#define OSDEV_COMPONENTS_CTCPINTERFACE_H
  25 +
  26 +#include <QObject>
  27 +#include <QList>
  28 +
  29 +class QTcpServer;
  30 +class QTcpSocket;
  31 +
  32 +namespace osdev {
  33 +namespace components {
  34 +
  35 +/**
  36 + * @brief Handles a generic client or server point-to-point connection
  37 + *
  38 + * This class can be instantiated as a client or a server.
  39 + *
  40 + * @note The server can currently only handle one client at a time.
  41 + */
  42 +class TcpInterface : public QObject
  43 +{
  44 + Q_OBJECT
  45 +
  46 +public:
  47 + /**
  48 + * @brief Constructor
  49 + * @param hostName Host to connect with (client-mode), or interface to
  50 + * connect at (server-mode)
  51 + * @param port Selected port-number
  52 + * @param i_bServer False for client-mode, true for server-mode
  53 + */
  54 + TcpInterface(const QString& hostName, int port = 2776, bool i_bServer = false);
  55 + /// @brief Destructor
  56 + ~TcpInterface();
  57 +
  58 + /// Deleted copy-constructor
  59 + TcpInterface(const TcpInterface&) = delete;
  60 + /// Deleted assignment operator
  61 + TcpInterface& operator=(const TcpInterface&) = delete;
  62 + /// Deleted move-constructor
  63 + TcpInterface(TcpInterface&&) = delete;
  64 + /// Deleted move operator
  65 + TcpInterface& operator=(TcpInterface&&) = delete;
  66 +
  67 + /**
  68 + * @return if the interface is active.
  69 + * In server mode the interface is listening or connected to and in
  70 + * client mode the interface is connected.
  71 + */
  72 + bool active() const
  73 + {
  74 + return m_active;
  75 + }
  76 +
  77 + /**
  78 + * @brief Reads the first block of data from the received data
  79 + * @return First block of data, as a QString
  80 + */
  81 + QString getData();
  82 +
  83 +public slots:
  84 +
  85 + /**
  86 + * @brief Called when data is ready to be read into the buffer
  87 + */
  88 + void readData();
  89 +
  90 + /**
  91 + * @brief Send a block of data to the other party
  92 + * @param i_qsData Data to be sent
  93 + */
  94 + void sendData(const QString& i_qsData);
  95 +
  96 +signals:
  97 + /// @brief Emitted when data is present on the connection
  98 + void dataPresent();
  99 +
  100 +private slots:
  101 + /// @brief Slot called when a new connection is made
  102 + void newConnection();
  103 +
  104 +private:
  105 + bool m_bServer; ///< True for server-mode, false for client-mode
  106 + bool m_active; ///< True if in server mode the server is listening or connected to and in client mode when the client is connected.
  107 +
  108 + QTcpServer* m_tcpServer; ///< Server object instance
  109 + QTcpSocket* m_tcpSocket; ///< Client object instance
  110 +
  111 + QTcpSocket* m_clientConnection; ///< Current client connection
  112 +
  113 + quint32 m_blockSize; ///< Maximum size of a data-block
  114 + QList<QByteArray> m_dataList; ///< Blocks of data read from the counterpart
  115 +};
  116 +
  117 +} // End namespace components
  118 +} // End namespace osdev
  119 +
  120 +#endif /* OSDEV_COMPONENTS_CTCPINTERFACE_H */
src/tcpsocket.cpp 0 → 100644
  1 +++ a/src/tcpsocket.cpp
  1 +/* ****************************************************************************
  2 + * Copyright 2019 Open Systems Development BV *
  3 + * *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a *
  5 + * copy of this software and associated documentation files (the "Software"), *
  6 + * to deal in the Software without restriction, including without limitation *
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
  8 + * and/or sell copies of the Software, and to permit persons to whom the *
  9 + * Software is furnished to do so, subject to the following conditions: *
  10 + * *
  11 + * The above copyright notice and this permission notice shall be included in *
  12 + * all copies or substantial portions of the Software. *
  13 + * *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
  20 + * DEALINGS IN THE SOFTWARE. *
  21 + * ***************************************************************************/
  22 +#include "tcpsocket.h"
  23 +
  24 +#include "log.h"
  25 +
  26 +#include <QHostAddress>
  27 +#include <QTcpSocket>
  28 +#include <QTimer>
  29 +#include <QDataStream>
  30 +
  31 +namespace osdev {
  32 +namespace components {
  33 +
  34 +TcpSocket::TcpSocket( const QString& ipAddress, int portNumber )
  35 + : m_pSocket(new QTcpSocket(this))
  36 + , m_blockSize(0)
  37 + , m_dataBuffer()
  38 + , m_pTimer( new QTimer() )
  39 +{
  40 + // First we connect the timer to this class
  41 + connect(m_pTimer.get(), SIGNAL(timeout()), this, SLOT(chkSendBuffer()));
  42 +
  43 + this->connectSocketSignals();
  44 +
  45 + m_pSocket->connectToHost( QHostAddress( ipAddress ), static_cast<quint16>(portNumber) );
  46 + if( !m_pSocket->waitForConnected( 3000 ) )
  47 + {
  48 + LogDebug("interfaceplugin", "Socket failed to connect.");
  49 + LogObject("interfaceplugin", this);
  50 + }
  51 + else
  52 + {
  53 + LogDebug("interfaceplugin", "Client connected : ");
  54 + LogObject("interfaceplugin", m_pSocket);
  55 + }
  56 +}
  57 +
  58 +TcpSocket::TcpSocket(QTcpSocket *pSocket)
  59 + : m_pSocket(pSocket)
  60 + , m_blockSize(0)
  61 + , m_dataBuffer()
  62 + , m_pTimer( new QTimer() )
  63 +{
  64 + Q_ASSERT(pSocket);
  65 +
  66 + connect(m_pTimer.get(), SIGNAL(timeout()), this, SLOT(chkSendBuffer()));
  67 +
  68 + this->connectSocketSignals();
  69 +}
  70 +
  71 +TcpSocket::~TcpSocket()
  72 +{
  73 + // Implicitly deletes m_pSocket if this object is its parent
  74 +}
  75 +
  76 +void TcpSocket::slotReadyRead()
  77 +{
  78 + // Let the poolmanager know we are busy receiving data at the moment and are
  79 + // unavailable for anything else.
  80 + emit signalReceivingData( this );
  81 +
  82 + QDataStream in( m_pSocket );
  83 + in.setVersion( QDataStream::Qt_5_4 );
  84 +
  85 + if( m_blockSize == 0 )
  86 + {
  87 + if( m_pSocket->bytesAvailable() < static_cast<int>(sizeof( quint32 ) ) )
  88 + {
  89 + return;
  90 + }
  91 +
  92 + in >> m_blockSize;
  93 + }
  94 +
  95 + if( m_pSocket->bytesAvailable() < m_blockSize )
  96 + {
  97 + return;
  98 + }
  99 +
  100 + in >> m_dataBuffer;
  101 +
  102 + emit signalDataReceived( m_dataBuffer, this );
  103 +
  104 + m_blockSize = 0; // Reset the blockSize for next read.
  105 + m_dataBuffer.clear(); // Reset the buffer for the next read.
  106 +}
  107 +
  108 +void TcpSocket::slotSendData( const QString &sData, TcpSocket *pSocket )
  109 +{
  110 + if( pSocket != this || sData.isNull() ) {
  111 + return;
  112 + }
  113 +
  114 + QByteArray block;
  115 + QDataStream out( &block, QIODevice::WriteOnly );
  116 +
  117 + out.setVersion( QDataStream::Qt_5_4 );
  118 + out << block.size();
  119 + out << sData;
  120 +
  121 + m_pSocket->write( block );
  122 + chkSendBuffer();
  123 +}
  124 +
  125 +void TcpSocket::slotSetSocket(QTcpSocket* pSocket )
  126 +{
  127 + if(m_pSocket) {
  128 + disconnectSocketSignals();
  129 + }
  130 + m_pSocket = pSocket;
  131 + connectSocketSignals();
  132 +}
  133 +
  134 +void TcpSocket::chkSendBuffer()
  135 +{
  136 + m_pTimer->stop();
  137 +
  138 + if( m_pSocket->bytesToWrite() > 0 )
  139 + {
  140 + m_pSocket->flush();
  141 + m_pTimer->start( 500 );
  142 + }
  143 + else
  144 + {
  145 + emit signalDataSent( this );
  146 + }
  147 +}
  148 +
  149 +void TcpSocket::slotConnected()
  150 +{
  151 + emit signalConnected( this );
  152 +}
  153 +
  154 +void TcpSocket::slotDisconnected()
  155 +{
  156 + emit signalDisconnected( this );
  157 +}
  158 +
  159 +QString TcpSocket::showError()
  160 +{
  161 + if( m_pSocket )
  162 + {
  163 + return m_pSocket->errorString();
  164 + }
  165 + else
  166 + {
  167 + return "No socket available";
  168 + }
  169 +}
  170 +
  171 +void TcpSocket::connectSocketSignals()
  172 +{
  173 + Q_ASSERT(m_pSocket);
  174 + // Connect the required signals and slots to gain control.
  175 + // First for receiving data.
  176 + connect( m_pSocket, SIGNAL( readyRead() ),
  177 + this, SLOT( slotReadyRead() ) );
  178 +
  179 + connect( m_pSocket, SIGNAL( connected() ),
  180 + this, SLOT( slotConnected() ) );
  181 +
  182 + connect( m_pSocket, SIGNAL( disconnected() ),
  183 + this, SLOT( slotDisconnected() ) );
  184 +}
  185 +
  186 +void TcpSocket::disconnectSocketSignals()
  187 +{
  188 + Q_ASSERT(m_pSocket);
  189 + // Connect the required signals and slots to gain control.
  190 + // First for receiving data.
  191 + disconnect( m_pSocket, SIGNAL( readyRead() ),
  192 + this, SLOT( slotReadyRead() ) );
  193 +
  194 + disconnect( m_pSocket, SIGNAL( connected() ),
  195 + this, SLOT( slotConnected() ) );
  196 +
  197 + disconnect( m_pSocket, SIGNAL( disconnected() ),
  198 + this, SLOT( slotDisconnected() ) );
  199 +}
  200 +
  201 +bool TcpSocket::isConnected()
  202 +{
  203 + return m_pSocket && m_pSocket->state() == QTcpSocket::ConnectedState;
  204 +}
  205 +
  206 +}
  207 +}
src/tcpsocket.h 0 → 100644
  1 +++ a/src/tcpsocket.h
  1 +/* ****************************************************************************
  2 + * Copyright 2019 Open Systems Development BV *
  3 + * *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a *
  5 + * copy of this software and associated documentation files (the "Software"), *
  6 + * to deal in the Software without restriction, including without limitation *
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
  8 + * and/or sell copies of the Software, and to permit persons to whom the *
  9 + * Software is furnished to do so, subject to the following conditions: *
  10 + * *
  11 + * The above copyright notice and this permission notice shall be included in *
  12 + * all copies or substantial portions of the Software. *
  13 + * *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
  20 + * DEALINGS IN THE SOFTWARE. *
  21 + * ***************************************************************************/
  22 +
  23 +#ifndef OSDEV_COMPONENTS_CTCPSOCKET_H
  24 +#define OSDEV_COMPONENTS_CTCPSOCKET_H
  25 +
  26 +#include <QObject>
  27 +//#include <QTimer>
  28 +//#include <QTcpSocket>
  29 +//#include <QHostAddress>
  30 +//#include <QDataStream>
  31 +//#include <QString>
  32 +
  33 +#include <memory>
  34 +
  35 +class QTcpSocket;
  36 +class QTimer;
  37 +
  38 +namespace osdev {
  39 +namespace components {
  40 +
  41 +/**
  42 + * @brief Wrapper around QTcpSocket
  43 + */
  44 +class TcpSocket : public QObject
  45 +{
  46 + Q_OBJECT
  47 +
  48 +public:
  49 + /**
  50 + * @brief Create a TcpSocket connecting to the given address
  51 + * @param ipAddress Host to connect to
  52 + * @param portNumber Port number to connect at
  53 + */
  54 + TcpSocket( const QString& ipAddress, int portNumber );
  55 +
  56 + /**
  57 + * @brief Create a TcpSocket based on an existing QTcpSocket
  58 + * @param pSocket Socket used. This class does NOT take ownership of the
  59 + * provided socket.
  60 + */
  61 + TcpSocket( QTcpSocket *pSocket );
  62 +
  63 + /// Deleted copy-constructor
  64 + TcpSocket(const TcpSocket&) = delete;
  65 + /// Deleted assignment operator
  66 + TcpSocket& operator=(const TcpSocket&) = delete;
  67 + /// Deleted move-constructor
  68 + TcpSocket(TcpSocket&&) = delete;
  69 + /// Deleted move operator
  70 + TcpSocket& operator=(TcpSocket&&) = delete;
  71 +
  72 + /// @brief Destructor
  73 + ~TcpSocket();
  74 +
  75 + /**
  76 + * @brief Retrieve the last error registered in the socket
  77 + * @return Error string
  78 + */
  79 + QString showError();
  80 +
  81 + /**
  82 + * @brief See if a connection is available
  83 + * @return True if a connection is available, false otherwise
  84 + */
  85 + bool isConnected();
  86 +
  87 +public slots:
  88 + /**
  89 + * @brief Slot called to send data
  90 + * @param sData Data to send
  91 + * @param pSocket Socket to which to send. If it is not equal to this, the
  92 + * slot does nothing and returns
  93 + */
  94 + void slotSendData( const QString &sData, TcpSocket *pSocket );
  95 +
  96 + /**
  97 + * @brief Updates the current QTcpSocket used
  98 + * @param pSocket New socket
  99 + */
  100 + void slotSetSocket( QTcpSocket *pSocket );
  101 +
  102 + /// @brief Slot called when a socket gets connected
  103 + void slotConnected();
  104 +
  105 + /// @brief Slot called when a socket gets disconnected
  106 + void slotDisconnected();
  107 +
  108 +signals:
  109 + /**
  110 + * @brief Signal emitted when data is received
  111 + * @param sData Block of data received
  112 + * @param pSocket Receiving socket
  113 + */
  114 + void signalDataReceived( const QString &sData, TcpSocket *pSocket );
  115 +
  116 + /**
  117 + * @brief Signal emitted when data was sent
  118 + * @param pSocket Sending socket
  119 + */
  120 + void signalDataSent( TcpSocket *pSocket );
  121 +
  122 + /**
  123 + * @brief Signal emitted when data is being received
  124 + * @param pSocket Receiving socket
  125 + */
  126 + void signalReceivingData( TcpSocket *pSocket );
  127 +
  128 + /**
  129 + * @brief Signal emitted when a socket gets connected
  130 + * @param pSocket Socket that gets connected
  131 + */
  132 + void signalConnected( TcpSocket *pSocket );
  133 +
  134 + /**
  135 + * @brief Signal emitted when a socket gets disconnected
  136 + * @param pSocket Socket that gets disconnected
  137 + */
  138 + void signalDisconnected( TcpSocket *pSocket );
  139 +
  140 +private slots:
  141 + /// @brief Slot called when a socket is ready to read
  142 + void slotReadyRead();
  143 +
  144 + /// @brief Emits the signalDataSent when all data was sent
  145 + void chkSendBuffer();
  146 +
  147 +private:
  148 + /// @brief Connects the socket signals to the slots of this class
  149 + void connectSocketSignals();
  150 +
  151 + /// @brief Disconnects the socket signals to the slots of this class
  152 + void disconnectSocketSignals();
  153 +
  154 + QTcpSocket *m_pSocket; ///< Current communication socket
  155 + int m_blockSize; ///< Maximum block size
  156 + QString m_dataBuffer; ///< Data to be sent
  157 +
  158 + std::unique_ptr<QTimer> m_pTimer; ///< Periodic check if all data was sent
  159 +};
  160 +
  161 +} // End namespace components
  162 +} // End namespace osdev
  163 +
  164 +#endif // OSDEV_COMPONENTS_CTCPSOCKET_H
tests/CMakeLists.txt 0 → 100644
  1 +++ a/tests/CMakeLists.txt
  1 +cmake_minimum_required(VERSION 3.0)
  2 +LIST(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../cmake)
  3 +
  4 +include(projectheader)
  5 +project_header(test_logutils)
  6 +
  7 +include_directories( SYSTEM
  8 + ${CMAKE_CURRENT_SOURCE_DIR}/../../src
  9 +)
  10 +
  11 +include(compiler)
  12 +set(SRC_LIST
  13 +)
  14 +
  15 +# add_executable( ${PROJECT_NAME}
  16 +# ${SRC_LIST}
  17 +# )
  18 +
  19 +# target_link_libraries(
  20 +# ${PROJECT_NAME}
  21 +# )
  22 +
  23 +# set_target_properties( ${PROJECT_NAME} PROPERTIES
  24 +# RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin
  25 +# LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib
  26 +# ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/archive
  27 +# )
  28 +
  29 +# include(installation)
  30 +# install_application()