Pool Video Switch v2
Software video switch for distributed remote display in a lecture environment
vncserver.cpp
Go to the documentation of this file.
1 /*
2  * vncserver.cpp
3  *
4  * Created on: 24.01.2013
5  * Author: sr
6  */
7 
8 
9 #include <QGuiApplication>
10 #include <QProcess>
11 #include <QScreen>
12 #include "vncserver.h"
13 #include "../util/util.h"
14 #include "../../shared/util.h"
15 
16 // Remove in future - see util.h
17 #undef errorOccurred
18 
19 VncServer* VncServer::me = nullptr;
20 
26 {
27  if (me == nullptr)
28  me = new VncServer();
29  return me;
30 }
31 
37 static QString makePassword(int len = 10)
38 {
39  QString ret(len, Qt::Uninitialized);
40  for (int i = 0; i < len; ++i)
41  ret[i] = QChar(43 + slxrand() % 80);
42  return ret;
43 }
44 
48 struct Sleeper : public QThread {
49  static void msleep(unsigned long msecs) { QThread::msleep(msecs); }
50 };
51 
55 VncServer::VncServer() : _process(nullptr), _port(0), _timerId(0) {}
56 
60 VncServer::~VncServer() = default;
61 
62 QSharedPointer<QFile> VncServer::createPwFile(const QDir& dir)
63 {
64  QDir::root().mkpath(dir.absolutePath());
65  QString str(dir.absoluteFilePath("vncpass"));
66  QSharedPointer<QFile> file = QSharedPointer<QFile>(new QFile(str));
67  if (file->exists()) {
68  file->remove();
69  }
70  file->open(QIODevice::WriteOnly);
71  return file;
72 }
73 
78 {
79  // Keep things clean
80  if (_process != nullptr) {
81  _process->blockSignals(true);
82  _process->kill();
83  }
84  this->stop();
85  // Generate passwords
88  // Create new password file
89  QSharedPointer<QFile> pwhandle = createPwFile(Util::settingsDir());
90  if (!pwhandle->isOpen()) {
91  pwhandle = createPwFile(QDir("/tmp"));
92  }
93  if (!pwhandle->isOpen()) {
94  qDebug() << "Could not open " << pwhandle->fileName() << " for writing";
95  emit started(0, _ropass, _rwpass);
96  return;
97  }
98  pwhandle->setPermissions(QFile::ReadOwner | QFile::WriteOwner);
99  pwhandle->write(_rwpass.toUtf8().constData());
100  pwhandle->write("\n");
101  pwhandle->write(_ropass.toUtf8().constData());
102  pwhandle->write("\n");
103  pwhandle->close();
104  // Create new process
105  _process = new QProcess(this);
106  connect(_process, &QProcess::readyReadStandardOutput, this, &VncServer::onStdOut);
107  connect(_process, &QProcess::readyReadStandardError, this, &VncServer::onStdErr);
108  connect(_process, &QProcess::errorOccurred, this, &VncServer::onError);
109  connect(_process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
110  this, &VncServer::onFinished);
111  _timerId = startTimer(4000);
112  QStringList args;
113  args << "-forever";
114  args << "-display" << ":0";
115  args << "-passwdfile" << (QStringLiteral("rm:") + pwhandle->fileName());
116  args << "-shared";
117  args << "-repeat";
118  args << "-autoport" << QString::number(54112);
119 
120  // Get rect of primary screen
121  const QRect primaryRect = QGuiApplication::primaryScreen()->geometry();
122 
123  // Tell x11vnc to just use primary screen
124  args << "-clip";
125  QString rect;
126  rect = QString::number(primaryRect.width())
127  + "x" + QString::number(primaryRect.height())
128  + "+" + QString::number(primaryRect.x())
129  + "+" + QString::number(primaryRect.y());
130  args << rect;
131 
132  qDebug() << "Arguments are: " << args;
133  _process->start("x11vnc", args, QIODevice::ReadOnly);
134 }
135 
140 {
141  if (_timerId != 0) {
142  killTimer(_timerId);
143  _timerId = 0;
144  }
145  if (_process == nullptr)
146  return;
147  qDebug("Stopping old VNC server.");
148  disconnect(_process, &QProcess::readyReadStandardOutput, this, &VncServer::onStdOut);
149  disconnect(_process, &QProcess::readyReadStandardError, this, &VncServer::onStdErr);
150  QProcess *process = _process;
151  _process = nullptr;
152  _port = 0;
153  process->terminate();
154  for (int i = 0; i < 10 && process->state() != QProcess::NotRunning; ++i)
155  Sleeper::msleep(10);
156  if (process->state() == QProcess::Running)
157  process->kill();
158  for (int i = 0; i < 10 && process->state() != QProcess::NotRunning; ++i)
159  Sleeper::msleep(10);
160  process->deleteLater();
161 }
162 
163 
164 /*
165  * Overrides
166  */
167 
168 
174 void VncServer::timerEvent(QTimerEvent * /* event */ )
175 {
176  // Error timeout (3s), tell server that vnc setup failed
177  this->stop();
178  emit started(0, _ropass, _rwpass);
179 }
180 
181 
182 /*
183  * Slots
184  */
185 
186 
191 {
192  if (_process == nullptr) {
193  qDebug("VncServer::onStdOut() called in bad state.");
194  return;
195  }
196  QByteArray data(_process->readAllStandardOutput());
197  qDebug() << "x11vnc: " << data;
198  if (_port <= 0) {
199  const int pos = data.indexOf("PORT=", 0);
200  if (pos != -1) {
201  _port = atoi(data.constData() + pos + 5);
202  qDebug() << "Got VNC port " << _port << ", ro " << _ropass << ", rw " << _rwpass;
203  emit started(_port, _ropass, _rwpass);
204  // Kill error timer, but only if port seemed valid
205  if (_timerId != 0 && _port > 0) {
206  killTimer(_timerId);
207  _timerId = 0;
208  }
209  }
210  }
211 }
212 
217 {
218  if (_process == nullptr) {
219  qDebug("VncServer::onStdErr() called in bad state.");
220  return;
221  }
222  _process->readAllStandardError(); // Throw away
223 }
224 
229 void VncServer::onError(QProcess::ProcessError /* error */ )
230 {
231  this->stop();
232  emit started(0, _ropass, _rwpass);
233 }
234 
239 void VncServer::onFinished(int /* exitCode */, QProcess::ExitStatus /* exitStatus */)
240 {
241  this->stop();
242  emit started(0, _ropass, _rwpass);
243 }
void stop()
VncServer::stop.
Definition: vncserver.cpp:139
void started(int port, const QString &ropass, const QString &rwpass)
QProcess * _process
Definition: vncserver.h:21
void onStdOut()
VncServer::onStdOut.
Definition: vncserver.cpp:190
int _port
Definition: vncserver.h:24
void onFinished(int exitCode, QProcess::ExitStatus exitStatus)
VncServer::onFinished.
Definition: vncserver.cpp:239
static VncServer * me
Definition: vncserver.h:31
~VncServer() override
VncServer::~VncServer.
QString _rwpass
Definition: vncserver.h:23
#define slxrand()
Definition: util.h:19
Ugly hack to get an el-cheapo platform independent sleep.
Definition: vncserver.cpp:48
void start()
VncServer::start.
Definition: vncserver.cpp:77
static QSharedPointer< QFile > createPwFile(const QDir &dir)
Definition: vncserver.cpp:62
QDir settingsDir()
Definition: util.cpp:15
int _timerId
Definition: vncserver.h:25
void timerEvent(QTimerEvent *event) override
Timer event, currently only used to assume VNC server setup failed after 3 seconds...
Definition: vncserver.cpp:174
void onStdErr()
VncServer::onStdErr.
Definition: vncserver.cpp:216
static QString makePassword(int len=10)
makePassword
Definition: vncserver.cpp:37
void onError(QProcess::ProcessError error)
VncServer::onError.
Definition: vncserver.cpp:229
static void msleep(unsigned long msecs)
Definition: vncserver.cpp:49
VncServer()
VncServer::VncServer.
Definition: vncserver.cpp:55
QString _ropass
Definition: vncserver.h:22
static VncServer * instance()
VncServer::instance.
Definition: vncserver.cpp:25