summaryrefslogtreecommitdiffstats
path: root/src/net/pvsLocalhostCommunicator.cpp
blob: 20783bb4a247848f5a6d5eb533d7bbc67fc268b7 (plain) (blame)
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
#include "pvsLocalhostCommunicator.h"
#include "src/util/consoleLogger.h"
#include "src/net/pvsMsg.h"

static QHostAddress localhost(QHostAddress::LocalHost);
#define localport 14913

PVSLocalhostCommunicator::PVSLocalhostCommunicator(QString path)
{
    _isServer = _isRunning = false;
    _sock = NULL;
}

void PVSLocalhostCommunicator::run()
{
    if (_isRunning)
        return;

    // First try to run as server
    _sock = new QUdpSocket();
    // We'll bind only to localhost, so nobody else can send commands (from remote hosts)
    // Otherwise we had to check the remote addr when receiving a datagram, but this
    // wouldn't be as secure since you can easily fake it
    _sock->bind(localhost, localport); // QUdpSocket::DontShareAddress? would need root
    connect(_sock, SIGNAL(readyRead()), this, SLOT(sock_dataArrival()));

    if (_sock->state() == QAbstractSocket::BoundState)
    {
        // OK, we are the first daemon to run
        _isServer = true;
        _isRunning = true;
        return;
    }
    if (_sock->bind())
    {
        _isRunning = true;
    }
}

void PVSLocalhostCommunicator::stop()
{
    _isRunning = false;
    _sock->deleteLater();
    _sock = NULL;
}

void PVSLocalhostCommunicator::sock_dataArrival()
{
    if (_sock == NULL) return;

    qint64 dsize;
    while ((dsize = _sock->pendingDatagramSize()) > -1)   // returns -1 if no more datagrams are pending
    {
        if (dsize < 4)   // anything shorter than 4 bytes is not a valid PVSMsg anyways, so take a shortcut
        {
            char x;
            _sock->readDatagram(&x, 1, NULL, NULL);
            continue; // discard the packet and see if there is more
        }

        PVSMsg receiver;
        receiver.readMessage(_sock, true);

        if (receiver.isMsgComplete())
        {
            // we received a message, so fire away
            ConsoleLog writeNetwork(QString("Received UDS command: ").append(receiver.getIdent()));
            _daemonDispatcher.fire(receiver.getIdent(), receiver);
        } // If the msg is not complete we have to discard it, since UDP
        // is packet oriented and we could not say for sure if the next one
        // would be the continuation of this msg.
        // Usually on the loopback interface it is safe to send datagrams
        // up to 8kb, so this is not be an issue anyway.
    }
}

void PVSLocalhostCommunicator::sendCommand(QString ident, QString cmd)
{
    if (_isRunning && !_isServer && _sock != NULL)
    {
        PVSMsg sender(PVSDAEMON, ident, cmd);
        char *data;
        int len;
        sender.getBinaryData(data, len);
        QByteArray qba(data, len);
        qDebug("Sending %d bytes to daemon...", qba.length());
        qint64 result = _sock->writeDatagram(qba, localhost, localport);
        _sock->waitForBytesWritten(100);

        // simply bail out on an error or disconnect or whatever
        if (result != len)
        {
            if (result == -1)
            {
                qDebug("Error sending PVSMsg to daemon: %s", qPrintable(_sock->errorString()));
            }
            else
            {
                qDebug("Sent PVSMsg was incomplete.");
            }
            stop();
        }
    }
}