aboutsummaryrefslogtreecommitdiff
path: root/src/TcpTasks/SyncClient/onsyncread.cpp
blob: c0f0b7340f68e84b8d1985e7b82a2b2344158fe3 (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
#include "syncclient.h"

void SyncClient::onSyncRead()
{
    // reset timeout after receiving (any) data
    _timeOut.start();

    // read from tcp connection and append to buffer
    QByteArray receiveBuffer = _tcpSocket.readAll();
    _rxBuffer.append( receiveBuffer );

    // prevent large heaps of text -- log only relevant message, not masterserver data
    if ( receiveBuffer.length() > 30 )
    {
        // log size of data
        _coreObject->Log.logEvent("tcp", QStringLiteral("%1 sent %2 characters")
                                  .arg(_clientLabel, QString::number(receiveBuffer.length()) ) );
    }
    else
    {
        // log message
        _coreObject->Log.logEvent("tcp", QStringLiteral("%1 sent '%2'")
                                  .arg(_clientLabel, receiveBuffer.data()) );
    }

    // remote masterserver opens with secure challenge
    if ( _rxBuffer.contains("secure") )
    {
        // parse to hash
        QMultiHash<QString, QString> receiveData = parseGameSpy0Buffer(_rxBuffer.toLatin1());

        // generate response
        QStringList response = replyQuery(receiveData);

        // return response
        _tcpSocket.write(response.join("").toLatin1());

        // sync request
        QString request = QStringLiteral("\\sync\\%1\\msid\\%2")
                .arg(_coreObject->Settings.SyncerSettings.syncGames,
                     _coreObject->masterserverIdentity);
        _tcpSocket.write(request.toLatin1());

        // all relevant information received. clear buffer for next interaction
        _rxBuffer = "";
        return;
    }

    if ( _rxBuffer.contains("final") )
    {
        // parse to hash: receivedData format is {gamename} => {string of addresses}
        QMultiHash<QString, QString> receiveData = parseGameSpy0Buffer(_rxBuffer.toLatin1());
        receiveData.remove("final"); // prevent "final" from registering as gamename

        // count number of addresses for logging
        int totalServerCount = 0;

        // use transaction for SQLite
        QSqlDatabase::database().transaction();

        // parse to list of list of <ServerInfo>
        QHashIterator<QString,QString> receiveDataIterator(receiveData);
        while ( receiveDataIterator.hasNext() )
        {
            // {gamename} => {string of addresses}
            receiveDataIterator.next();
            QString gamename          = receiveDataIterator.key();
            QString addressBufferList = receiveDataIterator.value();

            // split address list in single addresses
            QStringListIterator listIterator( addressBufferList.split(" ", QString::SkipEmptyParts) );
            while ( listIterator.hasNext() )
            {
                // address (ip:port)
                QString        addr       = listIterator.next();

                // older Qt5 masterservers sync in ::ffff:127.0.0.1 format, trim the '::ffff:'
                addr.remove("::ffff:");

                // (address cont.)
                QStringList    address    = addr.split(':');
                unsigned short remotePort = address.takeLast().toUShort();
                QString        remoteAddr = address.join(":"); // IPv4 has only 1 element, IPv6 has 4 that need joining with ':'

                // valid address?
                if ( ! QHostAddress(remoteAddr).isNull() and remotePort > 0 )
                {
                    // if it does not exist in the db, insert
                    if ( ! updateSyncedServer(remoteAddr, remotePort) )
                    {
                        // add
                        insertServer(remoteAddr, remotePort, gamename, false);
                    }
                }
                totalServerCount++;
            } // has next address
        } // has next game

        // commit SQLite
        QSqlDatabase::database().commit();

        // report in log
        _coreObject->Log.logEvent("sync", QStringLiteral("received %1 servers in %2 games from %3")
                                  .arg( QString::number(totalServerCount),
                                        QString::number(receiveData.count()),
                                        _clientLabel)
                                  );
    } // if final

    // else keep appending data until \\final\\ is received
}