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
|
#include "statuschecker.h"
void StatusChecker::onUdpResponseRead()
{
// read now called, reset workaround counter
_missedReadCalls = 0;
while ( _udpSocket.hasPendingDatagrams() )
{
// get sender and payload
QNetworkDatagram datagram = _udpSocket.receiveDatagram();
QString senderAddress = QHostAddress( datagram.senderAddress().toIPv4Address() ).toString();
unsigned short senderPort = datagram.senderPort();
QString receiveBuffer = datagram.data();
receiveBuffer = receiveBuffer.toLatin1();
// shorthand label
QString senderAddressLabel = QStringLiteral("%1:%2").arg(senderAddress, QString::number(senderPort));
_coreObject->Log.logEvent("udp", QStringLiteral("%1 sent '%2'").arg(senderAddressLabel, receiveBuffer ) );
// ignore empty data packets (query port forwarded to a game port)
if (receiveBuffer.length() <= 0)
continue;
// determine protocol and response based on the first character (backslash, byte value, ... )
unsigned short protocol_chooser = receiveBuffer.at(0).unicode();
if (protocol_chooser != 92)
continue;
// buffer complete? else wait for data to be complete
_dataBuffer[senderAddressLabel] += receiveBuffer;
// status response or validate response? (either status or secure, not both)
if ( receiveBuffer.contains("\\validate\\") )
{
// parse key/value pairs and QHash label
QMultiHash<QString, QString> receiveData = parseGameSpy0Buffer(_dataBuffer[senderAddressLabel]);
// load existing information
QString secure = _secureBuffer.value(senderAddressLabel).secure;
QString gamename = _secureBuffer.value(senderAddressLabel).gamename;
// if entry, secure, gamename and/or cipher do not exist, AuthResult will be false+invalid
AuthResult authResult = validateGamename(false, // this is not a beacon
gamename,
receiveData.value("validate",""),
_coreObject->SupportedGames.value(gamename).cipher,
secure,
receiveData.value("enctype", "0").toInt() );
// compare with received response
if ( authResult.auth )
{
// server authenticated - log and add to database
_coreObject->Log.logEvent("secure", QStringLiteral("successful validate from %1 for %2")
.arg(senderAddressLabel, gamename));
// update the existing entry
updateServer(senderAddress, senderPort, gamename, false, true);
// remove from secure buffer
_secureBuffer.remove(senderAddressLabel);
}
else // log failed validate
{
// set validate false (but update last response time)
updateServer(senderAddress, senderPort, gamename, false, false);
_coreObject->Log.logEvent("secure", QStringLiteral("failed validate from %1 for %2")
.arg(senderAddressLabel, gamename));
_coreObject->Log.logEvent("secure", QStringLiteral("secure: '%1', gamename: '%2', validate: '%3', expected: '%4'")
.arg(secure, gamename, receiveData.value("validate", "null"), authResult.validate ));
}
// clear receive buffer
_dataBuffer.remove(senderAddressLabel);
// there should be no further data (ignore)
continue;
}
// all status query data received?
if (receiveBuffer.contains("\\final\\"))
{
// parse key/value pairs and QHash label
QMultiHash<QString, QString> receiveData = parseGameSpy0Buffer(_dataBuffer[senderAddressLabel]);
// update or insert primary details
if ( ! updateServer(senderAddress, senderPort, receiveData.value("gamename", "unknown"), false, false) )
{
// add to database
insertServer(senderAddress, senderPort, receiveData.value("gamename", "unknown"), false);
}
// then update detailed information
if ( ! updateServerInfo(senderAddress, senderPort, receiveData) )
{
// insert and update new entry (this does NOT insert to the serverlist, only info)
// this assumes that an entry with this ip/port exists in the serverlist (fails silently)
insertServerInfo(senderAddress, senderPort);
updateServerInfo(senderAddress, senderPort, receiveData);
}
// update player info (removes old playerdata entries)
insertPlayerInfo(senderAddress, senderPort, receiveData);
// clear receive buffer
_dataBuffer.remove(senderAddressLabel);
} // if final
}
}
|