GCC Code Coverage Report


source/XpertMassCore/src/
File: source/XpertMassCore/src/MassDataServer.cpp
Date: 2025-11-20 01:41:33
Lines:
0/71
0.0%
Functions:
0/11
0.0%
Branches:
0/60
0.0%

Line Branch Exec Source
1 /* BEGIN software license
2 *
3 * MsXpertSuite - mass spectrometry software suite
4 * -----------------------------------------------
5 * Copyright (C) 2009--2020 Filippo Rusconi
6 *
7 * http://www.msxpertsuite.org
8 *
9 * This file is part of the MsXpertSuite project.
10 *
11 * The MsXpertSuite project is the successor of the massXpert project. This
12 * project now includes various independent modules:
13 *
14 * - massXpert, model polymer chemistries and simulate mass spectrometric data;
15 * - mineXpert, a powerful TIC chromatogram/mass spectrum viewer/miner;
16 *
17 * This program is free software: you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation, either version 3 of the License, or
20 * (at your option) any later version.
21 *
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * You should have received a copy of the GNU General Public License
28 * along with this program. If not, see <http://www.gnu.org/licenses/>.
29 *
30 * *****************************************************************************
31 * This specific code is a port to C++ of the Envemind Python code by Radzinski
32 * and colleagues of IsoSpec fame (Lacki, Startek and company :-)
33 *
34 * See https://github.com/PiotrRadzinski/envemind.
35 * *****************************************************************************
36 *
37 * END software license
38 */
39
40
41 #include <QDebug>
42 #include <QDateTime>
43 #include <QtNetwork>
44
45 #include "MsXpS/libXpertMassCore/MassDataServer.hpp"
46
47 namespace MsXpS
48 {
49 namespace libXpertMassCore
50 {
51
52
53 /*!
54 \class MsXpS::libXpertMassCore::MassDataServer
55 \inmodule libXpertMassCore
56 \ingroup XpertMassCoreUtilities
57 \inheaderfile MassDataServer.hpp
58
59 \brief The MassDataServer class provides a network server.
60 */
61
62 /*!
63 \variable MsXpS::libXpertMassCore::MassDataServer::m_ipAddress
64
65 \brief The IP address at which this server serves data.
66 */
67
68 /*!
69 * \variable MsXpS::libXpertMassCore::MassDataServer::m_portNumber
70 *
71 * \brief The port number at which this server serves data.
72 */
73
74 /*!
75 * \variable MsXpS::libXpertMassCore::MassDataServer::m_clients
76 *
77 * \brief The list of QTcpSocket instances representing the clients connected to
78 * this server.
79 */
80
81 /*!
82 * \variable MsXpS::libXpertMassCore::MassDataServer::m_readyClients
83 *
84 * \brief The list of QTcpSocket instances representing the clients connected to
85 * this server and effectively expecting data from this server.
86 */
87
88 /*!
89 \brief Constructs a MassDataServer instance.
90
91 \list
92 \li \a parent: QObject parent.
93 \endlist
94 */
95 MassDataServer::MassDataServer(QObject *parent): QTcpServer(parent)
96 {
97 }
98
99 /*!
100 \brief Destructs this MassDataServer instance.
101 */
102 MassDataServer::~MassDataServer()
103 {
104 }
105
106 bool
107 MassDataServer::start()
108 {
109 if(!listen())
110 {
111 qDebug() << "Failed to start the server.";
112 return false;
113 }
114
115 // At this point try to get to the details.
116
117 QList<QHostAddress> ip_addressesList = QNetworkInterface::allAddresses();
118
119 // Use the first non-localhost IPv4 address
120 for(int i = 0; i < ip_addressesList.size(); ++i)
121 {
122 if(ip_addressesList.at(i) != QHostAddress::LocalHost &&
123 ip_addressesList.at(i).toIPv4Address())
124 {
125 m_ipAddress = ip_addressesList.at(i).toString();
126 break;
127 }
128 }
129
130 // If we did not find one, use IPv4 localhost
131 if(m_ipAddress.isEmpty())
132 m_ipAddress = QHostAddress(QHostAddress::LocalHost).toString();
133
134 m_portNumber = serverPort();
135
136 return true;
137 }
138
139 QString
140 MassDataServer::getIpAddress() const
141 {
142 return m_ipAddress;
143 }
144
145 int
146 MassDataServer::getPortNumber() const
147 {
148 return m_portNumber;
149 }
150
151 /*!
152 \brief Sets to this MassDataServer instance the data to be served in
153 \a byte_array_to_serve.
154 */
155 void
156 MassDataServer::serveData(const QByteArray &byte_array_to_serve)
157 {
158 if(!byte_array_to_serve.size())
159 return;
160
161 for(QTcpSocket *client_p : m_readyClients)
162 {
163 if(client_p->state() == QAbstractSocket::ConnectedState)
164 {
165 QByteArray byte_array;
166 QDataStream out_stream(&byte_array, QIODevice::WriteOnly);
167 out_stream.setVersion(QDataStream::Qt_5_0);
168 out_stream << byte_array_to_serve;
169
170 qDebug() << "On the verge of writing byte_array of size:"
171 << byte_array.size();
172
173 int written_bytes = client_p->write(byte_array);
174 client_p->flush();
175
176 qDebug() << "Now written " << written_bytes
177 << " bytes to the socket at" << QDateTime::currentDateTime();
178
179 if(written_bytes >= byte_array.size())
180 {
181 qDebug() << "Data successfully written.";
182
183 emit writtenDataSignal(written_bytes);
184 }
185 else
186 {
187 qWarning() << "The data written to the socket were less than the "
188 "initial data.";
189 }
190 }
191 }
192 }
193
194 /*!
195 \brief Handles an incoming connection with socket descriptor \a
196 socket_descriptor.
197
198 If the connection is effective, that is, if a QTcpSocket client
199 could be allocated and configured with \a socket_descriptor, that client is
200 appended to the \l{m_clients} list of clients.
201 */
202 void
203 MassDataServer::incomingConnection(qintptr socket_descriptor)
204 {
205
206 // It is not because we have not data to use as a response to the caller
207 // that we do not perform the connection and then closing stuff! Otherwise we
208 // consume a file descriptor (the socket) each time a connection is tried
209 // here from the client.... Bug that has broken my head for weeks...
210
211 QTcpSocket *client_tcp_socket_p = new QTcpSocket(this);
212
213 if(!client_tcp_socket_p->setSocketDescriptor(socket_descriptor))
214 {
215 delete client_tcp_socket_p;
216 return;
217 }
218
219 qDebug() << "MineXpert3 connected from"
220 << client_tcp_socket_p->peerAddress().toString() << ":"
221 << client_tcp_socket_p->peerPort();
222
223 connect(client_tcp_socket_p,
224 &QTcpSocket::disconnected,
225 this,
226 [this, client_tcp_socket_p]() {
227 qDebug() << "One client has disconnected, removing it.";
228
229 qDebug() << "Before removing, there are" << m_readyClients.size()
230 << "ready clients.";
231 m_readyClients.remove(client_tcp_socket_p);
232 qDebug() << "Now remaining" << m_readyClients.size()
233 << "ready clients.";
234
235 qDebug() << "Before removing, there are" << m_clients.size()
236 << "clients.";
237 m_clients.removeOne(client_tcp_socket_p);
238 qDebug() << "Now remaining" << m_clients.size() << "clients.";
239
240 client_tcp_socket_p->deleteLater();
241 });
242
243 // When the client connects, it sends a "READY" message that we catch
244 // to unambiguously determine that the client is connected.
245 connect(client_tcp_socket_p,
246 &QTcpSocket::readyRead,
247 this,
248 [this, client_tcp_socket_p]() {
249 QByteArray msg = client_tcp_socket_p->readAll();
250
251 if(msg.contains("READY"))
252 {
253 qDebug() << "MineXpert3 is ready!";
254 m_readyClients.insert(client_tcp_socket_p);
255 }
256 });
257
258 m_clients.append(client_tcp_socket_p);
259
260 qDebug() << "MineXpert3 connected";
261
262 m_clients.append(client_tcp_socket_p);
263 }
264
265 /*!
266 \brief Returns true if this server has clients (\l{MassDataClient}) that are
267 ready to receive data.
268 */
269 bool
270 MassDataServer::hasReadyClient() const
271 {
272 return !m_readyClients.isEmpty();
273 }
274
275 /*!
276 \brief Reports the \a socket_error to the console using qDebug().
277 */
278 void
279 MassDataServer::error(QTcpSocket::SocketError socket_error)
280 {
281 qDebug() << "An error occurred in the mass data server:" << socket_error;
282 }
283
284
285 } // namespace libXpertMassCore
286
287 } // namespace MsXpS
288