#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(); } } }