summaryrefslogtreecommitdiffstats
path: root/src/client/net/serverdiscovery.cpp
diff options
context:
space:
mode:
authorManuel Schneider2014-05-28 00:37:28 +0200
committerManuel Schneider2014-05-28 00:37:28 +0200
commitafc69ca4ffb0e11d9d06b8ddd31ee40963f86f17 (patch)
treef7284ba33e98d2bb6e099f248c7b127282efa99f /src/client/net/serverdiscovery.cpp
parentRemove TODO. User get visual feedback via cam icon. (diff)
downloadpvs2-afc69ca4ffb0e11d9d06b8ddd31ee40963f86f17.tar.gz
pvs2-afc69ca4ffb0e11d9d06b8ddd31ee40963f86f17.tar.xz
pvs2-afc69ca4ffb0e11d9d06b8ddd31ee40963f86f17.zip
Outsource serverDiscovery.
Diffstat (limited to 'src/client/net/serverdiscovery.cpp')
-rw-r--r--src/client/net/serverdiscovery.cpp181
1 files changed, 181 insertions, 0 deletions
diff --git a/src/client/net/serverdiscovery.cpp b/src/client/net/serverdiscovery.cpp
new file mode 100644
index 0000000..9f1991c
--- /dev/null
+++ b/src/client/net/serverdiscovery.cpp
@@ -0,0 +1,181 @@
+
+#include <QNetworkInterface>
+#include "../../shared/settings.h"
+#include "../../shared/network.h"
+#include "../../shared/util.h"
+#include "serverdiscovery.h"
+#include <assert.h>
+
+
+/***************************************************************************//**
+ * Ctor
+ */
+ServerDiscovery::ServerDiscovery(QObject *parent) : QObject(parent)
+{
+ _hashErrorCount = 0;
+ _ipErrorCount = 0;
+
+ /* Try to get a UDP port for server discovery */
+ int tries = 10;
+ while (tries-- != 0)
+ {
+ const quint16 port = (quint16)(qrand() % 10000) + 10000;
+ if (_discoverySocket.bind(QHostAddress::Any, port))
+ break;
+ if (tries == 0)
+ qFatal("Could not bind to any UDP port for server discovery.");
+ }
+ // Handle incoming messages
+ connect(&_discoverySocket, SIGNAL(readyRead()), this, SLOT(onUdpReadyRead()));
+
+ /* Setup the discovery timer */
+ _discoveryTimer.setInterval(500);
+ _discoveryTimer.setSingleShot(true);
+ //
+ connect(&_discoveryTimer, SIGNAL(timeout()), this, SLOT(doDiscovery()));
+}
+
+/***************************************************************************//**
+ * Dtor
+ */
+ServerDiscovery::~ServerDiscovery()
+{
+}
+
+/***************************************************************************//**
+ * @brief start
+ */
+void ServerDiscovery::start(const QByteArray& sessionName)
+{
+ assert(!this->isActive());
+
+ // Set the session which is searched
+ _nameBytes = sessionName;
+
+ // Enable signal emittance
+ this->blockSignals(false);
+
+ // Reset the error counters
+ _hashErrorCount = _ipErrorCount = 0;
+
+ // reset anbd start the discovery timer
+ _discoveryTimer.setInterval(500);
+ _discoveryTimer.start();
+}
+
+/***************************************************************************//**
+ * @brief stop
+ */
+void ServerDiscovery::stop()
+{
+ assert(this->isActive());
+
+ //Bock further signal emittance
+ this->blockSignals(true);
+ _discoveryTimer.stop();
+}
+
+/*******************************************************************************
+ * SLOTS
+ ***************************************************************************//**
+ * @brief ConnectWindow::doDiscovery
+ */
+void ServerDiscovery::doDiscovery()
+{
+ // Send discovery
+ _packet.reset();
+ QByteArray iplist(Network::interfaceAddressesToString().toUtf8());
+ // qDebug
+ QByteArray salt1(SALT_LEN, 0);
+ if (_salt2.size() < SALT_LEN)
+ _salt2.resize(SALT_LEN);
+ for (int i = 0; i < SALT_LEN; ++i) {
+ salt1[i] = qrand() & 0xff;
+ _salt2[i] = qrand() & 0xff;
+ }
+ _packet.reset();
+ _packet.setField(_HASH, genSha1(&_nameBytes, &salt1, &iplist));
+ _packet.setField(_SALT1, salt1);
+ _packet.setField(_SALT2, _salt2);
+ _packet.setField(_IPLIST, iplist);
+ foreach (QNetworkInterface interface, QNetworkInterface::allInterfaces())
+ {
+ foreach (QNetworkAddressEntry entry, interface.addressEntries())
+ {
+ if (!entry.broadcast().isNull() && entry.ip() != QHostAddress::LocalHost && entry.ip() != QHostAddress::LocalHostIPv6)
+ {
+ qDebug() << "Broadcasting to " << entry.broadcast().toString();
+ if (!_packet.writeMessage(&_discoverySocket, entry.broadcast(), SERVICE_DISCOVERY_PORT))
+ qDebug("FAILED");
+ }
+ }
+ }
+ qDebug("Broadcasting to 255.255.255.255");
+ if (!_packet.writeMessage(&_discoverySocket, QHostAddress::Broadcast, SERVICE_DISCOVERY_PORT))
+ qDebug("FAILED");
+
+ // Start the timer again with a larger interval
+ if (_discoveryTimer.interval() < 5000)
+ _discoveryTimer.setInterval(_discoveryTimer.interval() * 2);
+ _discoveryTimer.start();
+}
+
+
+/***************************************************************************//**
+ * Handle incoming service discovery packets.
+ */
+void ServerDiscovery::onUdpReadyRead()
+{
+ char data[UDPBUFSIZ];
+ QHostAddress addr;
+ quint16 port;
+ while (_discoverySocket.hasPendingDatagrams())
+ {
+ // Discard any packets if discovery is stopped
+ if (!this->isActive()){
+ _discoverySocket.readDatagram(NULL, 0);
+ continue;
+ }
+
+ const qint64 size = _discoverySocket.readDatagram(data, UDPBUFSIZ, &addr, &port);
+ if (size <= 0) //|| _connection != NULL) // TODO CHECK
+ continue;
+
+ _packet.reset();
+ if (!_packet.readMessage(data, (quint32)size))
+ continue;
+
+ // Valid packet, process it:
+ const QByteArray hash(_packet.getFieldBytes(_HASH));
+ const QByteArray iplist(_packet.getFieldBytes(_IPLIST));
+ const QByteArray port(_packet.getFieldBytes(_PORT));
+ const QByteArray cert(_packet.getFieldBytes(_CERT));
+
+ // Check if the source IP of the packet matches any of the addresses given in the IP list
+ if (!Network::isAddressInList(QString::fromUtf8(iplist), addr.toString()))
+ {
+ ++_ipErrorCount;
+ emit error(ErrorType::InvalidIpList, _hashErrorCount);
+ continue;
+ }
+
+ // If so, check if the submitted hash seems valid
+ if (genSha1(&_nameBytes, &_salt2, &iplist, &port, &cert) != hash)
+ {
+ // did not match local session name, or other data was spoofed
+ ++_hashErrorCount;
+ emit error(ErrorType::InvalidHash, _ipErrorCount);
+ continue;
+ }
+
+ /* Otherwise it's a valid reply */
+ qDebug() << "Server detected:"
+ << addr.toString() + ":" + QString::fromUtf8(port) + "/" + _nameBytes;
+
+ // Tell that a server hs been found
+ emit serverDetected(addr.toString(), (quint16)QString::fromUtf8(port).toInt(), _nameBytes, cert);
+
+ // Stop the discovery
+ this->stop();
+ }
+}