From 4d522589c0ab04ae2be76d53788597626e57e71f Mon Sep 17 00:00:00 2001 From: Manuel Schneider Date: Tue, 22 Jul 2014 14:35:30 +0200 Subject: Bugfix: One click source change now fully supported Since the async nature of this protocol introduces race conditions when changing the source of the projection, the possiblity that two servers exist at a moment is still there. Even though we thought we do not support multiple sources. This is the reason why _desiredProjectionSource is needed after all. --- TODO | 2 +- src/server/mainwindow/mainwindow.cpp | 130 +++++++++++++++-------------------- src/server/net/client.h | 14 +++- 3 files changed, 68 insertions(+), 78 deletions(-) diff --git a/TODO b/TODO index b6d1eaa..897c470 100644 --- a/TODO +++ b/TODO @@ -10,7 +10,7 @@ alle Clientsperren wieder aufgehoben werden. [x] -[manuel] BUG: Changing projection source in student-to-tutor results in tutor +[x] BUG: Changing projection source in student-to-tutor results in tutor not starting x11vnc [ ] Beim Anschalten (des PVS-Dozentinnenteils) sollen alle lockScreen(true); if (_mode == Mode::Broadcast){ - // _watchers.insert(client->id(), client); - client->setWatcher(true); + client->setDesiredProjectionSource(_streamingSource); Client* c = getClientFromId(_streamingSource); if (c != NULL) { client->startVncClient(c); @@ -660,8 +659,10 @@ void MainWindow::onButtonTutorToAll() // Set all clients as watchers for (QList::iterator it(_clientFrames.begin()); it != _clientFrames.end(); ++it) { - if ((*it)->client() != NULL && (*it)->client() != getClientFromId(_streamingSource)) - (*it)->client()->setWatcher(true); + if ((*it)->client() != NULL && (*it)->client() != getClientFromId(_streamingSource)){ + (*it)->client()->setDesiredProjectionSource(getTutorFrame()->client()->id()); + } + } } else // If this mode is already active @@ -702,25 +703,21 @@ void MainWindow::onButtonTutorToStudent() // If this is the first call in this mode clear the watchers if (_mode != Mode::Multicast) { - // _watchers.clear(); for (QList::iterator it(_clientFrames.begin()); it != _clientFrames.end(); ++it) { if ((*it)->client() != NULL) - (*it)->client()->setWatcher(false); + (*it)->client()->setDesiredProjectionSource(NO_SOURCE); } } // If "to" already watches "from" stop it - // if (_watchers.contains(to->id())) - if (getClientFromId(getSelectedFrame()->client()->id())->isWatcher()) + if (getSelectedFrame()->client()->isWatcher()) { - // _watchers.remove(to->id()); - getClientFromId(getSelectedFrame()->client()->id())->setWatcher(false); + getSelectedFrame()->client()->setDesiredProjectionSource(NO_SOURCE); } else // list "to" as watcher { - // _watchers.insert(to->id(), to); - getClientFromId(getSelectedFrame()->client()->id())->setWatcher(true); + getSelectedFrame()->client()->setDesiredProjectionSource(getTutorFrame()->client()->id()); } _mode = Mode::Multicast; @@ -746,31 +743,25 @@ void MainWindow::onButtonStudentToTutor() QMessageBox::critical(this, tr("Projection"), sStrSourceOffline); else if (getTutorFrame()->client() == NULL) QMessageBox::critical(this, tr("Projection"), sStrTutorOffline); - else{ - DisableButtons(); - - if (_mode != Mode::Unicast) - { - // If this is the first run in this mode set the tutor as watcher - for (QList::iterator it(_clientFrames.begin()); it != _clientFrames.end(); ++it) - if ((*it)->client() != NULL) - (*it)->client()->setWatcher(getTutorFrame()->client()->id() == (*it)->client()->id()); - _mode = Mode::Unicast; - } - else + else + { + // If this is not the first run in this mode and the current source is selected, stop the streaming. + if (_mode == Mode::Unicast && getSelectedFrame()->client()->id() == _streamingSource) { - // If this mode is already active and the current source is selected, stop the streaming. - if (getSelectedFrame()->client()->id() == _streamingSource ) - { - // Stop reset everything - _mode = Mode::None; - reset(); - return; - } - // If another client is selected solely the current streaming source shall be changed. - // This should be handled by startVncServerIfNecessary(...). + // Stop reset everything + _mode = Mode::None; + reset(); + return; } + // Unset all clients desired sources. Except the tutors desired source, this has to be the selecteds frame + for (QList::iterator it(_clientFrames.begin()); it != _clientFrames.end(); ++it) + if ((*it)->client() != NULL){ + (*it)->client()->setDesiredProjectionSource(getTutorFrame()->client()->id() == (*it)->client()->id() ? getSelectedFrame()->client()->id():NO_SOURCE); + qDebug() << "ID" <<(*it)->client()->id() << "ds" << (*it)->client()->desiredProjectionSource() <<"ps"<< (*it)->client()->projectionSource(); +} + DisableButtons(); + _mode = Mode::Unicast; startVncServerIfNecessary(getSelectedFrame()->client()->id()); } } @@ -802,7 +793,8 @@ void MainWindow::onButtonStudentToTutorExclusive() // If this is the first run in this mode set the tutor as watcher for (QList::iterator it(_clientFrames.begin()); it != _clientFrames.end(); ++it) if ((*it)->client() != NULL) - (*it)->client()->setWatcher(getTutorFrame()->client()->id() == (*it)->client()->id()); + // Unset all but tutors desired projection, which is student + (*it)->client()->setDesiredProjectionSource(getTutorFrame()->client()->id() == (*it)->client()->id() ? getSelectedFrame()->client()->id():NO_SOURCE); _mode = Mode::LockedUnicast; } else @@ -1062,46 +1054,34 @@ void MainWindow::onVncServerStateChange(Client* client) if (client->isActiveVncServer()) { - if (_mode == Mode::Broadcast) - { - for (QList::iterator it(_clientFrames.begin()); it != _clientFrames.end(); ++it) - { - if ((*it)->client() != NULL) - { - // Unlock all online clients - (*it)->client()->lockScreen(false); - - // Start VNCclients on all online clients but source - if ((*it)->client() != client) - (*it)->client()->startVncClient(client); - } - } - } - else // !Mode::Broadcast --> Mode::LockedMC || Mode::MC +// if (_mode == Mode::Broadcast) +// { +// for (QList::iterator it(_clientFrames.begin()); it != _clientFrames.end(); ++it) +// { +// if ((*it)->client() != NULL) +// { +// // Unlock all online clients +// (*it)->client()->lockScreen(false); + +// // Start VNCclients on all online clients but source +// if ((*it)->client() != client) +// (*it)->client()->startVncClient(client); +// } +// } +// } +// else { + // apply the desired projection sources for (QList::iterator it(_clientFrames.begin()); it != _clientFrames.end(); ++it) { // Ignore offline clients if ( (*it)->client() != NULL) { - // if (_watchers.contains((*it)->client()->id())) - if ((*it)->client()->isWatcher()) - { - // Unlock destination and connect VNCclient - (*it)->client()->lockScreen(false); + qDebug() << "ID" <<(*it)->client()->id() << "ds" << (*it)->client()->desiredProjectionSource() <<"ps"<< (*it)->client()->projectionSource(); + if ( (*it)->client()->desiredProjectionSource() == client->id() ) (*it)->client()->startVncClient(client); - } - else if ((*it)->client()->id() == client->id() ) - { - // Unlock source - (*it)->client()->lockScreen(false); - } - else - { - // Lock others and stop their clients - (*it)->client()->lockScreen(_mode == Mode::LockedUnicast); - (*it)->client()->stopVncClient(); - } + + (*it)->client()->lockScreen((*it)->client()->desiredProjectionSource() == NO_SOURCE && _mode == Mode::LockedUnicast); } } } @@ -1109,15 +1089,16 @@ void MainWindow::onVncServerStateChange(Client* client) else { // VNC server stopped on some client or failed to start - reset local pending projection information - // foreach (Client *c, _watchers) { - // c->stopVncClient(); - // } for (QList::iterator it(_clientFrames.begin()); it != _clientFrames.end(); ++it) { if ((*it)->client() != NULL) { - if ((*it)->client()->isWatcher()) + if ((*it)->client()->desiredProjectionSource() == client->id()) { + (*it)->client()->setDesiredProjectionSource(NO_SOURCE); (*it)->client()->stopVncClient(); + if (_mode == Mode::LockedUnicast) + (*it)->client()->lockScreen(true); + } } } } @@ -1135,11 +1116,10 @@ void MainWindow::onVncClientStateChange(Client* client) { // VNC Client stopped -> remove from watchers if (!client->isActiveVncClient()){ - if (getClientFromId(client->id()) != NULL) - getClientFromId(client->id())->setWatcher(false); + // client->setDesiredProjectionSource(NO_SOURCE); /* - * If noboody is watching the multicast stop VNC server + * If nobody is watching the multicast stop VNC server * If the past connection of this client is not the current * _streamingSource then the manager has to have stopped it * already. This is necessary for the race condition when a server diff --git a/src/server/net/client.h b/src/server/net/client.h index 61b6a5b..6dbb5bd 100644 --- a/src/server/net/client.h +++ b/src/server/net/client.h @@ -10,6 +10,8 @@ //class QSslSocket; +#define NO_SOURCE 0 + struct ClientLogin { bool accept; @@ -33,15 +35,22 @@ public: inline const QString& host() const { return _host; } inline const QString ip() const { return _socket->peerAddress().toString(); } inline const int id() const { return _id; } + inline const int desiredProjectionSource(){ return _desiredSource; } inline const int projectionSource() const { return _projectionSource; } inline const bool isActiveVncClient() const { return _isActiveVncClient; } inline const bool isActiveVncServer() const { return _vncPort > 0; } inline const bool isLocked() const { return _locked; } - inline const bool isWatcher() const { return _isWatcher; } + inline const bool isWatcher() const { return _desiredSource != 0; } + + // Setters inline void setTutor(bool enable){ _isTutor = enable; } inline void setWatcher(bool enable){ _isWatcher = enable; } + inline void setDesiredProjectionSource(int id){ + qDebug() << "ID" <<_id << " new source " << _desiredSource; + _desiredSource = id; + } //Send message stuff void startVncServer(); @@ -65,7 +74,8 @@ private: int _id; // this client's unique id QString _vncRwPass, _vncRoPass; int _vncPort; // VNCserver state. Greater 0 -> active on this port. Equals 0 -> no server. - int _projectionSource; // VNCclient state. The source the client was or is connected to (depends on _isActiveVncClient) + int _desiredSource; // The source the client shall be connected to + int _projectionSource; // The source the client was or is connected to (depends on _isActiveVncClient) bool _isActiveVncClient; // VNCclient state. indicating that the client is displaying a remote screen via VNC bool _isTutor; // Flag indicating that the client has been set as a tutor bool _isWatcher; // Flag indicates that the client should watch to VNC Server. -- cgit v1.2.3-55-g7522