summaryrefslogtreecommitdiffstats
path: root/src/net
diff options
context:
space:
mode:
authorSebastian2010-05-12 19:42:27 +0200
committerSebastian2010-05-12 19:42:27 +0200
commitce3329047d378a14006ce74ec273ac59e3375303 (patch)
tree782430f270b4c7aca1b35d5b7813518e3797c555 /src/net
downloadpvs-ce3329047d378a14006ce74ec273ac59e3375303.tar.gz
pvs-ce3329047d378a14006ce74ec273ac59e3375303.tar.xz
pvs-ce3329047d378a14006ce74ec273ac59e3375303.zip
initial import of latest svn version
Diffstat (limited to 'src/net')
-rw-r--r--src/net/SslServer.cpp130
-rw-r--r--src/net/SslServer.h50
-rw-r--r--src/net/pvsClientConnection.cpp178
-rw-r--r--src/net/pvsClientConnection.h67
-rw-r--r--src/net/pvsDiscoveredServer.cpp152
-rw-r--r--src/net/pvsDiscoveredServer.h63
-rw-r--r--src/net/pvsListenServer.cpp308
-rw-r--r--src/net/pvsListenServer.h106
-rw-r--r--src/net/pvsLocalhostCommunicator.cpp104
-rw-r--r--src/net/pvsLocalhostCommunicator.h51
-rw-r--r--src/net/pvsMsg.cpp207
-rw-r--r--src/net/pvsMsg.h73
-rw-r--r--src/net/pvsServerConnection.cpp243
-rw-r--r--src/net/pvsServerConnection.h99
-rw-r--r--src/net/pvsServiceBroadcast.cpp51
-rw-r--r--src/net/pvsServiceBroadcast.h46
-rw-r--r--src/net/pvsServiceDiscovery.cpp181
-rw-r--r--src/net/pvsServiceDiscovery.h57
18 files changed, 2166 insertions, 0 deletions
diff --git a/src/net/SslServer.cpp b/src/net/SslServer.cpp
new file mode 100644
index 0000000..e353e0a
--- /dev/null
+++ b/src/net/SslServer.cpp
@@ -0,0 +1,130 @@
+/*
+# Copyright (c) 2009 - OpenSLX Project, Computer Center University of Freiburg
+#
+# This program is free software distributed under the GPL version 2.
+# See http://openslx.org/COPYING
+#
+# If you have any feedback please consult http://openslx.org/feedback and
+# send your suggestions, praise, or complaints to feedback@openslx.org
+#
+# General information about OpenSLX can be found at http://openslx.org/
+# -----------------------------------------------------------------------------
+# src/net/SslServer.cpp
+# - provide QTcpServer-like behaviour for SSL
+# -----------------------------------------------------------------------------
+*/
+
+#include "SslServer.h"
+#include <QtNetwork/QSslCipher>
+#include <QtNetwork/QSslSocket>
+#include "src/util/CertManager.h"
+
+
+SslServer::SslServer()
+{
+ _tmr = startTimer(7000);
+ //QSslSocket::setDefaultCiphers(QSslSocket::supportedCiphers());
+}
+
+SslServer::~SslServer()
+{
+ killTimer((_tmr));
+}
+
+void SslServer::incomingConnection(int socketDescriptor)
+{
+ QSslSocket *serverSocket = new QSslSocket(this);
+ connect(serverSocket,
+ SIGNAL(sslErrors(const QList<QSslError> &)),
+ this,
+ SLOT(sslErrors(const QList<QSslError> &))
+ );
+ serverSocket->setPrivateKey(CertManager::getPrivateKey("manager"));
+ serverSocket->setLocalCertificate(CertManager::getCertificate("manager"));
+ serverSocket->setPeerVerifyMode(QSslSocket::VerifyNone);
+ serverSocket->setProtocol(QSsl::SslV3);
+ //printf("Keylen %d\n", serverSocket->privateKey().length());
+ if (serverSocket->setSocketDescriptor(socketDescriptor))
+ {
+ // Once the connection is successfully encrypted, raise out newConnection event
+ connect(serverSocket, SIGNAL(encrypted()), this, SIGNAL(newConnection()));
+ serverSocket->startServerEncryption();
+ _pending.push_back(serverSocket);
+ }
+ else
+ {
+ delete serverSocket;
+ }
+}
+
+void SslServer :: sslErrors ( const QList<QSslError> & errors )
+{
+ printf("FIXME: SSL ERRORS on SERVER: %s\n", errors.begin()->errorString().toUtf8().data());
+}
+
+void SslServer::timerEvent (QTimerEvent* event)
+{
+ // Remove all sockets marked for deletion
+ for (QList<QSslSocket*>::iterator it = _delete.begin(); it != _delete.end(); it++)
+ {
+ (*it)->deleteLater();
+ }
+ _delete.clear();
+ // Mark all sockets for deletion where the ssl handshake did not happen after connecting
+ /*
+ bool flag;
+ do
+ {
+ flag = false;
+ for (QList<QSslSocket*>::iterator it = _pending.begin(); it != _pending.end(); it++)
+ {
+ if ((*it)->state() != QAbstractSocket::ConnectedState || !(*it)->isEncrypted())
+ {
+ _delete.push_back(*it);
+ _pending.removeAll(*it);
+ flag = true;
+ break;
+ }
+
+ }
+ }
+ while (flag);
+ */
+ _delete.append(_pending);
+ _pending.clear();
+}
+
+bool SslServer::hasPendingConnections()
+{
+ for (QList<QSslSocket*>::iterator it = _pending.begin(); it != _pending.end(); it++)
+ {
+ printf("State: %d - Encrypted: %d\n", (int)(*it)->state(), (*it)->isEncrypted());
+ if ((*it)->state() == QAbstractSocket::ConnectedState && (*it)->isEncrypted()) return true;
+ }
+ return false;
+}
+
+QTcpSocket* SslServer::nextPendingConnection()
+{
+ for (QList<QSslSocket*>::iterator it = _pending.begin(); it != _pending.end(); it++)
+ {
+ if ((*it)->state() == QAbstractSocket::ConnectedState && (*it)->isEncrypted())
+ {
+ _pending.removeAll(*it);
+ _delete.removeAll(*it);
+ return *it;
+ }
+ }
+ for (QList<QSslSocket*>::iterator it = _delete.begin(); it != _delete.end(); it++)
+ {
+ if ((*it)->state() == QAbstractSocket::ConnectedState && (*it)->isEncrypted())
+ {
+ _pending.removeAll(*it);
+ _delete.removeAll(*it);
+ return *it;
+ }
+ }
+ return NULL;
+}
+
+
diff --git a/src/net/SslServer.h b/src/net/SslServer.h
new file mode 100644
index 0000000..b1efeea
--- /dev/null
+++ b/src/net/SslServer.h
@@ -0,0 +1,50 @@
+/*
+# Copyright (c) 2009 - OpenSLX Project, Computer Center University of Freiburg
+#
+# This program is free software distributed under the GPL version 2.
+# See http://openslx.org/COPYING
+#
+# If you have any feedback please consult http://openslx.org/feedback and
+# send your suggestions, praise, or complaints to feedback@openslx.org
+#
+# General information about OpenSLX can be found at http://openslx.org/
+# -----------------------------------------------------------------------------
+# src/net/SslServer.cpp
+# - provide QTcpServer-like behaviour for SSL
+# -----------------------------------------------------------------------------
+*/
+
+#ifndef SSLSERVER_H_
+#define SSLSERVER_H_
+
+#include <QtCore/QList>
+#include <QtNetwork/QTcpServer>
+#include <QtNetwork/QSslError>
+
+class QSslSocket;
+
+class SslServer : public QTcpServer
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+ void sslErrors ( const QList<QSslError> & errors );
+
+public:
+ SslServer();
+ virtual ~SslServer();
+
+ virtual bool hasPendingConnections ();
+ // This one has to return a TcpSocket as we're overwriting from the base class
+ // just cast it to QSslSocket later
+ virtual QTcpSocket* nextPendingConnection();
+
+protected:
+ virtual void incomingConnection(int socketDescriptor);
+ void timerEvent (QTimerEvent* event);
+ QList<QSslSocket*> _pending;
+ QList<QSslSocket*> _delete;
+ int _tmr;
+};
+
+#endif /* SSLSERVER_H_ */
diff --git a/src/net/pvsClientConnection.cpp b/src/net/pvsClientConnection.cpp
new file mode 100644
index 0000000..dff40d5
--- /dev/null
+++ b/src/net/pvsClientConnection.cpp
@@ -0,0 +1,178 @@
+/*
+# Copyright (c) 2009,2010 - OpenSLX Project, Computer Center University of
+# Freiburg
+#
+# This program is free software distributed under the GPL version 2.
+# See http://openslx.org/COPYING
+#
+# If you have any feedback please consult http://openslx.org/feedback and
+# send your suggestions, praise, or complaints to feedback@openslx.org
+#
+# General information about OpenSLX can be found at http://openslx.org/
+# -----------------------------------------------------------------------------
+# pvsClientConnection.cpp
+# - ???.
+# -----------------------------------------------------------------------------
+*/
+
+#include "pvsClientConnection.h"
+#include "pvsListenServer.h"
+#include "src/util/consoleLogger.h"
+
+#include <cassert>
+#include <QtNetwork/QHostAddress>
+
+
+PVSClientConnection::PVSClientConnection(PVSListenServer* server, QSslSocket* sock)
+{
+ assert(sock);
+ assert(server);
+ _socket = sock;
+ _incomplete = NULL;
+ _toldDisconnect = false;
+ _server = server;
+ _lastData = time(NULL);
+ sock->setParent(this); // for automatic deletion
+ connect(_socket, SIGNAL(readyRead()), this, SLOT(sock_dataArrival()));
+ connect(_socket, SIGNAL(disconnected()), this, SLOT(sock_closed()));
+ connect(_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(sock_error(QAbstractSocket::SocketError)));
+}
+
+PVSClientConnection::~PVSClientConnection()
+{
+ this->closeConnection();
+ if (_incomplete != NULL) delete _incomplete;
+ if (_socket != NULL)
+ {
+ disconnect(_socket, SIGNAL(readyRead()), this, SLOT(sock_dataArrival()));
+ disconnect(_socket, SIGNAL(disconnected()), this, SLOT(sock_closed()));
+ disconnect(_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(sock_error(QAbstractSocket::SocketError)));
+ _socket->abort();
+ }
+}
+
+void PVSClientConnection::closeConnection()
+{
+ if (_toldDisconnect) return; // we already got served
+ if (_socket == NULL || _socket->state() == QAbstractSocket::UnconnectedState)
+ {
+ // should not happen but handled anyway
+ _toldDisconnect = true;
+ _server->disconnectClient(this);
+ return;
+ }
+ if (_socket->state() == QAbstractSocket::ClosingState) return; // sock_close() slot should eventually be called, nothing to do
+ if (_socket->state() == QAbstractSocket::ConnectedState) // this is what should be the case normally
+ {
+ _socket->disconnectFromHost(); // graceful shutdown of socket, sock_close() will be called once complete
+ return;
+ }
+ // otherwise the socket is in some unknown state, so do a harsh shutdown
+ _socket->abort();
+ _toldDisconnect = true;
+ _server->disconnectClient(this);
+}
+
+void PVSClientConnection::sock_dataArrival()
+{
+ if (_socket == NULL || _socket->state() != QAbstractSocket::ConnectedState)
+ {
+ ConsoleLog writeError("dataArrival called in bad state");
+ return;
+ }
+
+ _lastData = time(NULL);
+ while (_socket->bytesAvailable())
+ {
+ int retval = 0;
+ do
+ {
+ if (_incomplete == NULL) _incomplete = new PVSMsg(); // we need a pvsmsg object
+ retval = _incomplete->readMessage(_socket); // let the message read data from socket
+ if (retval == -1) // error parsing msg, disconnect client!
+ {
+ this->closeConnection();
+ return;
+ }
+ if (retval == 1) // message is complete
+ {
+ _server->handleClientMsg(_id, *_incomplete);
+ delete _incomplete; // ...and delete...
+ _incomplete = NULL; // ...so the next msg can be parsed
+ }
+ } while (retval == 1);
+ }
+}
+
+void PVSClientConnection::sock_closed()
+{
+ // should this be unreliable in some way i suggest using the signal "stateChanged()" instead
+ // and check if the state changed to unconnected.
+ if (_toldDisconnect) return;
+ _toldDisconnect = true;
+ _server->disconnectClient(this);
+}
+
+void PVSClientConnection::sock_error(QAbstractSocket::SocketError errcode)
+{
+ this->closeConnection();
+}
+
+/*
+void PVSClientConnection::push_back_receive(PVSMsg newMsg)
+{
+ _recQueue.push_back(newMsg);
+}
+*/
+
+bool PVSClientConnection::push_back_send(PVSMsg newMsg)
+{
+ if (_socket == NULL || _socket->state() != QAbstractSocket::ConnectedState) return false;
+ newMsg.setSndID(_id);
+ int len;
+ char data[2000];
+ char *tmp = data;
+ if (!newMsg.getBinaryData(tmp, len))
+ {
+ printf("Message empty. Ignored.\n");
+ return false;
+ }
+ QByteArray ba;
+ ba.append(tmp, len);
+ int ret = (int)_socket->write(ba);
+ //printf("Sent %d of %d bytes.\n", ret, len);
+ if (ret == -1)
+ {
+ this->closeConnection();
+ return false;
+ }
+ return true;
+}
+
+QSslSocket* PVSClientConnection::getSocket()
+{
+ return _socket;
+}
+
+void PVSClientConnection::setID(unsigned int id)
+{
+ _id = id;
+ this->push_back_send(PVSMsg(PVSLOGIN, "ID", int2String(_id)));
+}
+
+void PVSClientConnection::ping()
+{
+ // still needs flag/timer to check for a ping timeout (and a reply from the client)
+ this->push_back_send(PVSMsg(PVSCOMMAND, "PING", "HELLO?", _id));
+}
+
+QString PVSClientConnection::getAddress()
+{
+ if (_socket == NULL) return QString();
+ return _socket->peerAddress().toString();
+}
+
+QString PVSClientConnection::getNameUser()
+{
+ return getUserName();
+}
diff --git a/src/net/pvsClientConnection.h b/src/net/pvsClientConnection.h
new file mode 100644
index 0000000..cfbf98e
--- /dev/null
+++ b/src/net/pvsClientConnection.h
@@ -0,0 +1,67 @@
+/**
+ * PVSClientConnection
+ *
+ * holds and maintains a Connection made from/to a PVSServerConnection (or derivate)
+ * PVSClientConnections are created by the PVSListenServer if a PVSCLientConnection is accepted
+ *
+ */
+
+#include "pvsMsg.h"
+
+#include <QtNetwork/QSslSocket>
+
+
+#ifndef _PVSCLIENTCONNECTION_H_
+#define _PVSCLIENTCONNECTION_H_
+
+class PVSListenServer;
+
+class PVSClientConnection : public QObject
+{
+ Q_OBJECT
+
+public:
+ //C'Tor
+ PVSClientConnection(PVSListenServer* server, QSslSocket* sock = NULL);
+ // D'Tor
+ ~PVSClientConnection();
+
+ void closeConnection();
+ bool isConnected()
+ {
+ return _socket != NULL && _socket->state() == QAbstractSocket::ConnectedState;
+ }
+ time_t lastData()
+ {
+ return _lastData;
+ }
+
+ //void push_back_receive(PVSMsg newMsg);
+ bool push_back_send(PVSMsg newMsg);
+ QSslSocket* getSocket();
+
+ int getID() { return _id; }
+ void setID(unsigned int id);
+ void setServerID(unsigned int id) { _serverId = id; }
+
+ QString getAddress();
+ void setUsername(QString username);
+ QString getNameUser();
+ void ping();
+
+private Q_SLOTS:
+ void sock_dataArrival();
+ void sock_closed();
+ void sock_error(QAbstractSocket::SocketError errcode);
+
+private:
+ QSslSocket *_socket;
+ int _id;
+ unsigned int _serverId;
+ PVSMsg *_incomplete;
+ PVSListenServer *_server;
+ bool _toldDisconnect;
+ time_t _lastData;
+};
+
+#endif
diff --git a/src/net/pvsDiscoveredServer.cpp b/src/net/pvsDiscoveredServer.cpp
new file mode 100644
index 0000000..dddb5a0
--- /dev/null
+++ b/src/net/pvsDiscoveredServer.cpp
@@ -0,0 +1,152 @@
+/*
+# Copyright (c) 2009 - OpenSLX Project, Computer Center University of Freiburg
+#
+# This program is free software distributed under the GPL version 2.
+# See http://openslx.org/COPYING
+#
+# If you have any feedback please consult http://openslx.org/feedback and
+# send your suggestions, praise, or complaints to feedback@openslx.org
+#
+# General information about OpenSLX can be found at http://openslx.org/
+# -----------------------------------------------------------------------------
+# src/net/pvsDiscoveredServer.cpp
+# - represents an entry in the list of available servers
+# - handles some extra things like validating the identity of the remote host
+# -----------------------------------------------------------------------------
+*/
+
+#include "pvsDiscoveredServer.h"
+#include "src/util/serviceDiscoveryUtil.h"
+#include <QtNetwork/QSslKey>
+
+PVSDiscoveredServer::PVSDiscoveredServer(QObject* parent, QHostAddress host, int port, QByteArray fingerprint, QString name)
+ : QObject(parent)
+{
+ _validated = false;
+ _socket = NULL;
+ _host = host;
+ _port = port;
+ _fingerprint = fingerprint;
+ _name = name;
+ _lastUpdate = QDateTime::currentDateTime();
+ _lastCheck = QDateTime::fromTime_t(1000000);
+ this->validateCertificate();
+}
+
+PVSDiscoveredServer::~PVSDiscoveredServer() {
+ delete _socket;
+}
+
+void PVSDiscoveredServer::ssl_Error( const QList<QSslError> & errors )
+{
+ for (QList<QSslError>::const_iterator it = errors.begin(); it != errors.end(); it++)
+ {
+ QSslError err = *it;
+ if (err.error() == QSslError::HostNameMismatch) continue; // We don't pay attention to hostnames for validation
+ if (err.error() == QSslError::SelfSignedCertificate) {
+ continue; // Also, this will always be the case; we check the fingerprint later
+ }
+ //ConsoleLog writeNetwork(err.errorString().toUtf8().data());
+ //ConsoleLog writeNetwork("***** SSL ERROR, ABORTING *****");
+ printf("Unhandled SSL Error in SD: %s\n", err.errorString().toUtf8().data());
+ return;
+ }
+ _socket->ignoreSslErrors();
+}
+
+void PVSDiscoveredServer::sock_dataArrival()
+{
+ if (_socket == NULL) return;
+
+ char charbuff[2000];
+ while (_socket->bytesAvailable())
+ {
+ _socket->read(charbuff, 2000);
+ }
+}
+
+void PVSDiscoveredServer::sock_connected()
+{
+ QByteArray cert = _socket->peerCertificate().digest(QCryptographicHash::Sha1);
+ if (_socket->peerCertificate().isNull())
+ {
+ printf("**** WARNING - PEER CERTIFICATE IS NULL ****\n");
+ }
+ else
+ {
+ printf("%s\n", _socket->peerCertificate().subjectInfo(QSslCertificate::Organization).toUtf8().data());
+ printf("%s\n", _socket->peerCertificate().subjectInfo(QSslCertificate::CommonName).toUtf8().data());
+ printf("%s\n", _socket->peerCertificate().subjectInfo(QSslCertificate::LocalityName).toUtf8().data());
+ printf("%s\n", _socket->peerCertificate().subjectInfo(QSslCertificate::OrganizationalUnitName ).toUtf8().data());
+ printf("%s\n", _socket->peerCertificate().subjectInfo(QSslCertificate::CountryName ).toUtf8().data());
+ printf("%s\n", _socket->peerCertificate().subjectInfo(QSslCertificate::StateOrProvinceName ).toUtf8().data());
+ }
+ if (cert == _fingerprint && !_validated)
+ {
+ _validated = true;
+ emit validated(this);
+ printf("Validated certificate of %s :)\n", _socket->peerAddress().toString().toUtf8().data());
+ }
+ else
+ {
+ printf("Certificate of %s is invalid :(\n", _socket->peerAddress().toString().toUtf8().data());
+ QByteArray is, should;
+ is = cert.toBase64();
+ should = _fingerprint.toBase64();
+ printf("Is %s and should be %s\n", is.data(), should.data());
+ }
+ _socket->disconnectFromHost();
+}
+
+void PVSDiscoveredServer::validateCertificate()
+{
+ if (_validated) return; // Nothing to do, this one is legit
+ QDateTime now = QDateTime::currentDateTime();
+ if (_lastCheck.secsTo(now) < 30) return; // Too soon!
+ if (_host.isNull() || _port < 1 || _port > 65535) return; // Invalid
+ if (_socket != NULL) {
+ disconnect(_socket, SIGNAL(connected()), this, SLOT(sock_connected()));
+ disconnect(_socket, SIGNAL(readyRead()), this, SLOT(sock_dataArrival()));
+ disconnect(_socket, SIGNAL(sslErrors(const QList<QSslError> &)),
+ this, SLOT(ssl_Error(const QList<QSslError> &))
+ );
+ _socket->abort();
+ _socket->deleteLater();
+ }
+ _socket = new QSslSocket(this);
+ _socket->setProtocol(QSsl::SslV3);
+ _socket->setPeerVerifyMode(QSslSocket::VerifyPeer);
+ connect(_socket, SIGNAL(encrypted()), this, SLOT(sock_connected()));
+ connect(_socket, SIGNAL(readyRead()), this, SLOT(sock_dataArrival()));
+ connect(_socket, SIGNAL(sslErrors(const QList<QSslError> &)),
+ this, SLOT(ssl_Error(const QList<QSslError> &))
+ );
+ _socket->connectToHostEncrypted(_host.toString(), _port);
+ _lastCheck = now;
+}
+
+bool PVSDiscoveredServer::hasFingerprint(QByteArray &fingerprint)
+{
+ return _fingerprint == fingerprint;
+}
+
+bool PVSDiscoveredServer::hasHost(QHostAddress &host)
+{
+ return _host == host;
+}
+
+void PVSDiscoveredServer::update(int port)
+{
+ _port = port;
+ _lastUpdate = QDateTime::currentDateTime();
+}
+
+int PVSDiscoveredServer::getAge()
+{
+ return _lastUpdate.secsTo(QDateTime::currentDateTime());
+}
+
+QString PVSDiscoveredServer::getName()
+{
+ return _name;
+}
diff --git a/src/net/pvsDiscoveredServer.h b/src/net/pvsDiscoveredServer.h
new file mode 100644
index 0000000..d9f0c01
--- /dev/null
+++ b/src/net/pvsDiscoveredServer.h
@@ -0,0 +1,63 @@
+/*
+# Copyright (c) 2009 - OpenSLX Project, Computer Center University of Freiburg
+#
+# This program is free software distributed under the GPL version 2.
+# See http://openslx.org/COPYING
+#
+# If you have any feedback please consult http://openslx.org/feedback and
+# send your suggestions, praise, or complaints to feedback@openslx.org
+#
+# General information about OpenSLX can be found at http://openslx.org/
+# -----------------------------------------------------------------------------
+# src/net/pvsDiscoveredServer.h
+# - represents an entry in the list of available servers
+# - handles some extra things like validating the identity of the remote host
+# -----------------------------------------------------------------------------
+*/
+
+#ifndef PVSDISCOVEREDSERVER_H_
+#define PVSDISCOVEREDSERVER_H_
+
+#include <QtNetwork/QSslSocket>
+#include <QtNetwork/QHostAddress>
+#include <QtCore/QDateTime>
+
+class PVSDiscoveredServer;
+
+class PVSDiscoveredServer : public QObject {
+ Q_OBJECT
+
+private:
+ QHostAddress _host;
+ int _port;
+ QByteArray _fingerprint;
+ bool _validated;
+ QSslSocket *_socket;
+ QDateTime _lastCheck;
+ QDateTime _lastUpdate;
+ QString _name;
+
+public:
+ PVSDiscoveredServer(QObject* parent, QHostAddress host, int port, QByteArray fingerprint, QString name);
+ virtual ~PVSDiscoveredServer();
+ bool isValid() { return _validated; }
+ bool hasFingerprint(QByteArray &fingerprint);
+ bool hasHost(QHostAddress &host);
+ void update(int port);
+ int getAge();
+ QString getName();
+ QHostAddress getHost() { return _host; }
+ QByteArray getFingerprint() { return _fingerprint; }
+ int getPort() { return _port; }
+ void validateCertificate();
+
+private Q_SLOTS:
+ void ssl_Error( const QList<QSslError> & errors );
+ void sock_dataArrival();
+ void sock_connected();
+
+Q_SIGNALS:
+ void validated(PVSDiscoveredServer*);
+};
+
+#endif /* PVSDISCOVEREDSERVER_H_ */
diff --git a/src/net/pvsListenServer.cpp b/src/net/pvsListenServer.cpp
new file mode 100644
index 0000000..1dac9c0
--- /dev/null
+++ b/src/net/pvsListenServer.cpp
@@ -0,0 +1,308 @@
+/*
+ # Copyright (c) 2009,2010 - OpenSLX Project, Computer Center University of
+ # Freiburg
+ #
+ # This program is free software distributed under the GPL version 2.
+ # See http://openslx.org/COPYING
+ #
+ # If you have any feedback please consult http://openslx.org/feedback and
+ # send your suggestions, praise, or complaints to feedback@openslx.org
+ #
+ # General information about OpenSLX can be found at http://openslx.org/
+ # -----------------------------------------------------------------------------
+ # src/net/pvsListenServer.cpp
+ # - handling of clients (server side)
+ # - accepting new connections etc.
+ # -----------------------------------------------------------------------------
+ */
+
+#include "pvsListenServer.h"
+#include "pvsMsg.h"
+#include "pvsClientConnection.h"
+#include "src/util/consoleLogger.h"
+#include <QtNetwork/QSslSocket>
+#include "SslServer.h"
+#include <cassert>
+//#define verbose
+
+// Create listener
+PVSListenServer::PVSListenServer(int port, int clients)
+{
+ _id = generateID();
+ _listenSocket = NULL;
+ _timer = 0;
+ if (clients < 1)
+ _clientsMax = 100;
+ else
+ _clientsMax = clients;
+ _port = port;
+ init();
+
+}
+
+PVSListenServer::~PVSListenServer()
+{
+ if (_listenSocket != NULL)
+ {
+ disconnect(_listenSocket, SIGNAL(newConnection()), this, SLOT(
+ server_connectionRequest()));
+ _listenSocket->deleteLater();
+ }
+}
+
+PVSClientConnection* PVSListenServer::getConnectionFromId(int id)
+{
+ if (!(_clients.empty()))
+ {
+ // Check for ping timeout
+ for (std::list<PVSClientConnection*>::iterator it = _clients.begin(); it
+ != _clients.end(); it++)
+ {
+ PVSClientConnection *client = *it;
+ if (client)
+ if (client->getID() == id)
+ return client;
+ }
+ }
+ return NULL;
+}
+
+void PVSListenServer::sendToAll(PVSMsg msg)
+{
+ if (!(_clients.empty()))
+ {
+ // Check for ping timeout
+ for (std::list<PVSClientConnection*>::iterator it = _clients.begin(); it
+ != _clients.end(); it++)
+ {
+ PVSClientConnection *client = *it;
+ if (client)
+ client->push_back_send(msg);
+ }
+ }
+}
+
+// listen on a specific port
+bool PVSListenServer::startListen(int port)
+{
+ if (_listenSocket != NULL)
+ {
+ ConsoleLog writeError(
+ QString("Server already listening on port :").append(
+ int2String(_port)));
+ if (shutdown())
+ {
+ ConsoleLog writeError(QString("Server shutdown failed!"));
+ return false;
+ }
+ }
+ _port = port;
+ return init();
+}
+
+// stop listening and free socket descriptor
+bool PVSListenServer::shutdown()
+{
+ if (_timer != 0)
+ killTimer( _timer);
+ _timer = 0;
+ if (_listenSocket != NULL)
+ {
+ disconnect(_listenSocket, SIGNAL(newConnection()), this, SLOT(
+ server_connectionRequest()));
+ _listenSocket->close();
+ _listenSocket->deleteLater();
+ }
+ _listenSocket = NULL;
+ _fresh = true;
+ return false;
+}
+
+// timer event, 5 second interval
+void PVSListenServer::timerEvent(QTimerEvent *event)
+{
+ if (!(_clients.empty()))
+ {
+ // Check for ping timeout
+ time_t refval = time(NULL) - 10;
+ for (std::list<PVSClientConnection*>::iterator it = _clients.begin(); it
+ != _clients.end(); it++)
+ {
+ PVSClientConnection *client = *it;
+ client->ping();
+ if (!client->isConnected())
+ { // disconnected
+ if (disconnectClient(client))
+ break; // list was modified, iterator not valid anymore
+ }
+ if (client->lastData() < refval)
+ { // ping timeout
+ printf("Ping timeout for client %s\n", client->getNameUser().toLocal8Bit().data());
+ if (disconnectClient(client))
+ break; // list was modified, iterator not valid anymore
+ }
+ }
+ }
+}
+
+// remove a client
+bool PVSListenServer::disconnectClient(PVSClientConnection* delinquent)
+{
+ assert(delinquent);
+ delinquent->deleteLater();
+ if (!(_clients.empty()))
+ {
+ for (std::list<PVSClientConnection*>::iterator it = _clients.begin(); it
+ != _clients.end(); it++)
+ {
+ if ((*it) == delinquent)
+ {
+ (*it)->closeConnection();
+ _clients.remove((*it));
+ onClientDisconnected(delinquent);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+// All sorts of events:
+
+void PVSListenServer::onConnectionRemoved(PVSClientConnection* delinquent)
+{
+
+}
+
+void PVSListenServer::onClientConnected(PVSClientConnection* connected)
+{
+ connected->setServerID(_id);
+ connected->setID(generateID());
+}
+
+void PVSListenServer::onClientDisconnected(PVSClientConnection* disconnected)
+{
+ //
+}
+
+// Get client class for a given socket
+PVSClientConnection* PVSListenServer::getConnectionFromSocket(QSslSocket* sock)
+{
+ for (std::list<PVSClientConnection*>::iterator it = _clients.begin(); it
+ != _clients.end(); it++)
+ {
+ if ((*it)->getSocket() == sock) // match!
+ return (*it);
+ }
+ return NULL;
+}
+
+// generate a random (unique) id
+unsigned int PVSListenServer::generateID()
+{
+ int random_integer;
+ do
+ {
+ random_integer = getRandom(0, 0);
+ }
+ while (getConnectionFromID(random_integer));
+
+ return (unsigned int) random_integer;
+}
+
+// Get client class for a given id
+PVSClientConnection* PVSListenServer::getConnectionFromID(int id)
+{
+ for (std::list<PVSClientConnection*>::iterator it = _clients.begin(); it
+ != _clients.end(); it++)
+ {
+ if ((*it)->getID() == id || id == _id)
+ {
+ return (*it);
+ }
+ }
+ return NULL;
+}
+
+// Initialize listening socket
+bool PVSListenServer::init()
+{
+ if (_listenSocket != NULL)
+ shutdown();
+
+ if (_port > 0)
+ {
+ // make a socket, bind it, and listen on it:
+ _listenSocket = new SslServer;
+ QHostAddress addr(QHostAddress::Any);
+ _listenSocket->listen(addr, _port);
+
+ if (!_listenSocket->isListening())
+ {
+ ConsoleLog writeNetwork(
+ QString("Error listening on Port ").append(int2String(
+ _port)));
+ return false;
+ }
+ ConsoleLog writeNetwork(
+ QString("Server is listening. Socket: ").append(int2String(
+ (int) _listenSocket)));
+ connect(_listenSocket, SIGNAL(newConnection()), this, SLOT(
+ server_connectionRequest()));
+
+ _fresh = true;
+ if (_timer != 0)
+ killTimer( _timer);
+ _timer = startTimer(5000);
+ return true;
+ }
+ return false;
+}
+
+void PVSListenServer::server_connectionRequest()
+{
+ //printf("ConnReq\n");
+ if (_listenSocket == NULL)
+ return; // o.O
+ while (_listenSocket->hasPendingConnections())
+ {
+ QSslSocket* sock = (QSslSocket*)_listenSocket->nextPendingConnection();
+ //printf("Got one: %d: %s\n", (int)sock->isEncrypted(), sock->peerAddress().toString().toUtf8().data());
+ if (_clients.size() >= _clientsMax)
+ {
+ sock->abort();
+ sock->deleteLater();
+ continue;
+ }
+ PVSClientConnection* client = new PVSClientConnection(this, sock);
+ _clients.push_back(client); // create new client class and add to list
+ onClientConnected(client); // trigger event
+ _fresh = false;
+ }
+}
+
+void PVSListenServer::handleClientMsg(unsigned int clientID, PVSMsg msg)
+{
+ printf("Got Message for client %ud: [%c][%s][%s]\n", clientID,
+ (char) msg.getType(), msg.getIdent().toUtf8().data(),
+ msg.getMessage().toUtf8().data());
+ msg.setSndID(clientID);
+ if (msg.getType() == PVSCOMMAND)
+ _commandDispatcher.fire(msg.getIdent(), msg);
+ else if (msg.getType() == PVSMESSAGE)
+ _chatDispatcher.fire(msg.getIdent(), msg);
+ else if (msg.getType() == PVSLOGIN)
+ _loginDispatcher.fire(msg.getIdent(), msg);
+ else
+ ConsoleLog
+ writeNetwork(
+ QString(
+ "Could not dispatch Message of unknown Type.\n\t Message was: ").append(
+ msg.getIdent().append(QString(":").append(
+ msg.getMessage()))));
+}
+
+bool PVSListenServer::isListening()
+{
+ return _listenSocket != NULL && _listenSocket->isListening();
+}
diff --git a/src/net/pvsListenServer.h b/src/net/pvsListenServer.h
new file mode 100644
index 0000000..ab021c7
--- /dev/null
+++ b/src/net/pvsListenServer.h
@@ -0,0 +1,106 @@
+#ifndef _PVSLISTENSERVER_H_
+#define _PVSLISTENSERVER_H_
+#include <list>
+#include <src/util/dispatcher.h>
+#include <src/util/consoleLogger.h>
+#include <QtNetwork/QSslSocket>
+//#include <QtNetwork/QTcpServer>
+
+class SslServer;
+
+class PVSClientConnection;
+class PVSMsg;
+
+class PVSListenServer : public QObject
+{
+ Q_OBJECT
+
+private:
+
+ // internal control functions
+
+ std::list<PVSClientConnection*> _clients;
+
+
+ int _numCon;
+ bool _fresh;
+ unsigned int _clientsMax;
+ int _port;
+
+ //QTcpServer *_listenSocket;
+ SslServer *_listenSocket;
+
+ int _id;
+ EventIdentDispatcher<PVSMsg> _loginDispatcher;
+ EventIdentDispatcher<PVSMsg> _commandDispatcher;
+ EventIdentDispatcher<PVSMsg> _chatDispatcher;
+ int _timer;
+
+ // obvious init method is obvious
+ bool init();
+ unsigned int generateID();
+
+protected:
+ void timerEvent(QTimerEvent *event);
+
+public:
+
+
+// typedef void (A::*function)(void);
+ // C'Tor
+ explicit PVSListenServer(int port = 0, int clients = 0);
+ virtual ~PVSListenServer();
+
+ PVSClientConnection* getConnectionFromId(int id);
+ void sendToAll(PVSMsg msg);
+ // control methods
+ bool startListen(int port);
+ bool shutdown();
+ bool isListening();
+ bool disconnectClient(PVSClientConnection* delinquent);
+ void onConnectionRemoved(PVSClientConnection* delinquent);
+
+ std::list<PVSClientConnection*>* getClientListPtr()
+ {
+ return &_clients;
+ }
+ // methods which can/should be overwritten by derivates
+ virtual void onClientConnected(PVSClientConnection* connected); // you can hook up additional services on client connection here
+ virtual void onClientDisconnected(PVSClientConnection* disconnected); // deletes the client, but you can hook up stuff here too
+
+ void handleClientMsg(unsigned int clientID, PVSMsg msg); ///< called by a clientconnection if a msg was received
+
+
+ template<class T> void addLoginHandler(QString ident, T* who, void (T :: *func)(PVSMsg))
+ {
+ printf("Listener got added to LoginHandler\n");
+ _loginDispatcher.addListener(ident, who, func);
+ };
+ template<class T> void removeLoginHandler(QString ident, T* who, void (T :: *func)(PVSMsg))
+ {
+ _loginDispatcher.removeListener(ident, who, func);
+ };
+ template<class T> void addChatHandler(QString ident, T* who, void (T :: *func)(PVSMsg))
+ {
+ _chatDispatcher.addListener(ident, who, func);
+ };
+ template<class T> void removeChatHandler(QString ident, T* who, void (T :: *func)(PVSMsg))
+ {
+ _chatDispatcher.removeListener(ident, who, func);
+ };
+ template<class T> void addCommandHandler(QString ident, T* who, void (T :: *func)(PVSMsg))
+ {
+ _commandDispatcher.addListener(ident, who, func);
+ };
+ template<class T> void removeCommandHandler(QString ident, T* who, void (T :: *func)(PVSMsg))
+ {
+ _commandDispatcher.removeListener(ident, who, func);
+ };
+ PVSClientConnection* getConnectionFromSocket(QSslSocket* sock);
+ PVSClientConnection* getConnectionFromID(int id);
+
+private Q_SLOTS:
+ void server_connectionRequest();
+};
+
+#endif
diff --git a/src/net/pvsLocalhostCommunicator.cpp b/src/net/pvsLocalhostCommunicator.cpp
new file mode 100644
index 0000000..199b39c
--- /dev/null
+++ b/src/net/pvsLocalhostCommunicator.cpp
@@ -0,0 +1,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);
+ printf("Sending %d bytes to daemon...\n", 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)
+ {
+ printf("Error sending PVSMsg to daemon: %s\n", _sock->errorString().toUtf8().data());
+ }
+ else
+ {
+ printf("Sent PVSMsg was incomplete.\n");
+ }
+ stop();
+ }
+ }
+}
diff --git a/src/net/pvsLocalhostCommunicator.h b/src/net/pvsLocalhostCommunicator.h
new file mode 100644
index 0000000..425cc37
--- /dev/null
+++ b/src/net/pvsLocalhostCommunicator.h
@@ -0,0 +1,51 @@
+/// test documentation
+/// whatever
+//! and one more
+
+
+
+#ifndef _PVSLocalhostCommunicator_H_
+#define _PVSLocalhostCommunicator_H_
+#include <src/util/dispatcher.h>
+#include <QtNetwork/QUdpSocket>
+
+
+class PVSMsg;
+
+class PVSLocalhostCommunicator : public QObject
+{
+ Q_OBJECT
+public:
+ PVSLocalhostCommunicator(QString path);
+ void run();
+ bool server()
+ {
+ return _isServer;
+ };
+ bool running()
+ {
+ return _isRunning;
+ };
+ void stop();
+ void sendCommand(QString ident, QString cmd);
+ EventIdentDispatcher<PVSMsg>* getDispatcher()
+ {
+ return &_daemonDispatcher;
+ };
+
+private Q_SLOTS:
+ void sock_dataArrival();
+
+private:
+
+ bool _isServer, _isRunning;
+ QUdpSocket* _sock;
+
+
+
+ EventIdentDispatcher<PVSMsg> _daemonDispatcher; //!< Dispatcher for Daemon Commands
+};
+
+typedef PVSLocalhostCommunicator PVSUDSC;
+
+#endif
diff --git a/src/net/pvsMsg.cpp b/src/net/pvsMsg.cpp
new file mode 100644
index 0000000..b56c979
--- /dev/null
+++ b/src/net/pvsMsg.cpp
@@ -0,0 +1,207 @@
+/*
+ # Copyright (c) 2010 - OpenSLX Project, Computer Center University of Freiburg
+ #
+ # This program is free software distributed under the GPL version 2.
+ # See http://openslx.org/COPYING
+ #
+ # If you have any feedback please consult http://openslx.org/feedback and
+ # send your suggestions, praise, or complaints to feedback@openslx.org
+ #
+ # General information about OpenSLX can be found at http://openslx.org/
+ # -----------------------------------------------------------------------------
+ # src/net/pvsMsg.cpp
+ # - ??? .
+ # -----------------------------------------------------------------------------
+ */
+
+#include "pvsMsg.h"
+#include <cstring>
+#include <QtNetwork/QUdpSocket>
+#include <QtNetwork/QHostAddress>
+
+#ifndef min
+#define min(a,b) (((a)<(b))?(a):(b))
+#endif
+
+static unsigned char PVS_ID = 'P';
+
+// Several constructors for the PVSMsg class...
+PVSMsg::PVSMsg()
+{
+ _msgType = PVSMESSAGE;
+ _buffer = NULL;
+ _buffLen = 0;
+ _buffFill = 0;
+}
+
+PVSMsg::PVSMsg(PVSMsgType type, QString ident, QString msg, int recID)
+{
+ this->_recID = recID;
+
+ if (ident.size())
+ _msgIdent = ident;
+ else
+ _msgIdent = QString("invalid");
+
+ _msgType = type;
+ _msgString = msg;
+ _buffer = NULL;
+ _buffLen = 0;
+ _buffFill = 0;
+}
+
+PVSMsg::PVSMsg(PVSMsg const& copyMe)
+{
+ _msgType = copyMe._msgType;
+ _msgString = copyMe._msgString;
+ _msgIdent = copyMe._msgIdent;
+ _remoteIp = copyMe._remoteIp;
+
+ _buffLen = copyMe._buffLen;
+ _buffFill = copyMe._buffFill;
+ if (_buffLen > 0)
+ {
+ _buffer = new char[_buffLen];
+ memcpy(_buffer, copyMe._buffer, _buffLen);
+ }
+ else
+ _buffer = NULL;
+ _sndID = copyMe._sndID;
+ _recID = copyMe._recID;
+}
+
+// Destructor...
+PVSMsg::~PVSMsg()
+{
+ if (_buffer)
+ delete[] _buffer;
+}
+
+int PVSMsg::readMessage(QAbstractSocket* sock, bool udp)
+{
+ if (_buffFill > 0 && _buffLen <= _buffFill)
+ return 1;
+ qint64 ret = 0;
+ if (_buffFill < 4) // message header is not complete yet
+ {
+ if (_buffer == NULL)
+ {
+ _remoteIp = sock->peerAddress().toString();
+ if (udp)
+ _buffer = new char[1000];
+ else
+ _buffer = new char[4];
+ }
+ // Read as many bytes as needed to complete the 4 byte header
+ if (udp)
+ ret = ((QUdpSocket*)sock)->readDatagram(_buffer, 1000);
+ else
+ ret = sock->read(_buffer + _buffFill, 4 - _buffFill);
+ if (ret == -1) return -1;
+ _buffFill += (int)ret;
+ if (_buffFill == 0)
+ return 0;
+ if (_buffer[0] != PVS_ID)
+ {
+ // check if the id byte is correct
+ // otherwise either the message parsing is broken
+ // or someone is sending garbage
+ return -1;
+ }
+ if (_buffFill >= 4)
+ {
+ // header complete, allocate buffer
+ _buffLen = 4 + (unsigned char)_buffer[2] + (unsigned char)_buffer[3];
+ char *nb = new char[_buffLen + 1]; // +1 for \0
+ memcpy(nb, _buffer, _buffFill);
+ delete[] _buffer;
+ _buffer = nb;
+ }
+ }
+ if (_buffFill >= 4)
+ {
+ // got header, assemble rest of msg
+ if (!udp)
+ {
+ ret = sock->read(_buffer + _buffFill, _buffLen - _buffFill); // read remaining bytes
+ if (ret == -1) return -1;
+ _buffFill += (int)ret;
+ }
+ if (_buffFill >= _buffLen)
+ {
+ // message is complete
+ _buffer[_buffLen] = '\0'; // first, terminate with nullchar
+ _msgString = QString::fromUtf8(_buffer + 4 + (unsigned char)_buffer[2]); // get message
+ _buffer[4 + (unsigned char)_buffer[2]] = '\0';
+ _msgIdent = QString::fromUtf8(_buffer + 4); // get ident
+ _msgType = (PVSMsgType)_buffer[1]; // get msg type
+ return 1;
+ }
+ }
+ return 0;
+}
+
+void PVSMsg::setMessage(QString text)
+{
+ _msgString = text;
+}
+
+void PVSMsg::setIdent(QString ident)
+{
+ _msgIdent = ident;
+}
+
+QString PVSMsg::getMessage()
+{
+ return _msgString;
+}
+
+QString PVSMsg::getIdent()
+{
+ return _msgIdent;
+}
+
+bool PVSMsg::getBinaryData(char*& data, int& dataLen)
+{
+ if (_msgIdent.size() == 0)
+ return false;
+ this->makeSndBuff();
+ data = (char*) _buffer;
+ dataLen = _buffLen;
+ return true;
+}
+
+void PVSMsg::setSndID(int id)
+{
+ _sndID = id;
+}
+
+void PVSMsg::setRecID(int id)
+{
+ _recID = id;
+}
+
+// Create a send buffer with the necessary size
+bool PVSMsg::makeSndBuff()
+{
+ QByteArray uIdent = _msgIdent.toUtf8();
+ QByteArray uString = _msgString.toUtf8();
+ uIdent.truncate(255);
+ uString.truncate(255);
+ _buffLen = 4 + uIdent.size() + uString.size();
+ if (_buffer != NULL)
+ delete[] _buffer;
+ unsigned char *tmpBuffer = new unsigned char[_buffLen + 1];
+
+ tmpBuffer[0] = PVS_ID;
+ tmpBuffer[1] = (unsigned char) _msgType;
+ tmpBuffer[2] = (unsigned char) uIdent.size();
+ tmpBuffer[3] = (unsigned char) uString.size();
+ memcpy(tmpBuffer + 4, uIdent.data(), uIdent.size());
+ memcpy(tmpBuffer + 4 + uIdent.size(), uString.data(), uString.size());
+ //printf("[%c] '%s' - '%s'\n", (char)_msgType, _msgIdent.toUtf8().data(), _msgString.toUtf8().data());
+ tmpBuffer[_buffLen] = '\0';
+ //printf("Binary: '%s'\n", _buffer);
+ _buffer = (char*)tmpBuffer;
+ return true;
+}
diff --git a/src/net/pvsMsg.h b/src/net/pvsMsg.h
new file mode 100644
index 0000000..6fbcd99
--- /dev/null
+++ b/src/net/pvsMsg.h
@@ -0,0 +1,73 @@
+/*
+ * pvsMsg.h
+ *
+ * Created on: 08.01.2010
+ * Author: sr
+ */
+
+#ifndef PVSMSG_H_
+#define PVSMSG_H_
+
+
+#include <QtCore/QString>
+
+enum PVSMsgType
+{
+ PVSCOMMAND = 'C',
+ PVSMESSAGE = 'M',
+ PVSLOGIN = 'L',
+ PVSDAEMON = 'D',
+ PVSUNKNOWN = 'U'
+};
+
+class PVSServerConnection;
+class PVSListenServer;
+class PVSClientConnection;
+class QAbstractSocket;
+
+class PVSMsg
+{
+public:
+ friend class PVSServerConnection;
+ friend class PVSListenServer;
+ friend class PVSClientConnection;
+
+ PVSMsg();
+ PVSMsg(PVSMsgType type, QString _ident, QString msg, int recID = 0);
+ PVSMsg(PVSMsg const& copyMe);
+ ~PVSMsg();
+
+ int readMessage(QAbstractSocket* sock, bool udp = false); ///< -1 = error, 0 = incomplete, 1 = complete
+ unsigned int getLength()
+ {
+ return _msgString.size();
+ };
+ void setIdent(QString ident);
+ QString getIdent();
+ void setMessage(QString text);
+ QString getMessage();
+ PVSMsgType getType() { return _msgType; }
+ bool getBinaryData(char*& data, int& dataLen); ///< get binary representation of this PVSmsg
+
+ unsigned int getRecID() { return _recID; }
+ int getSndID() { return _sndID; }
+ QString getRemoteIp() { return _remoteIp; }
+ bool isMsgComplete() { return _buffFill > 0 && _buffFill == _buffLen; }
+
+private:
+ void setSndID(int id);
+ void setRecID(int id);
+ bool makeSndBuff();
+ PVSMsgType _msgType; ///< type of message (command, message, login, daemon)
+ QString _msgIdent; ///< message ident
+ QString _msgString; ///< message string
+ char *_buffer; ///< receive buffer
+ int _buffLen; ///< size of complete message in bytes
+ int _buffFill; ///< actual number of bytes in buffer
+
+ int _sndID;
+ int _recID;
+ QString _remoteIp;
+};
+
+#endif /* PVSMSG_H_ */
diff --git a/src/net/pvsServerConnection.cpp b/src/net/pvsServerConnection.cpp
new file mode 100644
index 0000000..04a1ef6
--- /dev/null
+++ b/src/net/pvsServerConnection.cpp
@@ -0,0 +1,243 @@
+#include "pvsServerConnection.h"
+#include "src/util/consoleLogger.h"
+#include "src/util/util.h"
+#include "pvsMsg.h"
+#include "src/pvs.h"
+#include <QtNetwork/QHostAddress>
+#include "src/core/pvsChatClient.h"
+#include "src/util/serviceDiscoveryUtil.h"
+#include "src/net/pvsDiscoveredServer.h"
+//#define verbose
+
+PVSServerConnection::PVSServerConnection(PVS *parent) : QObject(parent)
+{
+ _client = parent;
+ _incomplete = NULL;
+ _socket = NULL;
+ _timerId = 0;
+ _timer = 0;
+ _wasConnected = false;
+ loadCommands();
+}
+
+inline void PVSServerConnection::timerStop()
+{
+ if (_timer == 0) return;
+ killTimer(_timer);
+ _timer = 0;
+}
+
+bool PVSServerConnection::connectToServer(PVSDiscoveredServer* server, QString passwd)
+{
+ QHostAddress host = server->getHost();
+ if (_socket != NULL && _socket->state() == QAbstractSocket::ConnectedState
+ && _socket->peerAddress() == host) return false;
+ int port = server->getPort();
+ if (port < 1 || port > 65535) port = SERVER_PORT_INT;
+ ConsoleLog writeNetwork("Connecting to host:");
+ ConsoleLog writeNetwork(host.toString().toUtf8().data());
+ timerStop();
+ if (_socket != NULL)
+ {
+ _socket->blockSignals(true);
+ _socket->abort();
+ _socket->deleteLater();
+ }
+ _name = server->getName();
+ _expectedFingerprint = server->getFingerprint();
+ _passwd = passwd;
+ _socket = new QSslSocket(this);
+ connect(_socket, SIGNAL(encrypted()), this, SLOT(sock_connected()));
+ connect(_socket, SIGNAL(readyRead()), this, SLOT(sock_dataArrival()));
+ connect(_socket, SIGNAL(disconnected()), this, SLOT(sock_closed()));
+ connect(_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(sock_error(QAbstractSocket::SocketError)));
+ char tex[2000];
+ snprintf(tex, 2000, "Connecting to %s on port %d", host.toString().toUtf8().data(), (int)port);
+ ConsoleLog writeNetwork(tex);
+ connect(_socket,
+ SIGNAL(sslErrors(const QList<QSslError> &)),
+ this,
+ SLOT(sslErrors(const QList<QSslError> &))
+ );
+ _socket->connectToHostEncrypted(host.toString(), port);
+ if (_timer == 0) _timer = startTimer(10000);
+
+ return true; // we really don't know yet if it will succeed since its async
+}
+
+void PVSServerConnection::sslErrors ( const QList<QSslError> & errors )
+{
+ for (QList<QSslError>::const_iterator it = errors.begin(); it != errors.end(); it++)
+ {
+ QSslError err = *it;
+ printf("Connect SSL: %s\n", err.errorString().toUtf8().data());
+ if (err.error() == QSslError::HostNameMismatch) continue; // We don't pay attention to hostnames for validation
+ if (err.error() == QSslError::SelfSignedCertificate) continue; // Also, this will always be the case; we check the fingerprint later
+ ConsoleLog writeNetwork(err.errorString().toUtf8().data());
+ ConsoleLog writeNetwork("***** SSL ERROR, ABORTING *****");
+ return;
+ }
+ _socket->ignoreSslErrors();
+}
+
+void PVSServerConnection::disconnectFromServer()
+{
+ if (_socket == NULL) return;
+ _socket->disconnectFromHost();
+ handleDisconnectInternal();
+}
+
+void PVSServerConnection::timerEvent(QTimerEvent *event)
+{
+ if (_socket != NULL && _socket->state() == QAbstractSocket::ConnectedState) return;
+ // TODO: Check for ping timeout
+}
+
+void PVSServerConnection::sendMessage(PVSMsg newMessage)
+{
+ if (_socket == NULL || _socket->state() != QAbstractSocket::ConnectedState) return;
+ char *data;
+ int len;
+ newMessage.getBinaryData(data, len);
+ QByteArray qba(data, len);
+ _socket->write(qba);
+}
+
+void PVSServerConnection::ping()
+{
+ sendMessage(PVSMsg(PVSCOMMAND, "PING", "U THERE?"));;
+}
+
+QString PVSServerConnection::getServerName()
+{
+ if (!isConnected()) return QString();
+ return _name;
+}
+
+void PVSServerConnection::loadCommands()
+{
+ addLoginHandler("ID", this, &PVSServerConnection::onID);
+ addCommandHandler("PING", this, &PVSServerConnection::onPing);
+}
+
+void PVSServerConnection::onID(PVSMsg idmsg)
+{
+ _id = (unsigned int)string2Int(idmsg.getMessage());
+}
+
+void PVSServerConnection::onPing(PVSMsg pingmsg)
+{
+ if (pingmsg.getMessage().at(pingmsg.getMessage().size()-1) == '?')
+ {
+ sendMessage(PVSMsg(PVSCOMMAND, "PING", "HI!"));
+ }
+}
+
+void PVSServerConnection::handleClientMsg(PVSMsg receiver)
+{
+ // FIXME: @SimonR, this line cuase problems with pvs in daemon mode and dbus
+ //qDebug("Got Message for this client: [%c][%s][%s]\n", (char)receiver.getType(), receiver.getIdent().toUtf8().data(), receiver.getMessage().toUtf8().data());
+ if (receiver.getType() == PVSCOMMAND)
+ {
+ _commandDispatcher.fire(receiver.getIdent(), receiver);
+// ConsoleLog writeNetwork(QString("Received a command and handled it.").append(receiver.getIdent().append(QString(":").append(receiver.getMessage()))));
+ }
+ else if (receiver.getType() == PVSMESSAGE)
+ {
+ _chatDispatcher.fire(receiver.getIdent(), receiver);
+ ConsoleLog writeNetwork(QString("Received a chat message and handled it.").append(receiver.getIdent().append(QString(":").append(receiver.getMessage()))));
+ }
+ else if (receiver.getType() == PVSLOGIN)
+ {
+ _loginDispatcher.fire(receiver.getIdent(), receiver);
+// ConsoleLog writeNetwork(QString("Received a login and handled it. Ident: ").append(receiver.getIdent().append(QString(":")).append(receiver.getMessage())));
+ }
+ else if (receiver.getType() == PVSUNKNOWN)
+ {
+ ConsoleLog writeNetwork(QString("Received an unknown type. Ident : ").append(receiver.getIdent().append(QString(" : ").append(receiver.getMessage()))));
+ }
+}
+
+void PVSServerConnection::sock_dataArrival()
+{
+ if (_socket == NULL || _socket->state() != QAbstractSocket::ConnectedState)
+ {
+ ConsoleLog writeError("dataArrival called in bad state");
+ return;
+ }
+
+ while (_socket->bytesAvailable())
+ {
+ int retval = 0;
+ do
+ {
+ if (_incomplete == NULL) _incomplete = new PVSMsg(); // we need a pvsmsg object
+ retval = _incomplete->readMessage(_socket); // let the message read data from socket
+ if (retval == -1) // error parsing msg, disconnect client!
+ {
+ this->disconnectFromServer();
+ return;
+ }
+ if (retval == 1) // message is complete
+ {
+ this->handleClientMsg(*_incomplete);
+ delete _incomplete; // ...and delete...
+ _incomplete = NULL; // ...so the next msg can be parsed
+ }
+ } while (retval == 1);
+ }
+}
+
+void PVSServerConnection::sock_closed()
+{
+ // should this be unreliable in some way i suggest using the signal "stateChanged()" instead
+ // and check if the state changed to unconnected.
+ ConsoleLog writeNetwork("Socket was closed... oh well..");
+ handleDisconnectInternal();
+}
+
+void PVSServerConnection::sock_error(QAbstractSocket::SocketError errcode)
+{
+ char txt[204];
+ snprintf(txt, 200, "Connection error: %d", (int)errcode);
+ ConsoleLog writeNetwork(txt);
+ handleDisconnectInternal();
+}
+
+// Send to server username and loginname.
+void PVSServerConnection::sock_connected()
+{
+ QByteArray cert = _socket->peerCertificate().digest(QCryptographicHash::Sha1);
+ if (_expectedFingerprint != cert)
+ { // Nich mit mir, Freundchen!
+ disconnectFromServer();
+ // Maybe you want to inform the user that there was a certificate mismatch
+ // and that it is very possible that the CIA is trying to eavesdrop on the connection
+ return;
+ }
+ ConsoleLog writeNetwork("Connected!");
+ _wasConnected = true;
+ sendMessage(
+ PVSMsg(PVSLOGIN, "USERNAME", getFullUsername()+","+getenv("USER")));
+ sendMessage(
+ PVSMsg(PVSLOGIN, "PASSWORD", _passwd));
+ ConsoleLog writeNetwork("Sent Username and password.");
+
+ _client->onConnected(_name);
+}
+
+void PVSServerConnection::handleDisconnectInternal()
+{
+ _socket->blockSignals(true);
+ _socket->abort();
+ _socket->deleteLater();
+ _socket = NULL;
+ _name = QString();
+ _client->securityUnlock();
+ timerStop();
+ if (_wasConnected)
+ {
+ _wasConnected = false;
+ _client->onDisconnected();
+ }
+}
diff --git a/src/net/pvsServerConnection.h b/src/net/pvsServerConnection.h
new file mode 100644
index 0000000..0669d88
--- /dev/null
+++ b/src/net/pvsServerConnection.h
@@ -0,0 +1,99 @@
+/**
+ * PVSServerConnection
+ *
+ * holds and maintains a Connection to a PVSListenServer (or derivate)
+ *
+ */
+
+
+
+#ifndef _PVSSERVERCONNECTION_H_
+#define _PVSSERVERCONNECTION_H_
+
+#include "src/util/dispatcher.h"
+#include <QtNetwork/QSslSocket>
+
+class PVSMsg;
+class PVS;
+class PVSDiscoveredServer;
+
+class PVSServerConnection : public QObject
+{
+ Q_OBJECT
+public:
+ PVSServerConnection(PVS *parent);
+ ~PVSServerConnection() {}
+ bool connectToServer(PVSDiscoveredServer* server, QString passwd = QString());
+ void disconnectFromServer();
+ bool isConnected()
+ {
+ return _socket != NULL && _socket->state() == QAbstractSocket::ConnectedState;
+ }
+
+ void sendMessage(PVSMsg newMessage);
+
+ void ping();
+ QString getServerName();
+
+ virtual void loadCommands();
+ void onID(PVSMsg idmsg);
+ void onPing(PVSMsg pingmsg);
+ template<class T> void addLoginHandler(QString ident, T* who, void (T :: *func)(PVSMsg))
+ {
+ _loginDispatcher.addListener(ident, who, func);
+ };
+ template<class T> void removeLoginHandler(QString ident, T* who, void (T :: *func)(PVSMsg))
+ {
+ _loginDispatcher.removeListener(ident, who, func);
+ };
+ template<class T> void addChatHandler(QString ident, T* who, void (T :: *func)(PVSMsg))
+ {
+ _chatDispatcher.addListener(ident, who, func);
+ };
+ template<class T> void removeChatHandler(QString ident, T* who, void (T :: *func)(PVSMsg))
+ {
+ _chatDispatcher.removeListener(ident, who, func);
+ };
+ template<class T> void addCommandHandler(QString ident, T* who, void (T :: *func)(PVSMsg))
+ {
+ _commandDispatcher.addListener(ident, who, func);
+ };
+ template<class T> void removeCommandHandler(QString ident, T* who, void (T :: *func)(PVSMsg))
+ {
+ _commandDispatcher.removeListener(ident, who, func);
+ };
+
+protected:
+ void timerEvent(QTimerEvent *event);
+
+private Q_SLOTS:
+ void sslErrors(const QList<QSslError> & errors); // triggered for errors that occur during SSL negotiation
+ void sock_dataArrival(); // triggered if data is available for reading
+ void sock_closed(); // triggered if the socket is closed
+ void sock_error(QAbstractSocket::SocketError errcode); // triggered if an error occurs on the socket
+ void sock_connected(); // triggered if the connection is established and ready to use
+
+private:
+
+ inline void timerStop();
+ void handleClientMsg(PVSMsg receiver);
+ void handleDisconnectInternal();
+
+ EventIdentDispatcher<PVSMsg> _commandDispatcher;
+ EventIdentDispatcher<PVSMsg> _chatDispatcher;
+ EventIdentDispatcher<PVSMsg> _loginDispatcher;
+ PVSMsg *_incomplete;
+ QSslSocket *_socket;
+ unsigned int _id;
+ int _timerId;
+ //QString _host;
+ //quint16 _port;
+ int _timer;
+ PVS *_client;
+ bool _wasConnected;
+ QByteArray _expectedFingerprint;
+ QString _name;
+ QString _passwd;
+};
+
+#endif
diff --git a/src/net/pvsServiceBroadcast.cpp b/src/net/pvsServiceBroadcast.cpp
new file mode 100644
index 0000000..cf15b5b
--- /dev/null
+++ b/src/net/pvsServiceBroadcast.cpp
@@ -0,0 +1,51 @@
+/*
+# Copyright (c) 2009 - OpenSLX Project, Computer Center University of Freiburg
+#
+# This program is free software distributed under the GPL version 2.
+# See http://openslx.org/COPYING
+#
+# If you have any feedback please consult http://openslx.org/feedback and
+# send your suggestions, praise, or complaints to feedback@openslx.org
+#
+# General information about OpenSLX can be found at http://openslx.org/
+# -----------------------------------------------------------------------------
+# src/net/pvsServiceBroadcast.cpp
+# - broadcast sessionname
+# -----------------------------------------------------------------------------
+*/
+/********** COMPILE-TIME SETTINGS ***************/
+
+#include "pvsServiceBroadcast.h"
+#include "src/setup.h"
+#include <cassert>
+#include "src/util/serviceDiscoveryUtil.h"
+
+PVSServiceBroadcast::PVSServiceBroadcast()
+{
+ _announce = NULL;
+ _timer = 0;
+ _broadcaster.bind(SD_PORT_CONSOLE);
+ _everyone = QHostAddress(QHostAddress::Broadcast);
+}
+
+PVSServiceBroadcast::~PVSServiceBroadcast()
+{
+ if (_announce != NULL) delete _announce;
+ if (_timer != 0) this->killTimer(_timer);
+}
+
+void PVSServiceBroadcast::setFingerprint(QByteArray sha1)
+{
+ if (_announce != NULL) _announce->clear();
+ else _announce = new QByteArray();
+ appendSdField(_announce, "hsh", QString(sha1.toBase64()));
+ appendSdField(_announce, "prt", SERVER_PORT); // TODO: maybe this has to come from somewhere else if configurable
+ appendSdField(_announce, "aut", "SHA1");
+ if (_timer == 0) _timer = this->startTimer(SB_INTERVAL * 1000);
+}
+
+void PVSServiceBroadcast::timerEvent(QTimerEvent *event)
+{
+ if (_announce == NULL) return;
+ _broadcaster.writeDatagram(*_announce, _everyone, SD_PORT_CLIENT);
+}
diff --git a/src/net/pvsServiceBroadcast.h b/src/net/pvsServiceBroadcast.h
new file mode 100644
index 0000000..cf3f63d
--- /dev/null
+++ b/src/net/pvsServiceBroadcast.h
@@ -0,0 +1,46 @@
+/*
+# Copyright (c) 2009 - OpenSLX Project, Computer Center University of Freiburg
+#
+# This program is free software distributed under the GPL version 2.
+# See http://openslx.org/COPYING
+#
+# If you have any feedback please consult http://openslx.org/feedback and
+# send your suggestions, praise, or complaints to feedback@openslx.org
+#
+# General information about OpenSLX can be found at http://openslx.org/
+# -----------------------------------------------------------------------------
+# src/net/pvsServiceBroadcast.cpp
+# - broadcast sessionname, port, auth/encryption
+# -----------------------------------------------------------------------------
+*/
+
+#ifndef PVSSERVICEBROADCAST_H_
+#define PVSSERVICEBROADCAST_H_
+
+#include <QtCore/QString>
+#include <QtCore/QObject>
+#include <QtNetwork/QUdpSocket>
+#include "src/net/pvsMsg.h"
+
+class PVSMsg;
+
+class PVSServiceBroadcast : public QObject
+{
+ Q_OBJECT
+
+public:
+ PVSServiceBroadcast();
+ virtual ~PVSServiceBroadcast();
+ void setFingerprint(QByteArray sha1);
+
+protected:
+ void timerEvent(QTimerEvent *event);
+
+private:
+ QByteArray *_announce;
+ QUdpSocket _broadcaster;
+ QHostAddress _everyone;
+ int _timer;
+};
+
+#endif /* PVSSERVICEBROADCAST_H_ */
diff --git a/src/net/pvsServiceDiscovery.cpp b/src/net/pvsServiceDiscovery.cpp
new file mode 100644
index 0000000..0a99802
--- /dev/null
+++ b/src/net/pvsServiceDiscovery.cpp
@@ -0,0 +1,181 @@
+/*
+# Copyright (c) 2009 - OpenSLX Project, Computer Center University of Freiburg
+#
+# This program is free software distributed under the GPL version 2.
+# See http://openslx.org/COPYING
+#
+# If you have any feedback please consult http://openslx.org/feedback and
+# send your suggestions, praise, or complaints to feedback@openslx.org
+#
+# General information about OpenSLX can be found at http://openslx.org/
+# -----------------------------------------------------------------------------
+# src/net/pvsServiceDiscovery.cpp
+# - handle console broadcasts, tell client to connect on match
+# -----------------------------------------------------------------------------
+*/
+
+#include <QtCore/QHash>
+#include "src/pvs.h"
+#include "pvsServiceDiscovery.h"
+#include "pvsDiscoveredServer.h"
+#include "src/setup.h"
+#include "src/util/serviceDiscoveryUtil.h"
+#include <cassert>
+
+
+
+PVSServiceDiscovery::PVSServiceDiscovery(PVS* client)
+{
+ assert(client);
+ bool ret = _sock.bind(SD_PORT_CLIENT);
+ if (!ret)
+ {
+ printf("Could not open SERVICE DISCOVERY port\n");
+ exit(1);
+ }
+ connect(&_sock, SIGNAL(readyRead()), this, SLOT(sock_dataArrival()));
+ _currentServer = 0;
+ _last = QDateTime::currentDateTime();
+ _client = client;
+ _timerId = startTimer(10000);
+}
+
+PVSServiceDiscovery::~PVSServiceDiscovery()
+{
+ killTimer(_timerId);
+}
+
+void PVSServiceDiscovery::connectToSession(QString name, QString passwd)
+{
+ _sessionName = name;
+ _sessionPasswd = passwd;
+ if (name.length() == 0) return;
+ for (tServerList::iterator it = _servers.begin(); it != _servers.end(); it++)
+ {
+ PVSDiscoveredServer *ds = *it;
+ if (ds->isValid() && ds->getName() == name)
+ {
+ _client->connectToHost(ds, _sessionPasswd);
+ }
+ }
+}
+
+void PVSServiceDiscovery::sock_dataArrival()
+{
+ int len;
+ while ((len = _sock.pendingDatagramSize()) > -1)
+ {
+ if (len == 0) continue;
+ char *data = new char[len];
+ QHostAddress host;
+ len = _sock.readDatagram(data, len, &host);
+ SdFields fields = parseSdFields((unsigned char*)data, len);
+ QDateTime now = QDateTime::currentDateTime();
+ if (fields.contains("hsh") && fields.contains("prt") && fields.contains("aut"))
+ {
+ if (fields["aut"] == "SHA1")
+ {
+ this->handleDiscovery(
+ host,
+ atoi(fields["prt"].toUtf8().data()),
+ QByteArray::fromBase64(fields["hsh"].toAscii())
+ );
+ }
+ }
+ /*
+ // DEBUG ONLY: connect to any host without matching the session name
+ if (_last.secsTo(now) > 9 && fields.contains("prt"))
+ {
+ _last = now;
+ int port = atoi(fields["prt"].toUtf8().data());
+ _client->connectToHost(host, QByteArray(), port);
+ }
+ // ^^^^^^^^^^
+ */
+ }
+}
+
+void PVSServiceDiscovery::handleDiscovery(QHostAddress host, int port, QByteArray hash)
+{
+ int numhosts = 0; ///< while iterating we count how many entries have the same host
+ for (tServerList::iterator it = _servers.begin(); it != _servers.end(); it++)
+ {
+ if ((**it).hasHost(host))
+ {
+ ConsoleLog writeNetwork(host.toString() + " == " + (**it).getHost().toString());
+ if (++numhosts >= 5) return; // ddos through faked service broadcasts? ignore...
+ if ((**it).hasFingerprint(hash) && (**it).getPort() == port) // known entry...
+ {
+ if ((*it)->isValid() && (*it)->getName() == _sessionName && _sessionName.length() > 0)
+ {
+ ConsoleLog writeNetwork(QString("Connecting to ").append(_sessionName));
+ _client->connectToHost((*it), _sessionPasswd);
+ }
+ (**it).update(port);
+ return;
+ }
+ }
+ }
+ if (_servers.length() >= 30) return; // !?
+ QString oname = sha1ToReadable(hash);
+ QString name = oname;
+ int dup = 0;
+ while (nameExists(name))
+ {
+ name = "(" + QString::number(++dup) + ") " + oname;
+ }
+ PVSDiscoveredServer *ds = new PVSDiscoveredServer(this, host, port, hash, name);
+ connect(ds, SIGNAL(validated(PVSDiscoveredServer*)), this, SLOT(sendServerToGui(PVSDiscoveredServer*)));
+ _servers.push_back(ds);
+ setTimerInterval();
+}
+
+bool PVSServiceDiscovery::nameExists(QString name)
+{
+ for (tServerList::iterator it = _servers.begin(); it != _servers.end(); it++)
+ {
+ if ((**it).getName() == name) return true;
+ }
+ return false;
+}
+
+QStringList PVSServiceDiscovery::getAllServers()
+{
+ QStringList hosts;
+ for (tServerList::iterator it = _servers.begin(); it != _servers.end(); it++)
+ {
+ if ((**it).isValid()) hosts.append((**it).getName());
+ }
+ return hosts;
+}
+
+void PVSServiceDiscovery::sendServerToGui(PVSDiscoveredServer* ds)
+{
+ _client->guiAddHost(ds->getName());
+}
+
+void PVSServiceDiscovery::timerEvent(QTimerEvent *event)
+{
+ if (_servers.size() == 0) return;
+ if (_currentServer >= _servers.size()) _currentServer = 0;
+ PVSDiscoveredServer *ds = _servers.at(_currentServer);
+ if (ds->getAge() >= SB_INTERVAL*2 + 1) // Entry too old?
+ {
+ disconnect(ds, SIGNAL(validated(PVSDiscoveredServer*)), this, SLOT(sendServerToGui(PVSDiscoveredServer*)));
+ _client->guiDelHost(ds->getName());
+ delete ds;
+ _servers.removeAt(_currentServer); // Clean it up
+ setTimerInterval();
+ }
+ else
+ {
+ ds->validateCertificate();
+ }
+ ++_currentServer;
+}
+
+void PVSServiceDiscovery::setTimerInterval()
+{
+ killTimer(_timerId);
+ _timerId = startTimer(10000 / (_servers.size() + 1));
+}
diff --git a/src/net/pvsServiceDiscovery.h b/src/net/pvsServiceDiscovery.h
new file mode 100644
index 0000000..08a38b8
--- /dev/null
+++ b/src/net/pvsServiceDiscovery.h
@@ -0,0 +1,57 @@
+/*
+# Copyright (c) 2009 - OpenSLX Project, Computer Center University of Freiburg
+#
+# This program is free software distributed under the GPL version 2.
+# See http://openslx.org/COPYING
+#
+# If you have any feedback please consult http://openslx.org/feedback and
+# send your suggestions, praise, or complaints to feedback@openslx.org
+#
+# General information about OpenSLX can be found at http://openslx.org/
+# -----------------------------------------------------------------------------
+# src/net/pvsServiceDiscovery.cpp
+# - handle console broadcasts, tell client to connect on match
+# -----------------------------------------------------------------------------
+*/
+
+#ifndef PVSSERVICEDISCOVERY_H_
+#define PVSSERVICEDISCOVERY_H_
+
+#include <QtNetwork/QUdpSocket>
+#include <QtCore/QDateTime>
+
+class PVS;
+class PVSDiscoveredServer;
+typedef QList<PVSDiscoveredServer*> tServerList;
+
+class PVSServiceDiscovery : public QObject
+{
+ Q_OBJECT
+public:
+ PVSServiceDiscovery(PVS* client);
+ virtual ~PVSServiceDiscovery();
+ void connectToSession(QString name, QString passwd);
+ bool nameExists(QString name);
+ QStringList getAllServers();
+
+protected:
+ void timerEvent(QTimerEvent *event);
+
+private Q_SLOTS:
+ void sock_dataArrival();
+ void sendServerToGui(PVSDiscoveredServer*);
+
+private:
+ void handleDiscovery(QHostAddress host, int port, QByteArray hash);
+ void setTimerInterval();
+ QUdpSocket _sock;
+ QString _sessionName;
+ QString _sessionPasswd;
+ PVS *_client;
+ QDateTime _last; ///< to protect us from being abused as a ddos zombie
+ tServerList _servers;
+ int _currentServer;
+ int _timerId;
+};
+
+#endif /* PVSSERVICEDISCOVERY_H_ */