Commit 99048c1cbf0e97b4906a75462ece3f7db4979387
0 parents
Initial commit. dependencies not resolved yet.
Showing
15 changed files
with
1661 additions
and
0 deletions
.gitignore
0 → 100644
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() |