-
Notifications
You must be signed in to change notification settings - Fork 0
/
TcpSocketThread.cpp
357 lines (280 loc) · 12.4 KB
/
TcpSocketThread.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
#include <TcpSocketThread.h>
#include <auto_ptr.h>
#include <QCoreApplication>
#include <QHostAddress>
#include <QTime>
#include <TcpCommands/main/userLogin.h>
#include <TcpCommands/main/serverVersion.h>
#include <Logger/Logger.h>
#include <TcpCommandFactories.h>
#include <dbModels/dbAbstractModel.h>
#include "Database/DatabasePool.h"
#include <Config.h>
#include "Utils/UtilUsers.h"
#include "Utils/UtilDataStream.h"
TcpSocketThread::TcpSocketThread(int descriptor, QObject *parent) : QThread(parent)
{
// Sich selber in den Thread verschieben...
moveToThread(this);
// Socket erstellen und in den Thread verschrieben...
if ( ! _socket.setSocketDescriptor(descriptor) ) {
logError("Could not set socket descriptor for the new connection. Disconnect client.");
_socket.close();
}
_socket.setParent(NULL);
_socket.moveToThread(this);
}
void TcpSocketThread::checkState() {
qDebug() << _socket.state();
}
void TcpSocketThread::run() {
_timeoutTimer = new QTimer(this);
_timeoutTimer->moveToThread(this);
_timeoutTimer->setInterval(SOCKET_TIMEOUT);
connect(_timeoutTimer, SIGNAL(timeout()), this, SLOT(socketTimeout()));
_timeoutTimer->start(SOCKET_TIMEOUT);
// Ist noch kein Socket Deskriptor gesetzt, so ist beim setzen ein
// Fehler aufgetreten, und wir beenden diesen Thread...
if (_socket.socketDescriptor() == -1) {
logError("Socket descriptor for this socket not set. Exit tcp thread...");
return;
}
// IP Adresse & Port loggen...
logNotice( QString("Client connection from IP %1, port %2, to port %3")
.arg(_socket.localAddress().toString(),
QString::number( _socket.localPort() ),
QString::number( _socket.peerPort() )
)
);
logDebug("Thread for the connection started.");
logDebug("Install eventhandler, to close this thread, when tcp connection closed.");
connect(&_socket, SIGNAL(disconnected()), this, SLOT(quit()));
connect(&_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(socketError(QAbstractSocket::SocketError)));
// Wenn neue Daten zum lesen vorhanden sind:
connect(&_socket, SIGNAL(readyRead()), this, SLOT(newDataToRead()));
// Datenstream auf Socket setzen:
_socketBlockSize = 0;
/**
* Nun fangen wir an, am Tcp Port zu lauschen...
*/
logDebug("And now, i am waiting for data to read...");
exec();
}
void TcpSocketThread::newDataToRead() {
QTime timeStart( QTime::currentTime() );
try {
// Die zu verarbeitenden Daten, welche vom Client zum Server gesendet wurden...
QByteArray clientData;
logDebug("New Data to read available.");
// Wurde schon bestimmt, wie viele Bytes vom Client erwarten zu sind?
if (_socketBlockSize == 0) {
logDebug("Try to detect the size of the incoming data...");
// Wurden schon genug Daten empfangen, um die zu erwartenden Block zu bestimmen?
if (_socket.bytesAvailable() <= sizeof(quint32) ) {
// Wir müssen auf mehr Daten des Clients warten...
logDebug("Not enough data arrived. I wait for more data...");
return;
}
// Anzahl erwartende Bytes:
QDataStream dataStream(&_socket);
dataStream >> _socketBlockSize;
logDebug( QString("Size of incoming data detected. Size are %1 bits").arg(QString::number(_socketBlockSize)) );
}
// Wurden vom Client bereits alle Daten empfangen???
if (_socket.bytesAvailable() != _socketBlockSize) {
logDebug("Not all data packages from the client arrived (%1 from %2 bytes) Wait for more data...",
QString::number(_socket.bytesAvailable()), QString::number(_socketBlockSize) );
return;
}
else {
logDebug("All data from the client arrived. Start parsing the data...");
clientData = _socket.read(_socketBlockSize);
}
QDataStream dataStreamRead(&clientData, QIODevice::ReadWrite);
/**
* Alle Daten vom Client empfangen, jetzt folgt die Bearbeitung der
* empfangenen Daten
*/
logDebug("Start extract the incoming datas...");
// Art des Befehls:
// 0 -> TcpCommand group/command
// 1 -> timeout reseter
quint8 tcpType;
UtilDataStream::read(dataStreamRead, tcpType);
switch (tcpType) {
case 0:
/**
* Tcp Command:
*/
{
// Kommunikations- ID:
quint16 commId;
UtilDataStream::read(dataStreamRead, commId);
// Gruppenname, in welcher sich diese Aktion befindet.
QByteArray group;
UtilDataStream::read(dataStreamRead, group);
// Name der auszuführenden Aktion
QByteArray action;
UtilDataStream::read(dataStreamRead, action);
logNotice("Try to find action %1/%2...", group, action);
std::auto_ptr<TcpAbstractCommand> command( TcpCommandFactories::instance()->createCommand(group, action) );
// Wurde 0 zurückgegeben, so existiert der Befehl nicht...
if (command.get() == 0) {
logError("Could not run tcp command '%1/%2'. Action does not exists!", group, action);
close();
return;
}
command->setCommId(commId);
command->setSocket(&_socket);
command->setUserAccount(&_user);
command->setDataStreamRead(&dataStreamRead);
/**
* Überprüfen, ob Befehl ausgeführt werden darf...
*/
TcpAbstractCommand::TCP_RESPONSE_TYPE answerType = TcpAbstractCommand::NORMAL_RESPONSE;
// Hat User die Berechtigungen, diesen Befehl auszuführen??
if (! UtilUsers::canRunTcpCommand(_user.getColumn("id").toInt(), group, action) ) {
/**
* Benutzer hat nicht entsprechende Berechtigungen, um diesen Befehl auszuführen:
*/
logError("User has not enough permissions to run the tcp action %1/%2", group, action);
answerType = TcpAbstractCommand::TCP_PERMISSION_ERROR;
}
else {
// Befehl ausführen:
logDebug("Run action %1/%2...", group, action);
QVariant execReturn = command->exec();
logDebug("Run postExec().");
command->postExec( execReturn );
}
logDebug("Tramsit data over the tcp socket to the client...");
command->writeDataStream(answerType);
logDebug("Datastream transmitted success!...");
break;
}
case 1:
{
/**
* Timeout Reseter:
*/
logDebug("Reset socket timeout.");
// wir schreiben den Client die Zahl "15253" zurück...
QByteArray dataStreamWriteArray;
QDataStream dataStreamWrite(&dataStreamWriteArray, QIODevice::WriteOnly);
quint16 answer = 15253;
dataStreamWrite << (quint32) sizeof(quint16);
dataStreamWrite << answer;
_socket.write(dataStreamWriteArray);
_socket.flush();
break;
}
default:
logError("Unknown tcpType. Bye!");
close();
return;
}
logError("Tcp transction time: " + QString::number(timeStart.msecsTo(QTime::currentTime())) + "ms");
_timeoutTimer->stop();
_timeoutTimer->start(SOCKET_TIMEOUT);
}
catch (SqlException &e) {
logFatal("Ein SQL Fehler ist aufgetreten!");
logFatal("SQL: \n%1\n%2", e.sql(), e.error().databaseText());
logFatal("Driver error: %1", e.error().driverText() );
close();
}
catch (UtilDataStreamReadException &e) {
logFatal("Error by reading tcp datastream data. close tcp connection.");
logFatal("Error message is: %1", e.error());
}
catch (UtilDataStreamWriteException &e) {
logFatal("Error by wrting tcp datastream data. close tcp connection.");
logFatal("Error message is: %1", e.error());
}
// Empfangene Daten wurden nun abgearbeitet, daher in den Ursprungszustand
// zurücksetzen und auf die nächsten Daten warten...
_socketBlockSize = 0;
}
void TcpSocketThread::socketTimeout() {
logWarning("Socket timeout " + QString::number(SOCKET_TIMEOUT) + " ms reached. Close connection.");
close();
}
void TcpSocketThread::close() {
// Schließt die Tcp Verbindung, und das werfende Signal "disconnected" der Tcp- Verbindung
// beendet diesen Thread...
_socket.close();
}
// Wird aufgerufen, wenn der Thread beendet wurde..
void TcpSocketThread::deleteLater() {
// Müssen das Objekt zum Hauptthread verschieben, ansonstne erhalten wir ein Memory Leah
moveToThread(QCoreApplication::instance()->thread());
logNotice("Client connection closed, destroy tcp socket thread...");
// deleteLater der geerbten Klasse aufrufen, um Objekt zu zerstören...
QThread::deleteLater();
}
void TcpSocketThread::socketError(QAbstractSocket::SocketError errId) {
QString message;
switch (errId) {
case 0:
message = "The connection was refused by the peer (or timed out).";
break;
case 1:
message = "The remote host closed the connection.";
break;
case 2:
message = "The host address was not found.";
break;
case 3:
message = "The socket operation failed because the application lacked the required privileges.";
break;
case 4:
message = "The local system ran out of resources (e.g., too many sockets).";
break;
case 5:
message = "The socket operation timed out.";
break;
case 6:
message = "The datagram was larger than the operating system's limit.";
break;
case 7:
message = "An error occurred with the network (e.g., the network cable was accidentally plugged out).";
break;
// 8 and 9 only udp...
case 10:
message = "The requested socket operation is not supported by the local operating system (e.g., lack of IPv6 support).";
break;
case 11:
message = "Used by QAbstractSocketEngine only, The last operation attempted has not finished yet (still in progress in the background).";
break;
case 12:
message = "The socket is using a proxy, and the proxy requires authentication.";
break;
case 13:
message = "The SSL/TLS handshake failed, so the connection was closed.";
break;
case 14:
message = "Could not contact the proxy server because the connection to that server was denied.";
break;
case 15:
message = "The connection to the proxy server was closed unexpectedly (before the connection to the final peer was established).";
break;
case 16:
message = "The connection to the proxy server timed out or the proxy server stopped responding in the authentication phase.";
break;
case 17:
message = "The proxy address was not found.";
break;
case 18:
message = "The connection negotiation with the proxy server because the response from the proxy server could not be understood.";
break;
case -1:
message = "An unidentified error occurred.";
break;
default:
message = QString("TcpMainThread::emitTcpError(QString &message) have not defined the errorId QAbstractSocket::SocketError -> %1")
.arg( QString::number(errId) );
}
logNotice("TCP connection closed, reason: " + message);
// Verbindung schließen:
close();
}