aboutsummaryrefslogtreecommitdiff
path: root/src/UdpTasks/StatusChecker/oncheckerresponseread.cpp
blob: 098058a6d9a7dee1a461d579e322ef55f1d10ddf (plain)
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
    }
}