From afc69ca4ffb0e11d9d06b8ddd31ee40963f86f17 Mon Sep 17 00:00:00 2001 From: Manuel Schneider Date: Wed, 28 May 2014 00:37:28 +0200 Subject: Outsource serverDiscovery. --- src/client/connectwindow/connectwindow.cpp | 233 +++++++++-------------------- 1 file changed, 72 insertions(+), 161 deletions(-) (limited to 'src/client/connectwindow/connectwindow.cpp') diff --git a/src/client/connectwindow/connectwindow.cpp b/src/client/connectwindow/connectwindow.cpp index c8f7efd..34087ad 100644 --- a/src/client/connectwindow/connectwindow.cpp +++ b/src/client/connectwindow/connectwindow.cpp @@ -16,16 +16,19 @@ #define UDPBUFSIZ 9000 #define SALT_LEN 18 -/** +/***************************************************************************//** * Initialize Connection Window. * @param parent */ -ConnectWindow::ConnectWindow(QWidget *parent) : - QWidget(parent), _ui(new Ui::ConnectWindow), _connected(false), - _timerDiscover(0), _timerHide(0), _connection(NULL), _state(Idle), - _hashErrorCount(0), _hashSslErrorCount(0), _certErrorCount(0), - _ipErrorCount(0), _discoveryInterval(800) -{ +ConnectWindow::ConnectWindow(QWidget *parent) : QWidget(parent) +{ + _ui = new Ui::ConnectWindow; + _connected = false; + _timerHide = 0; + _connection = NULL; + _state = Idle; + _hashSslErrorCount = 0; + // Initialize the GUI _ui->setupUi(this); @@ -39,53 +42,21 @@ ConnectWindow::ConnectWindow(QWidget *parent) : connect(_ui->btn_connection, SIGNAL(clicked()), this, SLOT(onBtnConnection())); connect(_ui->btn_hide, SIGNAL(clicked()), this, SLOT(onBtnHide())); - 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(){} + // React on discovery signal + connect(&_serverDiscovery, SIGNAL(serverDetected(QString,quint16,QByteArray,QByteArray)), + this, SLOT(onServerDetected(QString,quint16,QByteArray,QByteArray))); -/** - * Set Client as Connected (true) or Disconnected (false). - * After settings updateState() is called. - * @param connected - */ -void ConnectWindow::setConnected(const bool connected) -{ - _connected = connected; this->updateState(); - if (_state == Scanning) - { - killTimer(_timerDiscover); - _discoveryInterval = 1000; - _timerDiscover = startTimer(_discoveryInterval); - } } -/** - * Set current state of Client. - * After setting state updateState() is called. - * @param state +/***************************************************************************//** + * @brief ConnectWindow::~ConnectWindow */ -void ConnectWindow::setState(const ConnectionState state) -{ - if (_state != state) - { - _state = state; - this->updateState(); - } -} +ConnectWindow::~ConnectWindow(){} + -/** + +/***************************************************************************//** * Handle changes in state and update window. * Also changing TextLabel which shows the user what the program is doing. */ @@ -115,7 +86,6 @@ void ConnectWindow::updateState() break; case Scanning: _ui->lblStatus->setText(tr("Scanning for session %1.").arg(_ui->lineEditName->text())); - _timerDiscover = startTimer(_discoveryInterval); break; case Connecting: _ui->lblStatus->setText(tr("Found session, connecting...")); @@ -132,12 +102,11 @@ void ConnectWindow::updateState() case Connected: _ui->lblStatus->setText(tr("Connection established!")); break; - case InvalidIpList: - case InvalidHash: case InvalidCert: + _ui->lblStatus->setText(tr("Invalid certificate.")); + break; case InvalidSslHash: - _ui->lblStatus->setText(tr("Invalid hash: %1; invalid cert: %2; invalid iplist: %3; invalid sslhash: %4") - .arg(_hashErrorCount).arg(_certErrorCount).arg(_ipErrorCount).arg(_hashSslErrorCount)); + _ui->lblStatus->setText(tr("Invalid Ssl hash: %1.").arg(_hashSslErrorCount)); break; } } @@ -146,57 +115,13 @@ void ConnectWindow::updateState() * Overrides */ -/** +/***************************************************************************//** * Called when a Qt timer fires; used for server discovery and * auto-hiding the connect dialog. */ 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(&_sessionNameBytes, &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) + if(event->timerId() == _timerHide) { killTimer(_timerHide); _timerHide = 0; @@ -204,11 +129,11 @@ void ConnectWindow::timerEvent(QTimerEvent* event) _ui->stackedWidget->setCurrentIndex(0); } else - // Unknown/Old timer id, kill it + // Unknown/Old timer id, kill it ??? PALM -> FACE killTimer(event->timerId()); } -/** +/***************************************************************************//** * Handle incoming closeEvent and hide window. * @param e */ @@ -218,7 +143,7 @@ void ConnectWindow::closeEvent(QCloseEvent *e) this->hide(); } -/** +/***************************************************************************//** * Gives the keyboard input focus to the input line. * @param event */ @@ -227,7 +152,7 @@ void ConnectWindow::showEvent(QShowEvent* event) _ui->lineEditName->setFocus(); } -/** +/***************************************************************************//** * Public function connect to session. * Check if currently connected to server, * if not --> connect to given sessionName. @@ -237,19 +162,16 @@ void ConnectWindow::connectToSession(const QByteArray sessionName) { if (_connected || _state != Idle) return; - - _discoveryInterval = 800; - _sessionNameBytes = sessionName; - _timerDiscover = startTimer(_discoveryInterval); - _hashErrorCount = _hashSslErrorCount = _certErrorCount = _ipErrorCount = 0; - this->setState(Scanning); + _state = Scanning; + this->updateState(); + _serverDiscovery.start(_ui->lineEditName->text().toUtf8()); } /* * Slots */ -/** +/***************************************************************************//** * Handle click on Connect/Disconnect button. * If already connected --> Stop/disconnect. * Else scanning for given sessionId. @@ -258,17 +180,19 @@ void ConnectWindow::onBtnConnection() { if (_timerHide){ killTimer(_timerHide); + _timerHide = 0; _ui->stackedWidget->setCurrentIndex(0); } - _timerHide = 0; - if (_timerDiscover) - killTimer(_timerDiscover); + + if (_serverDiscovery.isActive()) + _serverDiscovery.stop(); + if (_connected || _state != Idle) { // Stop or disconnect - _timerDiscover = 0; emit disconnect(); - this->setState(Idle); + _state = Idle; + this->updateState(); } else { @@ -277,7 +201,7 @@ void ConnectWindow::onBtnConnection() } } -/** +/***************************************************************************//** * Handle click on Cancel/Hide Button. * Just hide the window. */ @@ -286,53 +210,24 @@ void ConnectWindow::onBtnHide() this->hide(); } -/** - * Handle incoming service discovery packets. + +/***************************************************************************//** + * @brief ConnectWindow::onServerDetected + * @param host + * @param port + * @param sessionName + * @param certHash */ -void ConnectWindow::onUdpReadyRead() +void ConnectWindow::onServerDetected(const QString& host, const quint16 port, const QByteArray& sessionName, const QByteArray& certHash) { - 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(&_sessionNameBytes, &_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(), _sessionNameBytes, cert); - connect(_connection, SIGNAL(stateChange(ConnectWindow::ConnectionState)), this, SLOT(onConnectionStateChange(ConnectWindow::ConnectionState))); - connect(_connection, SIGNAL(destroyed(QObject*)), this, SLOT(onConnectionClosed(QObject*))); - } + _connection = new ServerConnection(host, port, sessionName, certHash); + connect(_connection, SIGNAL(stateChange(ConnectWindow::ConnectionState)), this, SLOT(onConnectionStateChange(ConnectWindow::ConnectionState))); + connect(_connection, SIGNAL(destroyed(QObject*)), this, SLOT(onConnectionClosed(QObject*))); + connect(_connection, SIGNAL(disconnected()), this, SLOT(onConnectionDisconnected())); } -/** + +/***************************************************************************//** * Handle connection state changes and update member variables describing state. * @param state */ @@ -341,7 +236,10 @@ void ConnectWindow::onConnectionStateChange(ConnectWindow::ConnectionState state bool reset = (_state == Scanning); if (state == InvalidSslHash) ++_hashSslErrorCount; - this->setState(state); + + _state = state; + this->updateState(); + if (reset) _state = Scanning; if (state == Connected) @@ -349,12 +247,16 @@ void ConnectWindow::onConnectionStateChange(ConnectWindow::ConnectionState state 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); + + _connected = true; + this->updateState(); + _connection = NULL; _timerHide = startTimer(2000); } } -/** +/***************************************************************************//** * If connection is closed set _connection = NULL. * @param connection */ @@ -362,3 +264,12 @@ void ConnectWindow::onConnectionClosed(QObject* connection) { _connection = NULL; } + +/***************************************************************************//** + * @brief ConnectWindow::onConnectionDisconnected + */ +void ConnectWindow::onConnectionDisconnected() +{ + _connected = false; + this->updateState(); +} -- cgit v1.2.3-55-g7522