summaryrefslogtreecommitdiffstats
path: root/src/server
diff options
context:
space:
mode:
authorsr2013-02-04 19:50:31 +0100
committersr2013-02-04 19:50:31 +0100
commit1a5709501f94014d41987b956338bb6424b9f90c (patch)
treed3b93fe8dc406bca56aff147ef5cc4cbf9ed6be0 /src/server
parentTest (diff)
downloadpvs2-1a5709501f94014d41987b956338bb6424b9f90c.tar.gz
pvs2-1a5709501f94014d41987b956338bb6424b9f90c.tar.xz
pvs2-1a5709501f94014d41987b956338bb6424b9f90c.zip
Initial commit
Diffstat (limited to 'src/server')
-rw-r--r--src/server/clicklabel/clicklabel.cpp14
-rw-r--r--src/server/clicklabel/clicklabel.h25
-rw-r--r--src/server/connectionframe/connectionframe.cpp278
-rw-r--r--src/server/connectionframe/connectionframe.h77
-rw-r--r--src/server/main.cpp41
-rw-r--r--src/server/mainwindow/mainwindow.cpp633
-rw-r--r--src/server/mainwindow/mainwindow.h76
-rw-r--r--src/server/net/certmanager.cpp92
-rw-r--r--src/server/net/certmanager.h29
-rw-r--r--src/server/net/client.cpp288
-rw-r--r--src/server/net/client.h104
-rw-r--r--src/server/net/discoverylistener.cpp165
-rw-r--r--src/server/net/discoverylistener.h40
-rw-r--r--src/server/net/listenserver.cpp40
-rw-r--r--src/server/net/listenserver.h30
-rw-r--r--src/server/net/sslserver.cpp113
-rw-r--r--src/server/net/sslserver.h50
-rw-r--r--src/server/sessionnamewindow/sessionnamewindow.cpp68
-rw-r--r--src/server/sessionnamewindow/sessionnamewindow.h38
-rw-r--r--src/server/util/global.cpp17
-rw-r--r--src/server/util/global.h29
-rw-r--r--src/server/util/util.cpp14
-rw-r--r--src/server/util/util.h17
23 files changed, 2278 insertions, 0 deletions
diff --git a/src/server/clicklabel/clicklabel.cpp b/src/server/clicklabel/clicklabel.cpp
new file mode 100644
index 0000000..2989542
--- /dev/null
+++ b/src/server/clicklabel/clicklabel.cpp
@@ -0,0 +1,14 @@
+#include "clicklabel.h"
+
+ClickLabel::ClickLabel(QWidget *parent) : QLabel(parent)
+{
+ QFont f(this->font());
+ f.setPixelSize(20);
+ this->setFont(f);
+ this->setMaximumHeight(22);
+}
+
+void ClickLabel::mouseReleaseEvent(QMouseEvent* e)
+{
+ emit clicked();
+}
diff --git a/src/server/clicklabel/clicklabel.h b/src/server/clicklabel/clicklabel.h
new file mode 100644
index 0000000..6a05152
--- /dev/null
+++ b/src/server/clicklabel/clicklabel.h
@@ -0,0 +1,25 @@
+#ifndef _CLICKLABEL_H_
+#define _CLICKLABEL_H_
+
+#include <QtGui>
+#include <QLabel>
+
+
+class ClickLabel : public QLabel
+{
+ Q_OBJECT
+
+public:
+ ClickLabel(QWidget *parent);
+
+protected:
+ void mouseReleaseEvent(QMouseEvent* e);
+
+
+signals:
+ void clicked();
+
+};
+
+
+#endif
diff --git a/src/server/connectionframe/connectionframe.cpp b/src/server/connectionframe/connectionframe.cpp
new file mode 100644
index 0000000..1544c76
--- /dev/null
+++ b/src/server/connectionframe/connectionframe.cpp
@@ -0,0 +1,278 @@
+/*
+# 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/gui/connectionFrame.cpp
+# -----------------------------------------------------------------------------
+*/
+
+
+#include "connectionframe.h"
+#include "../net/client.h"
+#include <QPixmap>
+#include <QImage>
+#include <cassert>
+
+static QIcon *term = NULL, *cam = NULL, *eye = NULL;
+
+static QString backgroundStyle("background-color: %1; margin: 1px; border: 1px solid black; border-radius: 6px");
+
+ConnectionFrame::ConnectionFrame(QWidget *parent, int width, int height) :
+ QGroupBox(parent), _client(NULL), _timerId(0), _timerCounter(0), _selected(false), _isTutor(false)
+{
+
+ //defines the ui-stuff
+ // load icons first
+ if (term == NULL)
+ {
+ term = new QIcon(":terminal");
+ cam = new QIcon(":cam32");
+ eye = new QIcon(":eye");
+ }
+
+ //this->setAttribute(Qt::WA_OpaquePaintEvent);
+
+ _mainLayout = new QBoxLayout(QBoxLayout::TopToBottom, this);
+ _mainLayout->setSpacing(1);
+ _mainLayout->setMargin(3);
+ _mainLayout->setAlignment(Qt::AlignHCenter);
+
+ _iconLayout = new QBoxLayout(QBoxLayout::RightToLeft, NULL);
+ _iconLayout->setSpacing(1);
+ _iconLayout->setMargin(3);
+
+ _lblUserName = new QLabel("Test", this);
+ _lblUserName->setStyleSheet(QString::fromUtf8("background-color: white; color: black;"));
+ _lblUserName->setAlignment(Qt::AlignHCenter);
+ //_lblUsername->resize(_lblUsername->width(), _lblUsername->font().pixelSize());
+
+ _lblHostName = new QLabel("PC", this);
+ _lblHostName->setStyleSheet(QString::fromUtf8("background-color: white; color: black;"));
+ _lblHostName->setAlignment(Qt::AlignHCenter);
+
+ _icoCam = addIcon(cam);
+ _icoEye = addIcon(eye);
+
+ _iconLayout->addWidget(_icoCam);
+ _iconLayout->addWidget(_icoEye);
+ _iconLayout->addStretch();
+
+ //_layout->addWidget(_imgScreen);
+ _mainLayout->addLayout(_iconLayout);
+ _mainLayout->addStretch();
+ _mainLayout->addWidget(_lblUserName);
+ _mainLayout->addWidget(_lblHostName);
+ this->setLayout(_mainLayout);
+ this->setSize(width, height);
+ this->updateColor();
+}
+
+ConnectionFrame::~ConnectionFrame()
+{
+ //
+}
+
+QLabel* ConnectionFrame::addIcon(const QIcon* icon)
+{
+ QLabel *label = new QLabel(this);
+ label->setPixmap(icon->pixmap(24, 24, QIcon::Normal, QIcon::On));
+ label->setAttribute(Qt::WA_TranslucentBackground);
+ label->hide();
+ _icons.append(label);
+ return label;
+}
+
+void ConnectionFrame::setSize(int width, int height)
+{
+ this->resize(width, height);
+}
+
+void ConnectionFrame::assignClient(Client* client)
+{
+ assert(_client == NULL);
+ connect(client, SIGNAL(destroyed(QObject*)), this, SLOT(onClientDisconnected(QObject*)));
+ connect(client, SIGNAL(thumbUpdated(Client*, const QPixmap&)), this, SLOT(onThumbUpdated(Client*, const QPixmap&)));
+ connect(client, SIGNAL(vncServerStateChange(Client*)), this, SLOT(onVncServerStateChange(Client*)));
+ connect(client, SIGNAL(vncClientStateChange(Client*)), this, SLOT(onVncClientStateChange(Client*)));
+ _client = client;
+ _computerId = client->computerId();
+ _lblHostName->setText(client->ip());
+ _lblHostName->setToolTip(client->host());
+ _lblUserName->setText(client->name());
+ showDefaultThumb();
+ if (_timerId == 0)
+ _timerId = startTimer(1000 + qrand() % 150);
+ this->updateColor();
+}
+
+void ConnectionFrame::showDefaultThumb()
+{
+ const int width = this->width() - 6;
+ const int height = this->height() - 8 - _lblHostName->height() - _lblUserName->height();
+ _remoteScreen = term->pixmap(width, height, QIcon::Normal, QIcon::On);
+ this->repaint();
+ //_imgScreen->setPixmap(_remoteScreen);
+}
+
+void ConnectionFrame::mouseReleaseEvent(QMouseEvent* event)
+{
+ event->accept();
+ if (event->button() == Qt::LeftButton)
+ {
+ QApplication::setOverrideCursor(QCursor(Qt::OpenHandCursor));
+ if (this->pos() != _previousPosition) {
+ qDebug("Moved");
+ emit frameMoved(this);
+ }
+ else
+ {
+ qDebug("Clicked");
+ emit clicked(this);
+ }
+ }
+}
+
+void ConnectionFrame::enterEvent(QEvent* event)
+{
+ QApplication::setOverrideCursor(QCursor(Qt::OpenHandCursor));
+ event->accept();
+}
+
+void ConnectionFrame::leaveEvent(QEvent* event)
+{
+ QApplication::setOverrideCursor(QCursor(Qt::ArrowCursor));
+ event->accept();
+}
+
+void ConnectionFrame::mousePressEvent(QMouseEvent *event)
+{
+ if (event->button() == Qt::RightButton)
+ {
+ // Menu...
+ }
+ else
+ {
+ _clickPoint = event->pos();
+ _previousPosition = this->pos();
+ QApplication::setOverrideCursor(QCursor(Qt::ClosedHandCursor));
+ }
+ // On click, the window has to be on the top-level.
+ activateWindow();
+ raise();
+ update();
+ event->accept();
+}
+
+void ConnectionFrame::mouseMoveEvent(QMouseEvent *event)
+{
+ QApplication::setOverrideCursor(QCursor(Qt::ClosedHandCursor));
+ move(mapToParent(event->pos()-_clickPoint));
+ event->accept();
+}
+
+void ConnectionFrame::mouseDoubleClickEvent(QMouseEvent* event)
+{
+ emit doubleClicked(this);
+ event->accept();
+}
+
+void ConnectionFrame::paintEvent(QPaintEvent *event)
+{
+ QGroupBox::paintEvent(event);
+ if (_remoteScreen.isNull())
+ return;
+ QPainter painter(this);
+ painter.drawPixmap((this->width() - _remoteScreen.width()) / 2, 4, _remoteScreen);
+ event->accept();
+}
+
+void ConnectionFrame::timerEvent(QTimerEvent* event)
+{
+ if (_client == NULL)
+ return;
+ ++_timerCounter;
+ if (_client->isActiveVncServer() && _timerCounter % 5 != 0)
+ return;
+ const int width = this->width() - 8;
+ const int height = this->height() - 9 - _lblHostName->height() - _lblUserName->height();
+ _client->requestThumb(width, height);
+}
+
+void ConnectionFrame::setSelection(bool selected)
+{
+ if (_selected == selected)
+ return;
+ _selected = selected;
+ this->updateColor();
+}
+
+void ConnectionFrame::updateColor()
+{
+ if (_client == NULL)
+ {
+ // Unconnected Frame
+ if (_selected)
+ this->setStyleSheet(backgroundStyle.arg("rgb(140, 140, 170)"));
+ else
+ this->setStyleSheet(backgroundStyle.arg("rgb(140, 140, 140)"));
+ for (QList<QLabel*>::iterator it(_icons.begin()); it != _icons.end(); ++it)
+ (**it).hide();
+ return;
+ }
+ _icoCam->setVisible(_client->isActiveVncServer());
+ _icoEye->setVisible(_client->isActiveVncClient());
+
+ // Normal client, no special stuff active
+
+ if (_selected && _isTutor)
+ this->setStyleSheet(backgroundStyle.arg("rgb(255, 220, 180)"));
+ else if (_isTutor)
+ this->setStyleSheet(backgroundStyle.arg("rgb(255, 180, 180)"));
+ else if (_selected)
+ this->setStyleSheet(backgroundStyle.arg("rgb(180, 180, 210)"));
+ else
+ this->setStyleSheet(backgroundStyle.arg("rgb(180, 180, 180)"));
+}
+
+/**
+ * Slots
+ */
+
+void ConnectionFrame::onClientDisconnected(QObject* client)
+{
+ assert(client == _client);
+ if (_timerId != 0)
+ {
+ killTimer(_timerId);
+ _timerId = 0;
+ }
+ _client = NULL;
+ _lblUserName->setText(QString());
+ showDefaultThumb();
+ this->updateColor();
+}
+
+void ConnectionFrame::onThumbUpdated(Client* client, const QPixmap& thumb)
+{
+ assert(client == _client);
+ _remoteScreen = thumb;
+ //_imgScreen->setPixmap(_remoteScreen);
+ this->repaint();
+}
+
+void ConnectionFrame::onVncServerStateChange(Client* client)
+{
+ this->updateColor();
+}
+
+void ConnectionFrame::onVncClientStateChange(Client* client)
+{
+ this->updateColor();
+}
diff --git a/src/server/connectionframe/connectionframe.h b/src/server/connectionframe/connectionframe.h
new file mode 100644
index 0000000..2b78056
--- /dev/null
+++ b/src/server/connectionframe/connectionframe.h
@@ -0,0 +1,77 @@
+#ifndef _CONNECTIONFRAME_H_
+#define _CONNECTIONFRAME_H_
+#include <QtGui>
+
+class Client;
+
+class ConnectionFrame : public QGroupBox
+{
+
+Q_OBJECT
+
+private:
+
+ QString _computerId;
+
+ QBoxLayout *_mainLayout;
+ QBoxLayout *_iconLayout;
+ QLabel *_lblUserName;
+ QLabel *_lblHostName;
+
+ QLabel *_icoCam, *_icoEye;
+ QList<QLabel*> _icons;
+
+ QPixmap _remoteScreen;
+
+ QPoint _clickPoint;
+ QPoint _previousPosition;
+
+ Client *_client;
+
+ int _timerId, _timerCounter;
+ bool _selected;
+ bool _isTutor;
+
+ void showDefaultThumb();
+ void updateColor();
+ QLabel* addIcon(const QIcon* icon);
+
+public:
+ ConnectionFrame(QWidget* parent, int width, int height);
+ virtual ~ConnectionFrame();
+
+ const QPixmap& getFramePixmap() const { return _remoteScreen; }
+ void setSize(int width, int height);
+ void assignClient(Client *client);
+ void setSelection(bool selected);
+ const inline bool selected() const { return _selected; }
+
+ const QString& computerId() const { return _computerId; }
+ Client* client() const { return _client; }
+
+ inline const bool isTutor() const { return _isTutor; }
+ inline void setTutor(bool b) { _isTutor = b; }
+
+protected:
+ void mouseDoubleClickEvent(QMouseEvent* event);
+ void mouseReleaseEvent(QMouseEvent* e);
+ void enterEvent(QEvent* event);
+ void leaveEvent(QEvent* event);
+ void mousePressEvent(QMouseEvent* event);
+ void mouseMoveEvent(QMouseEvent* event);
+ void paintEvent(QPaintEvent *event);
+ void timerEvent(QTimerEvent* event);
+
+signals:
+ void frameMoved(ConnectionFrame* frame);
+ void doubleClicked(ConnectionFrame* frame);
+ void clicked(ConnectionFrame* frame);
+
+private slots:
+ void onClientDisconnected(QObject* client);
+ void onThumbUpdated(Client* client, const QPixmap& thumb);
+ void onVncServerStateChange(Client* client);
+ void onVncClientStateChange(Client* client);
+};
+
+#endif
diff --git a/src/server/main.cpp b/src/server/main.cpp
new file mode 100644
index 0000000..e7c709a
--- /dev/null
+++ b/src/server/main.cpp
@@ -0,0 +1,41 @@
+#include "mainwindow/mainwindow.h"
+#include "util/util.h"
+
+int main(int argc, char** argv)
+{
+ QApplication app(argc, argv);
+ app.setOrganizationName("openslx");
+ app.setOrganizationDomain("openslx.org");
+ app.setApplicationName("pvsmgr");
+
+ qsrand((uint)QDateTime::currentMSecsSinceEpoch());
+
+ // Make sure settings directory exists
+ do {
+ USER_SETTINGS(settings);
+ QFileInfo fi(settings.fileName());
+ QDir path(fi.path());
+ qDebug() << "Settings directory is " << fi.path();
+ if (!path.exists())
+ path.mkpath(path.absolutePath());
+ // Now check if settings file exists. If not, copy system default (if available)
+ if (!fi.exists())
+ {
+ SYSTEM_SETTINGS(sys);
+ QFileInfo sysfi(sys.fileName());
+ if (sysfi.exists())
+ {
+ if (!QFile::copy(sys.fileName(), settings.fileName()))
+ qDebug() << "Copying default settings from " << sys.fileName() << " to " << settings.fileName() << " failed.";
+ }
+ }
+ } while (0);
+
+ // use system locale as language to translate gui
+ QTranslator translator;
+ translator.load(":pvsmgr");
+ app.installTranslator(&translator);
+
+ MainWindow pvsmgr;
+ return app.exec();
+}
diff --git a/src/server/mainwindow/mainwindow.cpp b/src/server/mainwindow/mainwindow.cpp
new file mode 100644
index 0000000..8c57b91
--- /dev/null
+++ b/src/server/mainwindow/mainwindow.cpp
@@ -0,0 +1,633 @@
+/*
+ # 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/
+ # -----------------------------------------------------------------------------
+ # mainWindow.cpp
+ This is the Main class for the pvsManager. The GUI is constructed here.
+ # -----------------------------------------------------------------------------
+ */
+// Self
+#include "mainwindow.h"
+// QT stuff
+#include <QtGui>
+#include <QFileDialog>
+// Other custom UI elements
+#include "../clicklabel/clicklabel.h"
+#include "../sessionnamewindow/sessionnamewindow.h"
+#include "../connectionframe/connectionframe.h"
+// Network
+#include "../net/listenserver.h"
+#include "../net/client.h"
+#include "../net/discoverylistener.h"
+#include "../../shared/networkmessage.h"
+// Others
+#include "../../shared/settings.h"
+#include "../util/util.h"
+#include "../util/global.h"
+// Auto-generated ui class
+#include "ui_mainwindow.h"
+
+MainWindow::MainWindow(QWidget* parent) :
+ QMainWindow(parent), ui(new Ui::MainWindow), _tbIconSize(24), _tbArea(Qt::LeftToolBarArea),
+ _buttonBlockTime(0)
+
+{
+ _sessionNameWindow = new SessionNameWindow(this);
+ ui->setupUi(this);
+
+ Global::setSessionName("1234");
+
+ //conWin = new ConnectionWindow(ui->widget);
+ //ui->VconWinLayout->addWidget(conWin);
+ //conList = new ConnectionList(ui->ClWidget);
+ //ui->ClientGLayout->addWidget(conList);
+
+ // Show only session name label, not textbox
+ _sessionNameLabel = new ClickLabel(this);
+ ui->mainLayout->addWidget(_sessionNameLabel);
+
+ ui->frmRoom->setStyleSheet("background-color:#444");
+
+ // toolbar and actions in pvsmgr
+ ui->action_Exit->setStatusTip(tr("Exit"));
+ ui->action_Lock->setStatusTip(tr("Lock or Unlock all Clients"));
+
+ // Close button in tool bar
+ connect(ui->action_Exit, SIGNAL(triggered()), this, SLOT(onButtonExit()));
+ connect(ui->action_BroadcastScreen, SIGNAL(triggered()), this, SLOT(onButtonBroadcast()));
+ connect(ui->action_Lock, SIGNAL(toggled(bool)), this, SLOT(onButtonLock(bool)));
+ // Clicking the session name label shows the edit field for it
+ connect(_sessionNameLabel, SIGNAL(clicked()), this, SLOT(onSessionNameClick()));
+ // Listen to updates to the session name through the session name window
+ connect(_sessionNameWindow, SIGNAL(updateSessionName()), this,
+ SLOT(onSessionNameUpdate()));
+
+ setAttribute(Qt::WA_QuitOnClose);
+ setUnifiedTitleAndToolBarOnMac(true);
+ this->showMaximized(); // show the Mainwindow maximized
+
+ _tilesX = 9;
+ _tilesY = 7;
+ _tileWidth = 10;
+ _tileHeight = 10;
+
+ _timerId = 0;
+ _timerTimeout = 0;
+
+ _listenServer = new ListenServer(CLIENT_PORT);
+ connect(_listenServer, SIGNAL(newClient(Client*)), this, SLOT(onClientConnected(Client*)));
+ _discoveryListener = new DiscoveryListener();
+
+ // Finally
+ this->onSessionNameUpdate();
+ _timerId = startTimer(10);
+ _timerTimeout = 8;
+}
+
+MainWindow::~MainWindow()
+{
+ _sessionNameLabel->deleteLater();
+ delete ui;
+}
+
+void MainWindow::placeFrameInFreeSlot(ConnectionFrame* frame)
+{
+ // Get occupied cell of each frame and store status in an array
+ const int elems = _tilesX * _tilesY;
+ int currentIndex = 0;
+ bool grid[elems];
+ memset(grid, 0, sizeof(bool) * elems); // set everything to false
+ for (QList<ConnectionFrame*>::iterator it(_clientFrames.begin()); it != _clientFrames.end(); ++it)
+ {
+ const QPoint &oldpos = (*it)->frameGeometry().topLeft();
+ const int tx = oldpos.x() / _tileWidth;
+ const int ty = oldpos.y() / _tileHeight;
+ const int index = tx + ty * _tilesX;
+ if (frame == *it)
+ {
+ // Current frame is the frame to place, remember its old index
+ currentIndex = index;
+ continue;
+ }
+ if (index < 0 || index >= elems)
+ {
+ // Current frame is out of bounds, place in top left corner
+ qDebug("Move A");
+ (*it)->move(0, 0);
+ grid[0] = true;
+ continue;
+ }
+ // Just mark cell as occupied in array
+ grid[index] = true;
+ }
+ // Safety
+ if (currentIndex < 0 || currentIndex >= elems)
+ currentIndex = 0;
+ // Now place in next free cell, start looking at current position of frame
+ for (int i = 0; i < elems; ++i)
+ {
+ const int index = (i + currentIndex) % elems;
+ if (grid[index])
+ continue;
+ const int x = (index % _tilesX) * _tileWidth;
+ const int y = (index / _tilesX) * _tileHeight;
+ //qDebug() << "Index=" << index << " i=" << i << " cI=" << currentIndex << " elems=" << elems << " x=" << x << " y=" << y;
+ qDebug("Move B");
+ frame->move(x, y);
+ break;
+ }
+}
+
+ConnectionFrame* MainWindow::createFrame()
+{
+ // Allocate and resize
+ ConnectionFrame *cf = new ConnectionFrame(ui->frmRoom, _tileWidth, _tileHeight);
+ _clientFrames.append(cf);
+ cf->show();
+ connect(cf, SIGNAL(frameMoved(ConnectionFrame *)), this, SLOT(onPlaceFrame(ConnectionFrame *)));
+ connect(cf, SIGNAL(clicked(ConnectionFrame *)), this, SLOT(onFrameClicked(ConnectionFrame *)));
+ return cf;
+}
+
+bool MainWindow::loadPosition(QSettings& settings, const QString& id, int& x, int& y)
+{
+ settings.beginGroup("client_position");
+ const QVariant retval(settings.value(id));
+ settings.endGroup();
+ if (retval.type() != QVariant::Point)
+ return false;
+ const QPoint point(retval.toPoint());
+ x = point.x();
+ y = point.y();
+ return true;
+}
+
+void MainWindow::savePosition(ConnectionFrame *cf)
+{
+ Client *client = cf->client();
+ if (client == NULL)
+ return;
+ QPoint pos(cf->pos().x() / _tileWidth, cf->pos().y() / _tileHeight);
+ USER_SETTINGS(settings);
+ settings.beginGroup("client_position");
+ settings.setValue(client->computerId(), pos);
+ settings.endGroup();
+}
+
+/*
+ * Overridden methods
+ */
+
+void MainWindow::closeEvent(QCloseEvent* e)
+{
+ int ret = QMessageBox::question(this, "Test", "Beenden?", 0, 1, 2);
+ if (ret == 1)
+ QApplication::exit(0);
+ else
+ e->ignore();
+}
+
+void MainWindow::changeEvent(QEvent* e)
+{
+ QMainWindow::changeEvent(e);
+}
+
+void MainWindow::resizeEvent(QResizeEvent* e)
+{
+ QMainWindow::resizeEvent(e);
+ if (_timerId == 0)
+ {
+ _timerId = startTimer(5);
+ }
+ _timerTimeout = 8;
+}
+
+void MainWindow::mouseReleaseEvent(QMouseEvent* e)
+{
+ // Try to figure out if the user clicked inside the "room" frame
+ // No idea if there is a more elegant way to do this without
+ // sub-classing that frame and overriding its mouseReleaseEvent
+ const QPoint pos(ui->frmRoom->mapFrom(this, e->pos()));
+ if (pos.x() < 0 || pos.y() < 0)
+ return;
+ const QSize frame(ui->frmRoom->size());
+ if (frame.width() > pos.x() && frame.height() > pos.y())
+ {
+ for (QList<ConnectionFrame*>::iterator it = _clientFrames.begin(); it != _clientFrames.end(); ++it)
+ {
+ (**it).setSelection(false);
+ }
+ }
+}
+
+void MainWindow::timerEvent(QTimerEvent* event)
+{
+ if (event->timerId() == _timerId)
+ {
+ _timerTimeout -= 1;
+ if (_timerTimeout == 1)
+ {
+ // Move toolbar if necessary
+ const int iconSize = this->size().width() / 30 + 14;
+ const int barSpace = ui->toolBar->actions().size() * (iconSize + 8);
+ const Qt::ToolBarArea area =
+ (barSpace < this->size().height() ? Qt::LeftToolBarArea : Qt::TopToolBarArea);
+ if (_tbIconSize != iconSize)
+ {
+ _tbIconSize = iconSize;
+ ui->toolBar->setIconSize(QSize(iconSize, iconSize));
+ }
+ if (_tbArea != area)
+ {
+ _tbArea = area;
+ this->addToolBar(area, ui->toolBar);
+ }
+ return;
+ }
+ // Kill timer when done
+ if (_timerTimeout <= 0)
+ {
+ killTimer(_timerId);
+ _timerId = 0;
+ // Resize all connection windows
+ if (ui->frmRoom->size().width() < 100 || ui->frmRoom->size().height() < 100 || _tilesX <= 0 || _tilesY <= 0)
+ return;
+ const int nw = ui->frmRoom->size().width() / _tilesX;
+ const int nh = ui->frmRoom->size().height() / _tilesY;
+ for (QList<ConnectionFrame*>::iterator it = _clientFrames.begin(); it != _clientFrames.end(); ++it)
+ {
+ const QPoint &oldpos = (*it)->frameGeometry().topLeft();
+ qDebug("Move C");
+ (*it)->move((oldpos.x() / _tileWidth) * nw, (oldpos.y() / _tileHeight) * nh);
+ (*it)->setSize(nw, nh);
+ }
+ _tileWidth = nw;
+ _tileHeight = nh;
+ }
+ }
+ else
+ {
+ // Unknown timer ID, kill
+ killTimer(event->timerId());
+ }
+}
+
+/*
+ * Slots
+ */
+
+void MainWindow::onPlaceFrame(ConnectionFrame* frame)
+{
+ if (_tilesX <= 0 || _tilesY <= 0)
+ return;
+ const QPoint &p = frame->frameGeometry().center();
+ const QSize &s = ui->frmRoom->geometry().size();
+ int x = (p.x() / _tileWidth) * _tileWidth;
+ int y = (p.y() / _tileHeight) * _tileHeight;
+ if (x < 0)
+ x = 0;
+ else if (x > s.width() - _tileWidth)
+ x = (_tilesX - 1) * _tileWidth;
+ if (y < 0)
+ y = 0;
+ else if (y > s.height() - _tileHeight)
+ y = (_tilesY - 1) * _tileHeight;
+ qDebug("Move D");
+ frame->move(x, y);
+ savePosition(frame);
+ const QPoint &newpos = frame->frameGeometry().topLeft();
+ for (QList<ConnectionFrame*>::iterator it(_clientFrames.begin()); it != _clientFrames.end(); ++it)
+ {
+ if (*it == frame)
+ continue;
+ if ((*it)->frameGeometry().topLeft() == newpos)
+ {
+ placeFrameInFreeSlot(*it);
+ }
+ }
+}
+
+void MainWindow::onFrameClicked(ConnectionFrame* frame)
+{
+ for (QList<ConnectionFrame*>::iterator it(_clientFrames.begin()); it != _clientFrames.end(); ++it)
+ {
+ if (*it == frame)
+ frame->setSelection(true);
+ else
+ (**it).setSelection(false);
+ }
+}
+
+void MainWindow::onSessionNameClick()
+{
+ _sessionNameWindow->show(Global::sessionName());
+}
+
+void MainWindow::onSessionNameUpdate()
+{
+ _sessionNameLabel->setText(tr("Session Name: %1 [click to edit]").arg(Global::sessionName()));
+}
+
+void MainWindow::onButtonSettings()
+{
+ // Move to any free tile
+ placeFrameInFreeSlot(createFrame());
+}
+
+void MainWindow::onButtonChat()
+{
+ /*
+ for (QList<ConnectionFrame*>::iterator it = _clientFrames.begin(); it != _clientFrames.end(); ++it) {
+ (*it)->setSize(100 + qrand() % 200);
+ }
+ */
+}
+
+void MainWindow::onButtonBroadcast()
+{
+ const qint64 now = QDateTime::currentMSecsSinceEpoch();
+ if (now < _buttonBlockTime)
+ return;
+ _buttonBlockTime = now + 3000;
+ Client *source = NULL; // the desired source (selected frame)
+ Client *oldSource = NULL; // if there is a client that is already broadcaster, save it here
+ for (QList<ConnectionFrame*>::iterator it(_clientFrames.begin()); it != _clientFrames.end(); ++it)
+ {
+ Client *c = (**it).client();
+ if ((**it).selected())
+ source = c;
+ if (c != NULL && c->isProjectionSource())
+ oldSource = c;
+ }
+ if (source == NULL && oldSource == NULL)
+ {
+ QMessageBox::information(this, tr("No Projection Source selected"), tr("You did not select any active client as the connection source."));
+ return;
+ }
+ if (oldSource != NULL)
+ {
+ // Is already broadcast source, disable
+ oldSource->setProjectionSource(false);
+ oldSource->stopVncServer();
+ if (source == NULL || source->id() == oldSource->id())
+ return;
+ }
+ source->setProjectionSource(true);
+ for (QList<ConnectionFrame*>::iterator it(_clientFrames.begin()); it != _clientFrames.end(); ++it)
+ {
+ Client *c = (**it).client();
+ if (c == NULL || c->id() == source->id())
+ continue;
+ //c->setDesiredProjectionSource(source->id());
+ c->setProjectionSource(false);
+ }
+ source->startVncServer();
+}
+
+void MainWindow::onButtonLock(bool checked)
+{
+ NetworkMessage msg;
+ msg.setField(_ID, _LOCK);
+ if (checked)
+ msg.setField("ENABLE", QByteArray("1"));
+ else
+ msg.setField("ENABLE", QByteArray("0"));
+ for (QList<ConnectionFrame*>::iterator it(_clientFrames.begin()); it != _clientFrames.end(); ++it)
+ {
+ Client *c = (**it).client();
+ if (c == NULL || (**it).isTutor())
+ continue; // Don't lock the tutor
+ c->sendMessage(msg);
+ }
+}
+
+void MainWindow::onButtonExit()
+{
+ this->close();
+}
+
+void MainWindow::onClientConnected(Client* client)
+{
+ qDebug("ListenServer told MainWindow about new connection");
+ connect(client, SIGNAL(authenticating(Client*, ClientLogin*)), this, SLOT(onClientAuthenticating(Client*, ClientLogin*)));
+ connect(client, SIGNAL(authenticated(Client*)), this, SLOT(onClientAuthenticated(Client*)));
+ connect(client, SIGNAL(vncClientStateChange(Client*)), this, SLOT(onVncClientStateChange(Client*)));
+}
+
+void MainWindow::onClientAuthenticating(Client* client, ClientLogin* request)
+{
+ disconnect(client, SIGNAL(authenticating(Client*, ClientLogin*)), this, SLOT(onClientAuthenticating(Client*, ClientLogin*)));
+ if (!request->accept) // Another receiver of that signal already rejected the client, so nothing to do
+ return;
+ bool inuse;
+ QString check = request->name;
+ int addnum = 1;
+ do
+ {
+ inuse = false;
+ for (QList<ConnectionFrame*>::iterator it(_clientFrames.begin()); it != _clientFrames.end(); ++it)
+ {
+ Client *c = (**it).client();
+ if (c == NULL)
+ continue;
+ if (!c->isAuthed())
+ continue;
+ if (c->ip() == request->ip)
+ {
+ request->accept = false;
+ return;
+ }
+ if (c->name() == check)
+ {
+ inuse = true;
+ check = request->name + " (" + QString::number(++addnum) + ")";
+ break;
+ }
+ }
+ } while (inuse && addnum < 100);
+ if (inuse)
+ request->accept = false;
+ else
+ request->name = check;
+}
+
+void MainWindow::onClientAuthenticated(Client* client)
+{
+ disconnect(client, SIGNAL(authenticated(Client*)), this, SLOT(onClientAuthenticated(Client*)));
+ connect(client, SIGNAL(vncServerStateChange(Client*)), this, SLOT(onVncServerStateChange(Client*)));
+ bool hasActiveTutor = false;
+ ConnectionFrame *deadTutor = NULL;
+ bool anyClient = false;
+ ConnectionFrame *existing = NULL;
+ for (QList<ConnectionFrame*>::iterator it(_clientFrames.begin()); it != _clientFrames.end(); ++it)
+ {
+ if ((*it)->computerId() == client->computerId())
+ existing = *it;
+ if ((*it)->client() != NULL)
+ anyClient = true;
+ if ((*it)->isTutor())
+ {
+ if ((*it)->client() == NULL)
+ deadTutor = (*it)->client();
+ else
+ hasActiveTutor = true;
+ }
+ }
+ if (!anyClient && deadTutor != NULL)
+ deadTutor->setTutor(false);
+ if (existing != NULL)
+ {
+ if (!anyClient && !hasActiveTutor)
+ existing->setTutor(true);
+ existing->assignClient(client);
+ return;
+ }
+ // New one, create
+ ConnectionFrame *cf = createFrame();
+ // Try to load last known position
+ int x, y;
+ bool ok;
+ USER_SETTINGS(usr);
+ ok = loadPosition(usr, client->computerId(), x, y);
+ if (!ok)
+ {
+ SYSTEM_SETTINGS(sys);
+ ok = loadPosition(sys, client->computerId(), x, y);
+ }
+ if (x >= _tilesX || y >= _tilesY)
+ ok = false;
+ if (ok)
+ {
+ if (x < 0)
+ x = 0;
+ if (y < 0)
+ y = 0;
+ qDebug("Move E");
+ cf->move(x * _tileWidth, y * _tileHeight);
+ onPlaceFrame(cf);
+ }
+ else
+ {
+ // Move to any free tile
+ placeFrameInFreeSlot(cf);
+ }
+ // Assign client instance
+ cf->assignClient(client);
+ // Make first active client tutor
+ if (!anyClient && !hasActiveTutor)
+ cf->setTutor(true);
+ // ################
+ NetworkMessage msg;
+ // If clients are currently locked, tell this new client
+ if (ui->action_Lock->isChecked())
+ {
+ msg.reset();
+ msg.setField(_ID, _LOCK);
+ msg.setField("ENABLE", QByteArray("1"));
+ client->sendMessage(msg);
+ }
+ // Same for VNC projections
+ for (QList<ConnectionFrame*>::iterator it(_clientFrames.begin()); it != _clientFrames.end(); ++it)
+ {
+ Client *c = (**it).client();
+ if (c != NULL && c != client && c->isActiveVncServer() && c->isProjectionSource())
+ {
+ msg.reset();
+ msg.setField(_ID, _VNCCLIENT);
+ msg.setField("HOST", c->ip());
+ msg.setField("PORT", QString::number(c->vncPort()));
+ msg.setField("ROPASS", c->vncRoPass());
+ msg.setField("CAPTION", c->name() + " @ " + c->host());
+ client->sendMessage(msg);
+ break;
+ }
+ }
+}
+
+void MainWindow::onVncServerStateChange(Client* client)
+{
+ if (client->vncPort() > 0)
+ {
+ // VNC Server started on some client - start projection on all clients interested in that client's screen
+ NetworkMessage msg;
+ msg.setField(_ID, _VNCCLIENT);
+ msg.setField("HOST", client->ip());
+ msg.setField("PORT", QString::number(client->vncPort()));
+ msg.setField("ROPASS", client->vncRoPass());
+ msg.setField("CAPTION", client->name() + " @ " + client->host());
+ for (QList<ConnectionFrame*>::iterator it(_clientFrames.begin()); it != _clientFrames.end(); ++it)
+ {
+ Client *c = (**it).client();
+ if (c == NULL)
+ continue; // Offline
+ if (c->id() == client->id() ||
+ (c->desiredProjectionSource() != client->id() && !client->isProjectionSource()))
+ continue; // Not interested
+ c->sendMessage(msg);
+ }
+ }
+ else
+ {
+ // VNC server stopped on some client or failed to start - reset local pending projection information
+ // If at least one other client seemed to be waiting for this client's screen, pop up a message
+ // on the console
+ bool wasInterested = client->isProjectionSource();
+ client->setProjectionSource(true);
+ for (QList<ConnectionFrame*>::iterator it(_clientFrames.begin()); it != _clientFrames.end(); ++it)
+ {
+ Client *c = (**it).client();
+ if (c == NULL)
+ continue;
+ if (c->desiredProjectionSource() == client->id())
+ {
+ wasInterested = true;
+ c->setDesiredProjectionSource(0);
+ }
+ }
+ if (wasInterested)
+ {
+ QMessageBox::information(this,
+ tr("Projection Error"),
+ tr("Could not send screen contents of %1 to other clients: VNC Startup failed.").arg(client->name())
+ );
+ }
+ }
+}
+
+void MainWindow::onVncClientStateChange(Client* client)
+{
+ // If the client started projection, ignore event. Also if
+ // the source is not known (anymore), we cannot do anything meaningful here
+ if (client->isActiveVncClient() || client->currentProjectionSource() == 0)
+ return;
+ // Client is not a vnc client anymore. Check if the VNC server it was (supposedly) connected
+ // to is still running, and kill it if there are no more clients connected to it.
+ // (client->currentProjectionSource() will still contain the id of the server it was connected to during this event)
+ // 1. check if vnc server is still running
+ // 2. check if there are any other clients "using" that server
+ bool inUse = false;
+ Client *server = NULL;
+ for (QList<ConnectionFrame*>::iterator it(_clientFrames.begin()); it != _clientFrames.end(); ++it)
+ {
+ Client *c = (**it).client();
+ if (c == NULL || c == client)
+ continue;
+ if (c->currentProjectionSource() == client->currentProjectionSource())
+ {
+ inUse = true;
+ break;
+ }
+ if (c->id() == client->currentProjectionSource())
+ server = c;
+ }
+ // 3. kill server if applicable
+ if (!inUse && server != NULL)
+ server->stopVncServer();
+}
diff --git a/src/server/mainwindow/mainwindow.h b/src/server/mainwindow/mainwindow.h
new file mode 100644
index 0000000..4f9d142
--- /dev/null
+++ b/src/server/mainwindow/mainwindow.h
@@ -0,0 +1,76 @@
+#ifndef _MAINWINDOW_H_
+#define _MAINWINDOW_H_
+
+#include <QtGui>
+#include <QMainWindow>
+
+class SessionNameWindow;
+class ConnectionFrame;
+class ListenServer;
+class DiscoveryListener;
+class Client;
+class ClientLogin;
+
+namespace Ui
+{
+ class MainWindow;
+}
+
+class MainWindow : public QMainWindow
+{
+ Q_OBJECT
+
+private:
+ Ui::MainWindow *ui;
+ SessionNameWindow *_sessionNameWindow;
+ QLabel *_sessionNameLabel;
+ QList<ConnectionFrame*> _clientFrames;
+ int _tileWidth, _tileHeight;
+ int _tilesX, _tilesY;
+ int _tbIconSize;
+ Qt::ToolBarArea _tbArea;
+ int _timerId, _timerTimeout;
+ ListenServer *_listenServer;
+ DiscoveryListener *_discoveryListener;
+ qint64 _buttonBlockTime;
+
+ void placeFrameInFreeSlot(ConnectionFrame* frame);
+ ConnectionFrame* createFrame();
+ bool loadPosition(QSettings& settings, const QString& id, int& x, int& y);
+ void savePosition(ConnectionFrame *cf);
+
+public:
+ MainWindow(QWidget *parent = 0);
+ ~MainWindow();
+
+protected:
+ void closeEvent(QCloseEvent *e);
+ void changeEvent(QEvent *e);
+ void resizeEvent(QResizeEvent *e);
+ void mouseReleaseEvent(QMouseEvent* e);
+ void timerEvent(QTimerEvent* event);
+
+
+protected slots:
+ // This
+ void onSessionNameClick();
+ void onSessionNameUpdate();
+ void onButtonSettings();
+ void onButtonChat();
+ void onButtonBroadcast();
+ void onButtonLock(bool checked);
+ void onButtonExit();
+ // connection frame
+ void onPlaceFrame(ConnectionFrame* frame);
+ void onFrameClicked(ConnectionFrame* frame);
+ // Net
+ void onClientConnected(Client* client);
+ void onClientAuthenticating(Client* client, ClientLogin* request);
+ void onClientAuthenticated(Client* client);
+ void onVncServerStateChange(Client* client);
+ void onVncClientStateChange(Client* client);
+
+};
+
+
+#endif
diff --git a/src/server/net/certmanager.cpp b/src/server/net/certmanager.cpp
new file mode 100644
index 0000000..e661a70
--- /dev/null
+++ b/src/server/net/certmanager.cpp
@@ -0,0 +1,92 @@
+/*
+ # 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/util/CertManager.cpp
+ # - Manage SSL certificates
+ # - provide access by name
+ # -----------------------------------------------------------------------------
+ */
+
+#include "certmanager.h"
+#include "../util/util.h"
+#include <QMap>
+#include <QFileInfo>
+#include <QSettings>
+#include <cstdlib>
+
+namespace CertManager
+{
+static QMap<QString, QSslCertificate> _certs;
+static QMap<QString, QSslKey> _keys;
+
+static void generateFiles(QString& key, QString& cert);
+static bool loadFiles(QString& keyFile, QString& certFile, QSslKey &key, QSslCertificate &cert);
+
+bool getPrivateKeyAndCert(const QString &name, QSslKey &key, QSslCertificate &cert)
+{
+ if (_keys.contains(name))
+ {
+ key = _keys[name];
+ cert = _certs[name];
+ return true;
+ }
+ USER_SETTINGS(settings);
+ QString certFile = settings.fileName().append(".").append(name);
+ QString keyFile = certFile;
+ keyFile.append(".rsa");
+ certFile.append(".crt");
+ //
+ if (!loadFiles(keyFile, certFile, key, cert))
+ {
+ generateFiles(keyFile, certFile);
+ if (!loadFiles(keyFile, certFile, key, cert))
+ return false;
+ }
+ _certs.insert(name, cert);
+ _keys.insert(name, key);
+ return true;
+}
+
+static bool loadFiles(QString& keyFile, QString& certFile, QSslKey &key, QSslCertificate &cert)
+{
+ QFileInfo keyInfo(keyFile);
+ QFileInfo certInfo(certFile);
+ if (keyInfo.exists() && certInfo.exists())
+ { // Both files exist, see if they're valid and return
+ QFile kf(keyFile);
+ kf.open(QFile::ReadOnly);
+ key = QSslKey(&kf, QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey);
+ QList<QSslCertificate> certlist = QSslCertificate::fromPath(certFile);
+ if (!key.isNull() && !certlist.empty())
+ {
+ cert = certlist.first();
+ if (!cert.isNull())
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+static void generateFiles(QString& key, QString& cert)
+{
+ char tmp[1000];
+ unlink(key.toLocal8Bit().data());
+ unlink(cert.toLocal8Bit().data());
+ snprintf(tmp, 1000,
+ "openssl req -x509 -nodes -days 3650 -newkey rsa:1024 -subj '/C=DE/ST=BaWue/L=Freiburg/CN=openslx.org' -keyout \"%s\" -out \"%s\"",
+ key.toLocal8Bit().data(), cert.toLocal8Bit().data());
+ system(tmp);
+ snprintf(tmp, 1000, "chmod 0600 \"%s\" \"%s\"", key.toLocal8Bit().data(), cert.toLocal8Bit().data());
+ system(tmp);
+}
+}
diff --git a/src/server/net/certmanager.h b/src/server/net/certmanager.h
new file mode 100644
index 0000000..c69bc23
--- /dev/null
+++ b/src/server/net/certmanager.h
@@ -0,0 +1,29 @@
+/*
+# 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/util/CertManager.cpp
+# - Manage SSL certificates
+# - provide access by name
+# -----------------------------------------------------------------------------
+*/
+
+#ifndef CERTMANAGER_H_
+#define CERTMANAGER_H_
+
+#include <QtNetwork/QSslCertificate>
+#include <QtNetwork/QSslKey>
+
+namespace CertManager
+{
+ bool getPrivateKeyAndCert(const QString &name, QSslKey &key, QSslCertificate &cert);
+}
+
+#endif /* CERTMANAGER_H_ */
diff --git a/src/server/net/client.cpp b/src/server/net/client.cpp
new file mode 100644
index 0000000..ca91e76
--- /dev/null
+++ b/src/server/net/client.cpp
@@ -0,0 +1,288 @@
+/*
+ * client.cpp
+ *
+ * Created on: 18.01.2013
+ * Author: sr
+ */
+
+#include "client.h"
+#include "../util/global.h"
+#include "../../shared/settings.h"
+#include "../../shared/util.h"
+#include <QSslSocket>
+#include <QHostAddress>
+#include <QPixmap>
+#include <cassert>
+
+#define CHALLENGE_LEN 20
+
+ClientId Client::_clientIdCounter = 0;
+
+Client::Client(QSslSocket* socket) :
+ _socket(socket), _authed(0), _desiredProjectionSource(0), _isProjectionSource(false),
+ _currentProjectionSource(0), _vncPort(0), _activeVncClient(false)
+{
+ assert(socket != NULL);
+ _id = ++_clientIdCounter;
+ _pingTimeout = QDateTime::currentMSecsSinceEpoch() + PING_TIMEOUT_MS;
+ _ip = _socket->peerAddress().toString();
+ qDebug("*** Client %s created.", qPrintable(_ip));
+ // Connect important signals
+ connect(_socket, SIGNAL(disconnected()), this, SLOT(onClosed()));
+ connect(_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onError(QAbstractSocket::SocketError)));
+ connect(_socket, SIGNAL(sslErrors(const QList<QSslError> &)), this, SLOT(onSslErrors(const QList<QSslError> &)));
+ connect(_socket, SIGNAL(readyRead()), this, SLOT(onDataArrival()));
+ // Send challenge
+ _challenge.resize(CHALLENGE_LEN);
+ for (int i = 0; i < CHALLENGE_LEN; ++i)
+ _challenge[i] = qrand() & 0xff;
+ _toClient.reset();
+ _toClient.setField(_ID, _CHALLENGE);
+ _toClient.setField(_CHALLENGE, _challenge);
+ _toClient.writeMessage(_socket);
+ // give client 3 seconds to complete handshake
+ _timerIdAuthTimeout = startTimer(3000);
+}
+
+Client::~Client()
+{
+ if (_socket != NULL)
+ {
+ qDebug("**** DELETE IN DESTRUCTOR");
+ _socket->deleteLater();
+ }
+ qDebug("*** Client %s destroyed.", qPrintable(_ip));
+}
+
+void Client::timerEvent(QTimerEvent* event)
+{
+ if (event->timerId() == _timerIdAuthTimeout)
+ {
+ // Client did not send login request within 3 seconds
+ killTimer(_timerIdAuthTimeout);
+ _timerIdAuthTimeout = 0;
+ this->disconnect();
+ }
+}
+
+void Client::sendMessage(NetworkMessage& message)
+{
+ if (_socket == NULL || _socket->state() != QAbstractSocket::ConnectedState)
+ return;
+ message.writeMessage(_socket);
+ if (!message.writeComplete())
+ {
+ qCritical() << "SendMessage to client " << _name << "@" << _ip << " failed!";
+ }
+}
+
+void Client::requestThumb(const int width, const int height)
+{
+ if (_socket == NULL || _socket->state() != QAbstractSocket::ConnectedState)
+ {
+ qDebug("requestThumb called in bad state");
+ return;
+ }
+ _toClient.reset();
+ _toClient.setField(_ID, _THUMB);
+ _toClient.setField(_X, QString::number(width));
+ _toClient.setField(_Y, QString::number(height));
+ _toClient.writeMessage(_socket);
+}
+
+void Client::onDataArrival()
+{
+ _pingTimeout = QDateTime::currentMSecsSinceEpoch() + PING_TIMEOUT_MS;
+ //
+ if (_socket == NULL || _socket->state() != QAbstractSocket::ConnectedState)
+ {
+ qDebug("dataArrival called in bad state");
+ return;
+ }
+
+ //qDebug() << _socket->bytesAvailable() << " bytes to read";
+ bool ret;
+ while (_socket->bytesAvailable())
+ {
+ ret = _fromClient.readMessage(_socket); // let the message read data from socket
+ if (!ret) // error parsing msg, disconnect client!
+ {
+ this->disconnect();
+ return;
+ }
+ if (_fromClient.readComplete()) // message is complete
+ {
+ this->handleMsg();
+ if (_socket == NULL)
+ return;
+ _fromClient.reset();
+ }
+ }
+}
+
+void Client::onSslErrors(const QList<QSslError> & errors)
+{
+ this->disconnect();
+}
+
+void Client::onClosed()
+{
+ this->disconnect();
+}
+
+void Client::onError(QAbstractSocket::SocketError errcode)
+{
+ this->disconnect();
+}
+
+void Client::handleMsg()
+{
+ const QString &id = _fromClient.getFieldString(_ID);
+ if (id.isEmpty())
+ {
+ qDebug("Received message with empty ID field. ignored.");
+ return;
+ }
+ qDebug() << "Received message " << id;
+
+ if (_authed == 2)
+ {
+ // Following messages are only valid of the client is already authenticated
+ if (id == _THUMB)
+ {
+ QPixmap pixmap;
+ if (!pixmap.loadFromData(_fromClient.getFieldBytes("IMG")))
+ {
+ qDebug("Could not decode thumbnail image from client.");
+ return;
+ }
+ emit thumbUpdated(this, pixmap);
+ }
+ else if (id == _VNCSERVER)
+ {
+ // Client tells about startup of vnc server
+ const int port = _fromClient.getFieldString("PORT").toInt();
+ if (port <= 0)
+ {
+ if (_vncPort <= 0)
+ {
+ qDebug() << "Starting VNC server on client" << _name << " (" << _ip << ") failed.";
+ // TODO: Show message on manager
+ }
+ }
+ else
+ {
+ _vncRoPass = _fromClient.getFieldString("ROPASS");
+ _vncRwPass = _fromClient.getFieldString("RWPASS");
+ }
+ _vncPort = port;
+ emit vncServerStateChange(this);
+ }
+ else if (id == _VNCCLIENT)
+ {
+ // Client tells us that it started or stopped displaying a remote screen via VNC
+ _activeVncClient = (_fromClient.getFieldString("ENABLED").toInt() != 0);
+ const ClientId other = (ClientId)_fromClient.getFieldString("CLIENTID").toInt();
+
+ if (!_activeVncClient && other == 0)
+ _desiredProjectionSource = 0;
+
+ emit vncClientStateChange(this);
+
+ if (!_activeVncClient)
+ _currentProjectionSource = 0;
+ else
+ _currentProjectionSource = other;
+ }
+ return;
+ }
+
+ if (_authed == 1) // Not authed yet, only care about login requests
+ {
+ if (id == _LOGIN)
+ {
+ killTimer(_timerIdAuthTimeout);
+ _timerIdAuthTimeout = 0;
+ ClientLogin request;
+ request.accept = true;
+ request.host = _fromClient.getFieldString("HOST");
+ request.name = _fromClient.getFieldString("NAME");
+ request.ip = _socket->peerAddress().toString();
+ qDebug() << "Login request by " << request.name;
+ // emit event, see if request is accepted
+ emit authenticating(this, &request);
+ if (!request.accept)
+ {
+ qDebug("Request denied.");
+ this->disconnect(); // Nope
+ return;
+ }
+ // Accepted
+ _authed = 2;
+ qDebug("valid, step <- 2");
+ _name = request.name;
+ _host = request.host;
+ _toClient.reset();
+ _toClient.setField(_ID, _LOGIN);
+ _toClient.writeMessage(_socket);
+ emit authenticated(this);
+ }
+ return;
+ }
+
+ if (_authed == 0)
+ {
+ // Waiting for challenge reply by client
+ if (id == _CHALLENGE)
+ {
+ QByteArray hash(_fromClient.getFieldBytes(_HASH));
+ QByteArray challenge(_fromClient.getFieldBytes(_CHALLENGE));
+ if (genSha1(&Global::sessionNameArray(), &_challenge) != hash)
+ { // Challenge reply is invalid, drop client
+ _toClient.buildErrorMessage("Challenge reply invalid.");
+ _toClient.writeMessage(_socket);
+ this->deleteLater();
+ return;
+ }
+ // Now answer to challenge by client
+ _toClient.reset();
+ _toClient.setField(_ID, _CHALLENGE);
+ _toClient.setField(_HASH, genSha1(&Global::sessionNameArray(), &challenge));
+ _toClient.writeMessage(_socket);
+ _authed = 1;
+ qDebug("client's challenge reply was valid, step <- 1");
+ }
+ return;
+ }
+
+}
+
+void Client::startVncServer()
+{
+ _vncPort = 0;
+ _toClient.reset();
+ _toClient.setField(_ID, _VNCSERVER);
+ _toClient.setField("ENABLE", QByteArray("1"));
+ sendMessage(_toClient);
+}
+
+void Client::stopVncServer()
+{
+ _toClient.reset();
+ _toClient.setField(_ID, _VNCSERVER);
+ _toClient.setField("ENABLE", QByteArray("0"));
+ sendMessage(_toClient);
+}
+
+void Client::disconnect()
+{
+ if (_socket != NULL)
+ {
+ qDebug("*** Client %s disconnected.", qPrintable(_ip));
+ _socket->blockSignals(true);
+ _socket->abort();
+ _socket->deleteLater();
+ _socket = NULL;
+ this->deleteLater();
+ }
+}
diff --git a/src/server/net/client.h b/src/server/net/client.h
new file mode 100644
index 0000000..8004ebb
--- /dev/null
+++ b/src/server/net/client.h
@@ -0,0 +1,104 @@
+#ifndef CLIENT_H_
+#define CLIENT_H_
+
+#include <QtCore>
+#include <QSslError>
+#include <QAbstractSocket>
+#include "../../shared/networkmessage.h"
+
+class QSslSocket;
+
+struct ClientLogin
+{
+ bool accept;
+ QString name;
+ QString host;
+ QString ip;
+};
+
+typedef int ClientId;
+
+class Client : public QObject
+{
+ Q_OBJECT
+
+private:
+ static ClientId _clientIdCounter;
+
+ QSslSocket *_socket;
+ int _authed; // 0 = challenge sent, awaiting reply 1 = challenge ok, client challenge replied, awaiting login, 2 = ESTABLISHED
+ QString _name;
+ QString _host;
+ QString _ip;
+ QByteArray _challenge;
+ qint64 _pingTimeout;
+ NetworkMessage _toClient, _fromClient;
+ int _timerIdAuthTimeout;
+
+ ClientId _id; // this client's unique id
+
+ // If this client should be projected to from another client, the other client's id is set here. 0 otherwise.
+ // This is not currently used and it is questionable if this makes sense, as it might just be confusing if
+ // several groups students watch different other students.
+ // Also, visualizing such a situation in the GUI in a meaningful way would be hard.
+ ClientId _desiredProjectionSource;
+ // This boolean tells whether this client is currently the VNC broadcast source. This
+ // version only allows "one to all others" setups
+ bool _isProjectionSource;
+
+ ClientId _currentProjectionSource;
+
+ QString _vncRwPass, _vncRoPass;
+ int _vncPort;
+ bool _activeVncClient;
+
+ void handleMsg();
+ void disconnect();
+
+protected:
+ void timerEvent(QTimerEvent* event);
+
+public:
+ explicit Client(QSslSocket* socket);
+ ~Client();
+ void requestThumb(const int width, const int height);
+ void sendMessage(NetworkMessage& message);
+ //void acceptData();
+ const inline bool isAuthed() const { return _authed == 2; }
+ const inline QString& name() const { return _name; }
+ const inline QString& host() const { return _host; }
+ const inline QString& ip() const { return _ip; }
+ // The computer ID (used eg. for saving the frame positions) is currently the IP, but this is an extra method for easier modification later on
+ const inline QString& computerId() const { return _ip; }
+ const inline ClientId id() const { return _id; }
+
+ inline const QString& vncRwPass() const { return _vncRwPass; }
+ inline const QString& vncRoPass() const { return _vncRoPass; }
+ inline const int vncPort() const { return _vncPort; }
+ inline const bool isActiveVncClient() const { return _activeVncClient; }
+ inline const bool isActiveVncServer() const { return _vncPort > 0; }
+ inline const ClientId desiredProjectionSource() const { return _desiredProjectionSource; }
+ inline void setDesiredProjectionSource(ClientId source) { _desiredProjectionSource = source; }
+ inline const bool isProjectionSource() const { return _isProjectionSource; }
+ inline void setProjectionSource(bool enable) { _isProjectionSource = enable; }
+ inline const ClientId currentProjectionSource() const { return _currentProjectionSource; }
+ inline void setCurrentProjectionSource(ClientId source) { _currentProjectionSource = source; }
+ void startVncServer();
+ void stopVncServer();
+
+signals:
+ void authenticating(Client* client, ClientLogin* request);
+ void authenticated(Client* client);
+ void thumbUpdated(Client* client, const QPixmap& thumb);
+ void vncServerStateChange(Client* client);
+ void vncClientStateChange(Client* client);
+
+private slots:
+ void onSslErrors(const QList<QSslError> & errors); // triggered for errors that occur during SSL negotiation
+ void onDataArrival(); // triggered if data is available for reading
+ void onClosed(); // triggered if the socket is closed
+ void onError(QAbstractSocket::SocketError errcode); // triggered if an error occurs on the socket
+
+};
+
+#endif /* CLIENT_H_ */
diff --git a/src/server/net/discoverylistener.cpp b/src/server/net/discoverylistener.cpp
new file mode 100644
index 0000000..051a972
--- /dev/null
+++ b/src/server/net/discoverylistener.cpp
@@ -0,0 +1,165 @@
+/*
+ * discoverylistener.cpp
+ *
+ * Created on: 25.01.2013
+ * Author: sr
+ */
+
+#include "discoverylistener.h"
+#include "certmanager.h"
+#include "../util/global.h"
+#include "../../shared/settings.h"
+#include "../../shared/network.h"
+#include "../../shared/util.h"
+#include <QCryptographicHash>
+#include <QSslCertificate>
+#include <QSslKey>
+
+#define UDPBUFSIZ 9000
+#define SPAM_CUTOFF 50
+#define SPAM_MODERATE_INTERVAL 6787
+#define SPAM_MODERATE_AT_ONCE 100
+
+// static objects
+
+
+// +++ static ++++ hash ip address +++
+
+static quint16 hash(const QHostAddress& host)
+{
+ static quint16 seed1 = 0, seed2 = 0;
+ while (seed1 == 0) // Make sure the algorithm uses different seeds each time the program is
+ { // run to prevent hash collision attacks
+ seed1 = (quint16)(qrand() & 0xffff);
+ seed2 = (quint16)(qrand() & 0xffff);
+ }
+ quint8 data[16], len;
+ if (host.protocol() == QAbstractSocket::IPv4Protocol)
+ {
+ // IPv4
+ quint32 addr = host.toIPv4Address();
+ len = 4;
+ memcpy(data, &addr, len);
+ }
+ else if (QAbstractSocket::IPv6Protocol)
+ {
+ // IPv6
+ len = 16;
+ // Fast version (might break with future qt versions)
+ memcpy(data, host.toIPv6Address().c, len);
+ /* // --- Safe version (but better try to figure out a new fast way if above stops working ;))
+ Q_IPV6ADDR addr = host.toIPv6Address();
+ for (int i = 0; i < len; ++i)
+ data[i] = addr[i];
+ */
+ }
+ else
+ {
+ // Durr?
+ len = 2;
+ data[0] = (quint16)qrand();
+ data[1] = (quint16)qrand();
+ }
+ quint16 result = 0;
+ quint16 mod = seed1;
+ for (quint8 i = 0; i < len; ++i)
+ {
+ result = ((result << 1) + data[i]) ^ mod; // because of the shift this algo is not suitable for len(input) > 8
+ mod += seed2 + data[i];
+ }
+ return result;
+}
+
+// +++++++++++++++++++++++++++++++++++
+
+DiscoveryListener::DiscoveryListener() :
+ _socket(this), _counterResetPos(0)
+{
+ if (!_socket.bind(SERVICE_DISCOVERY_PORT))
+ qFatal("Could not bind to service discovery port %d", (int)SERVICE_DISCOVERY_PORT);
+ connect(&_socket, SIGNAL(readyRead()), this, SLOT(onReadyRead()));
+ for (int i = 0; i < SD_PACKET_TABLE_SIZE; ++i)
+ _packetCounter[i] = 0;
+ startTimer((SPAM_MODERATE_AT_ONCE * SPAM_MODERATE_INTERVAL) / SD_PACKET_TABLE_SIZE + 1);
+}
+
+DiscoveryListener::~DiscoveryListener()
+{
+ // TODO Auto-generated destructor stub
+}
+
+/**
+ * Overrides
+ */
+
+/**
+ * Decrease packet counters
+ */
+void DiscoveryListener::timerEvent(QTimerEvent* event)
+{
+ for (int i = 0; i < SPAM_MODERATE_AT_ONCE; ++i)
+ {
+ if (++_counterResetPos >= SD_PACKET_TABLE_SIZE)
+ _counterResetPos = 0;
+ if (_packetCounter[_counterResetPos] > 10)
+ _packetCounter[_counterResetPos] -= 10;
+ else if (_packetCounter[_counterResetPos] != 0)
+ _packetCounter[_counterResetPos] = 0;
+ }
+}
+
+/**
+ * Slots
+ */
+
+void DiscoveryListener::onReadyRead()
+{
+ char data[UDPBUFSIZ];
+ QHostAddress addr;
+ quint16 port;
+ while (_socket.hasPendingDatagrams())
+ {
+ const qint64 size = _socket.readDatagram(data, UDPBUFSIZ, &addr, &port);
+ if (size <= 0)
+ continue;
+ const quint16 bucket = hash(addr) % SD_PACKET_TABLE_SIZE;
+ if (_packetCounter[bucket] > SPAM_CUTOFF)
+ {
+ qDebug() << "SD: Potential (D)DoS from " << _socket.peerAddress().toString();
+ // emit some signal and pop up a big warning that someone is flooding/ddosing the PVS SD
+ // ... on the other hand, will the user understand? ;)
+ continue;
+ }
+ ++_packetCounter[bucket];
+ _packet.reset();
+ if (!_packet.readMessage(data, (quint32)size))
+ continue;
+ // Valid packet, process it:
+ const QByteArray iplist(_packet.getFieldBytes(_IPLIST));
+ const QByteArray hash(_packet.getFieldBytes(_HASH));
+ const QByteArray salt1(_packet.getFieldBytes(_SALT1));
+ const QByteArray salt2(_packet.getFieldBytes(_SALT2));
+ // For security, the salt has to be at least 16 bytes long
+ if (salt1.size() < 16 || salt2.size() < 16)
+ continue; // To make this more secure, you could remember the last X salts used, and ignore new packets using the same
+ // 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()))
+ continue;
+ // If so, check if the submitted hash seems valid
+ if (genSha1(&Global::sessionNameArray(), &salt1, &iplist) != hash)
+ continue; // did not match local session name
+ qDebug("Got matching discovery request...");
+ QByteArray myiplist(Network::interfaceAddressesToString().toUtf8());
+ QSslKey key;
+ QSslCertificate cert;
+ CertManager::getPrivateKeyAndCert("manager", key, cert);
+ QByteArray certhash(cert.digest(QCryptographicHash::Sha1));
+ // Reply to client
+ _packet.reset();
+ _packet.setField(_HASH, genSha1(&Global::sessionNameArray(), &salt2, &myiplist, &CLIENT_PORT_ARRAY, &certhash));
+ _packet.setField(_IPLIST, myiplist);
+ _packet.setField(_PORT, CLIENT_PORT_ARRAY);
+ _packet.setField(_CERT, certhash);
+ _packet.writeMessage(&_socket, addr, port);
+ }
+}
diff --git a/src/server/net/discoverylistener.h b/src/server/net/discoverylistener.h
new file mode 100644
index 0000000..64d4351
--- /dev/null
+++ b/src/server/net/discoverylistener.h
@@ -0,0 +1,40 @@
+/*
+ * discoverylistener.h
+ *
+ * Created on: 25.01.2013
+ * Author: sr
+ */
+
+#ifndef DISCOVERYLISTENER_H_
+#define DISCOVERYLISTENER_H_
+
+#include <QtCore>
+#include <QUdpSocket>
+#include "../../shared/networkmessage.h"
+
+#define SD_PACKET_TABLE_SIZE 20000
+
+class DiscoveryListener : public QObject
+{
+ Q_OBJECT
+
+private:
+ QUdpSocket _socket;
+ NetworkMessage _packet;
+ int _counterResetPos;
+
+ quint8 _packetCounter[SD_PACKET_TABLE_SIZE]; // count packets per source address to ignore spammers
+
+protected:
+ void timerEvent(QTimerEvent* event);
+
+public:
+ DiscoveryListener();
+ virtual ~DiscoveryListener();
+
+private slots:
+ void onReadyRead();
+
+};
+
+#endif /* DISCOVERYLISTENER_H_ */
diff --git a/src/server/net/listenserver.cpp b/src/server/net/listenserver.cpp
new file mode 100644
index 0000000..706962d
--- /dev/null
+++ b/src/server/net/listenserver.cpp
@@ -0,0 +1,40 @@
+#include "listenserver.h"
+#include "client.h"
+#include <QSslSocket>
+
+#define MAX_CLIENTS 50
+
+ListenServer::ListenServer(quint16 port)
+{
+ if (!_server.listen(QHostAddress::Any, port) || !_server.isListening())
+ qFatal("Cannot bind to TCP port %d (incoming SSL clients)", (int)port);
+ connect(&_server, SIGNAL(newConnection()), this, SLOT(newClientConnection()));
+}
+
+ListenServer::~ListenServer()
+{
+ _server.close();
+ for (int i = 0; i < _clients.size(); ++i)
+ _clients[i]->deleteLater();
+}
+
+/**
+ * Slots
+ */
+
+void ListenServer::newClientConnection()
+{
+ QSslSocket* sock;
+ while ((sock = (QSslSocket*)_server.nextPendingConnection()) != NULL)
+ {
+ if (_clients.size() >= MAX_CLIENTS)
+ {
+ sock->abort();
+ sock->deleteLater();
+ continue;
+ }
+ Client* client = new Client(sock);
+ _clients.append(client); // create new client class and add to list
+ emit newClient(client);
+ }
+}
diff --git a/src/server/net/listenserver.h b/src/server/net/listenserver.h
new file mode 100644
index 0000000..f237703
--- /dev/null
+++ b/src/server/net/listenserver.h
@@ -0,0 +1,30 @@
+#ifndef LISTENSERVER_H_
+#define LISTENSERVER_H_
+
+#include <QtCore>
+#include <QList>
+#include "sslserver.h"
+
+class Client;
+
+class ListenServer : public QObject
+{
+ Q_OBJECT
+
+private:
+ SslServer _server;
+ QList<Client*> _clients;
+
+public:
+ explicit ListenServer(quint16 port);
+ virtual ~ListenServer();
+
+private slots:
+ void newClientConnection();
+
+signals:
+ void newClient(Client* client);
+
+};
+
+#endif /* LISTENSERVER_H_ */
diff --git a/src/server/net/sslserver.cpp b/src/server/net/sslserver.cpp
new file mode 100644
index 0000000..70daea4
--- /dev/null
+++ b/src/server/net/sslserver.cpp
@@ -0,0 +1,113 @@
+/*
+ # 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 "certmanager.h"
+
+SslServer::SslServer()
+{
+ _tmr = startTimer(5123);
+ //QSslSocket::setDefaultCiphers(QSslSocket::supportedCiphers());
+}
+
+SslServer::~SslServer()
+{
+ killTimer((_tmr));
+}
+
+void SslServer::incomingConnection(int socketDescriptor)
+{
+ QSslSocket *serverSocket = new QSslSocket(NULL);
+ connect(serverSocket, SIGNAL(sslErrors(const QList<QSslError> &)), this, SLOT(sslErrors(const QList<QSslError> &)));
+ QSslKey key;
+ QSslCertificate cert;
+ CertManager::getPrivateKeyAndCert("manager", key, cert);
+ serverSocket->setPrivateKey(key);
+ serverSocket->setLocalCertificate(cert);
+ 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 our newConnection event
+ connect(serverSocket, SIGNAL(encrypted()), this, SIGNAL(newConnection()));
+ serverSocket->startServerEncryption();
+ _pending.push_back(serverSocket);
+ }
+ else
+ {
+ serverSocket->deleteLater();
+ }
+}
+
+void SslServer::sslErrors(const QList<QSslError> & errors)
+{
+ //qDebug("FIXME: SSL ERRORS on SERVER: %s", qPrintable(errors.begin()->errorString()));
+}
+
+void SslServer::timerEvent(QTimerEvent* event)
+{
+ // Remove all sockets marked for deletion
+ while (!_delete.isEmpty())
+ {
+ QSslSocket *sock = _delete.takeFirst();
+ sock->blockSignals(true);
+ sock->deleteLater();
+ }
+ _delete = _pending;
+ _pending.clear();
+}
+
+bool SslServer::hasPendingConnections()
+{
+ for (QList<QSslSocket*>::iterator it(_pending.begin()); it != _pending.end(); it++)
+ {
+ qDebug("State: %d - Encrypted: %d", (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())
+ {
+ QSslSocket *sock = *it;
+ QObject::disconnect(sock, SIGNAL(encrypted()), this, SIGNAL(newConnection()));
+ _pending.removeAll(sock);
+ _delete.removeAll(sock);
+ return sock;
+ }
+ }
+ for (QList<QSslSocket*>::iterator it(_delete.begin()); it != _delete.end(); it++)
+ {
+ if ((*it)->state() == QAbstractSocket::ConnectedState && (*it)->isEncrypted())
+ {
+ QSslSocket *sock = *it;
+ QObject::disconnect(sock, SIGNAL(encrypted()), this, SIGNAL(newConnection()));
+ _pending.removeAll(sock);
+ _delete.removeAll(sock);
+ return sock;
+ }
+ }
+ return NULL;
+}
+
diff --git a/src/server/net/sslserver.h b/src/server/net/sslserver.h
new file mode 100644
index 0000000..400bf6a
--- /dev/null
+++ b/src/server/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();
+
+ 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:
+ void incomingConnection(int socketDescriptor);
+ void timerEvent (QTimerEvent* event);
+ QList<QSslSocket*> _pending;
+ QList<QSslSocket*> _delete;
+ int _tmr;
+};
+
+#endif /* SSLSERVER_H_ */
diff --git a/src/server/sessionnamewindow/sessionnamewindow.cpp b/src/server/sessionnamewindow/sessionnamewindow.cpp
new file mode 100644
index 0000000..1d8c699
--- /dev/null
+++ b/src/server/sessionnamewindow/sessionnamewindow.cpp
@@ -0,0 +1,68 @@
+/*
+ # 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/
+ # -----------------------------------------------------------------------------
+ # mainWindow.cpp
+ This is the Main class for the pvsManager. The GUI is contructed here.
+ # -----------------------------------------------------------------------------
+ */
+
+#include <QtGui>
+#include "sessionnamewindow.h"
+#include "../util/global.h"
+
+#include "ui_sessionname.h"
+
+SessionNameWindow::SessionNameWindow(QWidget *parent) :
+ QDialog(parent), ui(new Ui::SessionName)
+
+{
+ ui->setupUi(this);
+ connect(ui->bboxOkCancel, SIGNAL(accepted()), this, SLOT(onOkClicked()));
+ connect(ui->bboxOkCancel, SIGNAL(rejected()), this, SLOT(close()));
+ connect(ui->cmdRandom, SIGNAL(clicked(bool)), this, SLOT(onGenerateRandomName()));
+}
+
+SessionNameWindow::~SessionNameWindow()
+{
+ delete ui;
+}
+
+void SessionNameWindow::show(const QString& name)
+{
+ ui->txtName->setText(name);
+ this->showNormal();
+}
+
+/*
+ * Overridden methods
+ */
+
+void SessionNameWindow::closeEvent(QCloseEvent *e)
+{
+ e->ignore();
+ this->hide();
+}
+
+/**
+ * Slots
+ */
+
+void SessionNameWindow::onOkClicked()
+{
+ Global::setSessionName(ui->txtName->text());
+ emit updateSessionName();
+ this->hide();
+}
+
+void SessionNameWindow::onGenerateRandomName()
+{
+ ui->txtName->setText(QString::number(qrand() % 9000 + 1000));
+}
diff --git a/src/server/sessionnamewindow/sessionnamewindow.h b/src/server/sessionnamewindow/sessionnamewindow.h
new file mode 100644
index 0000000..ed944c1
--- /dev/null
+++ b/src/server/sessionnamewindow/sessionnamewindow.h
@@ -0,0 +1,38 @@
+#ifndef _SESSIONNAMEWINDOW_H_
+#define _SESSIONNAMEWINDOW_H_
+
+#include <QtGui>
+
+
+namespace Ui
+{
+class SessionName;
+}
+
+class SessionNameWindow : public QDialog
+{
+ Q_OBJECT
+
+private:
+ Ui::SessionName *ui;
+
+public:
+ SessionNameWindow(QWidget *parent = 0);
+ ~SessionNameWindow();
+
+ void show(const QString& name);
+
+protected:
+ void closeEvent(QCloseEvent *e);
+
+private slots:
+ void onOkClicked();
+ void onGenerateRandomName();
+
+signals:
+ void updateSessionName();
+
+};
+
+
+#endif
diff --git a/src/server/util/global.cpp b/src/server/util/global.cpp
new file mode 100644
index 0000000..9b7b4f2
--- /dev/null
+++ b/src/server/util/global.cpp
@@ -0,0 +1,17 @@
+/*
+ * global.cpp
+ *
+ * Created on: 29.01.2013
+ * Author: sr
+ */
+
+#include "global.h"
+
+QString Global::_sessionName = QString();
+QByteArray Global::_sessionNameArray = QByteArray();
+
+void Global::setSessionName(const QString& name)
+{
+ Global::_sessionName = name;
+ Global::_sessionNameArray = name.toUtf8();
+}
diff --git a/src/server/util/global.h b/src/server/util/global.h
new file mode 100644
index 0000000..38eec6d
--- /dev/null
+++ b/src/server/util/global.h
@@ -0,0 +1,29 @@
+/*
+ * global.h
+ *
+ * Created on: 29.01.2013
+ * Author: sr
+ */
+
+#ifndef GLOBAL_H_
+#define GLOBAL_H_
+
+#include <QString>
+#include <QByteArray>
+
+class Global
+{
+private:
+ Global(){}
+ ~Global(){}
+
+ static QString _sessionName;
+ static QByteArray _sessionNameArray;
+
+public:
+ static const QString& sessionName() { return Global::_sessionName; }
+ static const QByteArray& sessionNameArray() { return Global::_sessionNameArray; }
+ static void setSessionName(const QString& name);
+};
+
+#endif /* GLOBAL_H_ */
diff --git a/src/server/util/util.cpp b/src/server/util/util.cpp
new file mode 100644
index 0000000..7ff9404
--- /dev/null
+++ b/src/server/util/util.cpp
@@ -0,0 +1,14 @@
+/*
+ * Util.cpp
+ *
+ * Created on: 18.01.2013
+ * Author: sr
+ */
+
+#include "util.h"
+
+namespace Util
+{
+
+}
+
diff --git a/src/server/util/util.h b/src/server/util/util.h
new file mode 100644
index 0000000..e2d6a62
--- /dev/null
+++ b/src/server/util/util.h
@@ -0,0 +1,17 @@
+#ifndef UTIL_H_
+#define UTIL_H_
+
+// Helper for getting a settings object in various places, so if you ever change the organization, location,
+// file format or anything, you won't have to edit in 100 places.
+// Use like this:
+// USER_SETTINGS(settings)
+// settings.value("somekey")
+#define USER_SETTINGS(name) QSettings name (QSettings::IniFormat, QSettings::UserScope, "openslx", "pvs2mgr")
+#define SYSTEM_SETTINGS(name) QSettings name (QSettings::IniFormat, QSettings::SystemScope, "openslx", "pvs2mgr")
+
+namespace Util
+{
+
+}
+
+#endif /* UTIL_H_ */