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
|
#include "statuschecker.h"
void StatusChecker::onTicker()
{
// get next recent item from database (id > index)
QSqlQuery q = getNextServer(_dbIndex);
if ( q.next() )
{
// get serverinfo from query
_dbIndex = q.value("id").toInt();
QString remoteAddress = q.value("ip").toString();
unsigned short remotePort = static_cast<unsigned short>(q.value("queryport").toInt());
QString gamename = q.value("gamename").toString();
bool authenticated = static_cast<unsigned short>(q.value("f_auth").toBool());
// if this particular server was added through SYNC, it may not yet have been authenticated.
// send secure/validate challenge in that case
if ( ! authenticated )
{
// shorthand label
QString remoteAddressLabel = QStringLiteral("%1:%2").arg(remoteAddress, QString::number(remotePort));
QString secure = genChallengeString(6, false);
// use HeartBeat struct to cache gamename+secure
// TODO optimise the HeartBeat struct in BeaconServer to cater both purposes
UdpData secureInfo;
secureInfo.secure = secure;
secureInfo.gamename = gamename;
_secureBuffer.insert(remoteAddressLabel, secureInfo);
// send secure challenge
QString udpSecure = QStringLiteral("\\secure\\%1").arg(secure);
QNetworkDatagram udpSecureDatagram(udpSecure.toUtf8(), QHostAddress(remoteAddress), remotePort);
_udpSocket.writeDatagram(udpSecureDatagram);
}
// create datagram with info- or status request
QNetworkDatagram udpDatagram(_udpRequest.toUtf8(), QHostAddress(remoteAddress), remotePort);
// and send
_udpSocket.writeDatagram(udpDatagram);
// readyRead miss workaround
if ( _udpSocket.hasPendingDatagrams() )
{
/* WORKAROUND INFO
* _udpSocket.bytesAvailable() > 0 and _udpSocket.hasPendingDatagrams(),
* but apparently no readyRead signal was emitted. As a result, incoming data
* is no longer processed. Temporary fix until the cause has been found:
* emit readyRead manually when datagrams are available. It is still possible
* that the ticker is faster than the readyRead-bound function and that readyRead
* was issued correctly, so we count two ticks of missed read calls. If the
* readyRead signal was correctly issued, the onUdpResponseRead function will
* reset the missed readcall counter. Even when botched, it is better to emit the
* same signal twice, rather than not at all (onUdpResponseRead has a failsaife
* for duplicate/redundant calls).
*
* Other info:
* is this related to https://www.qtcentre.org/threads/64370-QUdpSocket-readyRead-failure ?
*
* Displaying readyread state and available data:
qDebug() << "bytes available: "
<< _udpSocket.bytesAvailable()
<< "pending datagrams: "
<< _udpSocket.hasPendingDatagrams()
;
*/
_missedReadCalls++;
// two missed calls in 2 ticks, emit signal manually
if ( _missedReadCalls >= 2)
{
_coreObject->Log.logEvent("warning", "checker udp data not signalled: emitting readyread manually");
emit _udpSocket.readyRead();
}
} // end workaround
} // end next
}
|