summaryrefslogtreecommitdiffstats
path: root/src/client/connectwindow/connectwindow.cpp
diff options
context:
space:
mode:
authorsr2013-02-04 19:50:31 +0100
committersr2013-02-04 19:50:31 +0100
commit1a5709501f94014d41987b956338bb6424b9f90c (patch)
treed3b93fe8dc406bca56aff147ef5cc4cbf9ed6be0 /src/client/connectwindow/connectwindow.cpp
parentTest (diff)
downloadpvs2-1a5709501f94014d41987b956338bb6424b9f90c.tar.gz
pvs2-1a5709501f94014d41987b956338bb6424b9f90c.tar.xz
pvs2-1a5709501f94014d41987b956338bb6424b9f90c.zip
Initial commit
Diffstat (limited to 'src/client/connectwindow/connectwindow.cpp')
-rw-r--r--src/client/connectwindow/connectwindow.cpp284
1 files changed, 284 insertions, 0 deletions
diff --git a/src/client/connectwindow/connectwindow.cpp b/src/client/connectwindow/connectwindow.cpp
new file mode 100644
index 0000000..bc4e9b2
--- /dev/null
+++ b/src/client/connectwindow/connectwindow.cpp
@@ -0,0 +1,284 @@
+/*
+ * connectwindow.cpp
+ *
+ * Created on: 28.01.2013
+ * Author: sr
+ */
+
+#include "connectwindow.h"
+#include "../../shared/settings.h"
+#include "../../shared/network.h"
+#include "../../shared/util.h"
+
+#include "../net/serverconnection.h"
+
+#include <QNetworkInterface>
+
+#define UDPBUFSIZ 9000
+#define SALT_LEN 18
+
+ConnectWindow::ConnectWindow(QWidget *parent) :
+ QDialog(parent), _connected(false), _timerDiscover(0), _timerHide(0), _connection(NULL), _state(Idle),
+ _hashErrorCount(0), _hashSslErrorCount(0), _certErrorCount(0), _ipErrorCount(0), _discoveryInterval(800)
+{
+ setupUi(this);
+ //
+ connect(cmdOK, SIGNAL(clicked()), this, SLOT(onOkClick()));
+ connect(cmdCancel, SIGNAL(clicked()), this, SLOT(onCancelClick()));
+ 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.");
+ }
+ connect(&_discoverySocket, SIGNAL(readyRead()), this, SLOT(onUdpReadyRead()));
+ this->setState(Idle);
+}
+
+ConnectWindow::~ConnectWindow()
+{
+
+}
+
+void ConnectWindow::setConnected(const bool connected)
+{
+ _connected = connected;
+ this->updateState();
+ if (_state == Scanning)
+ {
+ killTimer(_timerDiscover);
+ _discoveryInterval = 1000;
+ _timerDiscover = startTimer(_discoveryInterval);
+ }
+}
+
+void ConnectWindow::setState(const ConnectionState state)
+{
+ if (_state != state)
+ {
+ _state = state;
+ this->updateState();
+ }
+}
+
+void ConnectWindow::updateState()
+{
+ txtName->setEnabled(_state == Idle && !_connected);
+
+ if (_connected)
+ {
+ cmdOK->setEnabled(true);
+ cmdOK->setText(tr("&Disconnect"));
+ lblStatus->setText(tr("Connected."));
+ txtName->setEnabled(false);
+ return;
+ }
+
+ if (_state != Idle)
+ cmdOK->setText(tr("&Stop"));
+ else
+ cmdOK->setText(tr("&Connect"));
+
+ switch (_state)
+ {
+ case Idle:
+ lblStatus->setText(tr("Ready to connect; please enter session name."));
+ break;
+ case Scanning:
+ lblStatus->setText(tr("Scanning for session %1.").arg(txtName->text()));
+ _timerDiscover = startTimer(_discoveryInterval);
+ break;
+ case Connecting:
+ lblStatus->setText(tr("Found session, connecting..."));
+ break;
+ case AwaitingChallenge:
+ lblStatus->setText(tr("Waiting for server challenge..."));
+ break;
+ case AwaitingChallengeResponse:
+ lblStatus->setText(tr("Replied to challenge, sent own..."));
+ break;
+ case LoggingIn:
+ lblStatus->setText(tr("Logging in..."));
+ break;
+ case Connected:
+ lblStatus->setText(tr("Connection established!"));
+ break;
+ case InvalidIpList:
+ case InvalidHash:
+ case InvalidCert:
+ case InvalidSslHash:
+ lblError->setText(tr("Invalid hash: %1; invalid cert: %2; invalid iplist: %3; invalid sslhash: %4")
+ .arg(_hashErrorCount).arg(_certErrorCount).arg(_ipErrorCount).arg(_hashSslErrorCount));
+ break;
+ }
+}
+
+/**
+ * Overrides
+ */
+
+void ConnectWindow::timerEvent(QTimerEvent* event)
+{
+ if (event->timerId() == _timerDiscover)
+ {
+ killTimer(_timerDiscover);
+ if (_connected || _state != Scanning) // Not scanning, bail out
+ return;
+ if (_discoveryInterval < 30000)
+ _discoveryInterval += 100;
+ _timerDiscover = startTimer(_discoveryInterval);
+ // Don't send packet if we're trying to connect
+ if (_connection != NULL)
+ return;
+ // Send discovery
+ _packet.reset();
+ QByteArray iplist(Network::interfaceAddressesToString().toUtf8());
+ 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");
+ // End send discovery
+ }
+ else if(event->timerId() == _timerHide)
+ {
+ killTimer(_timerHide);
+ _timerHide = 0;
+ this->hide();
+ }
+ else
+ // Unknown/Old timer id, kill it
+ killTimer(event->timerId());
+}
+
+void ConnectWindow::closeEvent(QCloseEvent *e)
+{
+ e->ignore();
+ this->hide();
+}
+
+/**
+ * Slots
+ */
+
+void ConnectWindow::onOkClick()
+{
+ if (_timerHide)
+ killTimer(_timerHide);
+ _timerHide = 0;
+ if (_timerDiscover)
+ killTimer(_timerDiscover);
+ if (_connected || _state != Idle)
+ {
+ // Stop or disconnect
+ _timerDiscover = 0;
+ emit disconnect();
+ this->setState(Idle);
+ }
+ else
+ {
+ // Connect (scan for session)
+ _discoveryInterval = 800;
+ _nameBytes = txtName->text().toUtf8();
+ _timerDiscover = startTimer(_discoveryInterval);
+ _hashErrorCount = _hashSslErrorCount = _certErrorCount = _ipErrorCount = 0;
+ this->setState(Scanning);
+ }
+}
+
+void ConnectWindow::onCancelClick()
+{
+ this->hide();
+}
+
+void ConnectWindow::onUdpReadyRead()
+{
+ char data[UDPBUFSIZ];
+ QHostAddress addr;
+ quint16 port;
+ while (_discoverySocket.hasPendingDatagrams())
+ {
+ const qint64 size = _discoverySocket.readDatagram(data, UDPBUFSIZ, &addr, &port);
+ if (size <= 0 || _connection != NULL)
+ 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;
+ this->setState(InvalidIpList);
+ this->setState(Scanning);
+ 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;
+ this->setState(InvalidHash);
+ this->setState(Scanning);
+ continue;
+ }
+ // Otherwise it's a valid reply, try to connect
+ _connection = new ServerConnection(addr.toString(), (quint16)QString::fromUtf8(port).toInt(), _nameBytes, cert);
+ connect(_connection, SIGNAL(stateChange(ConnectWindow::ConnectionState)), this, SLOT(onConnectionStateChange(ConnectWindow::ConnectionState)));
+ connect(_connection, SIGNAL(destroyed(QObject*)), this, SLOT(onConnectionClosed(QObject*)));
+ }
+}
+
+void ConnectWindow::onConnectionStateChange(ConnectWindow::ConnectionState state)
+{
+ bool reset = (_state == Scanning);
+ if (state == InvalidSslHash)
+ ++_hashSslErrorCount;
+ this->setState(state);
+ if (reset)
+ _state = Scanning;
+ if (state == Connected)
+ {
+ QObject::disconnect(_connection, SIGNAL(stateChange(ConnectWindow::ConnectionState)), this, SLOT(onConnectionStateChange(ConnectWindow::ConnectionState)));
+ QObject::disconnect(_connection, SIGNAL(destroyed(QObject*)), this, SLOT(onConnectionClosed(QObject*)));
+ emit connected(_connection);
+ _connection = NULL;
+ _timerHide = startTimer(2000);
+ }
+}
+
+void ConnectWindow::onConnectionClosed(QObject* connection)
+{
+ _connection = NULL;
+}