/* * vncserver.cpp * * Created on: 24.01.2013 * Author: sr */ #include #include #include #include "vncserver.h" #include "../util/util.h" /******************************************* * STATIC *******************************************/ VncServer* VncServer::me = NULL; VncServer* VncServer::instance() { if (me == NULL) me = new VncServer(); return me; } // static QString makePassword(int len = 10) { char pass[len]; for (int i = 0; i < len; ++i) pass[i] = 43 + qrand() % 80; return QString::fromUtf8(pass, len); } // Ugly hack to get an el-cheapo platform independent sleep struct Sleeper : public QThread { static void msleep(unsigned long msecs) { QThread::msleep(msecs); } }; /******************************************* * INSTANCE *******************************************/ VncServer::VncServer() : _process(NULL), _port(0), _timerId(0) { // TODO Auto-generated constructor stub } VncServer::~VncServer() { // TODO Auto-generated destructor stub } bool VncServer::isVncServerRunning() { if (_port > 0) return true; return false; } void VncServer::start() { // Keep things clean if (_process != NULL) { disconnect(_process, SIGNAL(error(QProcess::ProcessError)), this, SLOT(onError(QProcess::ProcessError))); disconnect(_process, SIGNAL(finished(int)), this, SLOT(onFinished(int))); } this->stop(); // Generate passwords _rwpass = makePassword(); _ropass = makePassword(); // Create new password file QDir path = Util::settingsDir(); QString pwfile(path.absoluteFilePath("vncpass")); QFile pwhandle(pwfile); if (pwhandle.exists()) pwhandle.remove(); if (!pwhandle.open(QIODevice::WriteOnly)) { qDebug() << "Could not open " << pwfile << " for writing"; emit started(0, _ropass, _rwpass); return; } pwhandle.setPermissions(QFile::ReadOwner | QFile::WriteOwner); pwhandle.write(_rwpass.toUtf8().constData()); pwhandle.write("\n"); pwhandle.write(_ropass.toUtf8().constData()); pwhandle.write("\n"); pwhandle.close(); // Create new process _process = new QProcess(this); connect(_process, SIGNAL(readyReadStandardOutput()), this, SLOT(onStdOut())); connect(_process, SIGNAL(readyReadStandardError()), this, SLOT(onStdErr())); connect(_process, SIGNAL(error(QProcess::ProcessError)), this, SLOT(onError(QProcess::ProcessError))); connect(_process, SIGNAL(finished(int)), this, SLOT(onFinished(int))); _timerId = startTimer(4000); QStringList args; args << "-forever"; args << "-display" << ":0"; args << "-passwdfile" << (QString("rm:" + pwfile)); args << "-shared"; args << "-repeat"; args << "-autoport" << QString::number(54112); // Get rect of primary screen int primary = QApplication::desktop()->primaryScreen(); QRect primaryRect = QApplication::desktop()->availableGeometry(primary); // Tell x11vnc to just use primary screen args << "-clip"; QString rect; rect = QString::number(primaryRect.width()) + "x" + QString::number(primaryRect.height()) + "+" + QString::number(primaryRect.x()) + "+" + QString::number(primaryRect.y()); args << rect; qDebug() << "Arguments are: " << args; _process->start("x11vnc", args, QIODevice::ReadOnly); } void VncServer::stop() { if (_timerId != 0) { killTimer(_timerId); _timerId = 0; } if (_process == NULL) return; qDebug("Stopping old VNC server."); disconnect(_process, SIGNAL(readyReadStandardOutput()), this, SLOT(onStdOut())); disconnect(_process, SIGNAL(readyReadStandardError()), this, SLOT(onStdErr())); QProcess *process = _process; _process = NULL; _port = 0; process->terminate(); for (int i = 0; i < 10 && process->state() != QProcess::NotRunning; ++i) Sleeper::msleep(10); if (process->state() == QProcess::Running) process->kill(); for (int i = 0; i < 10 && process->state() != QProcess::NotRunning; ++i) Sleeper::msleep(10); process->deleteLater(); } /* * Overrides */ /** * Timer event, currently only used to assume VNC server setup failed * after 3 seconds... */ void VncServer::timerEvent(QTimerEvent *event) { // Error timeout (3s), tell server that vnc setup failed this->stop(); emit started(0, _ropass, _rwpass); } /* * Slots */ void VncServer::onStdOut() { if (_process == NULL) { qDebug("VncServer::onStdOut() called in bad state."); return; } QByteArray data(_process->readAllStandardOutput()); qDebug() << "x11vnc: " << data; if (_port <= 0) { const int pos = data.indexOf("PORT=", 0); if (pos != -1) { _port = atoi(data.constData() + pos + 5); qDebug() << "Got VNC port " << _port << ", ro " << _ropass << ", rw " << _rwpass; emit started(_port, _ropass, _rwpass); // Kill error timer, but only if port seemed valid if (_timerId != 0 && _port > 0) { killTimer(_timerId); _timerId = 0; } } } } void VncServer::onStdErr() { if (_process == NULL) { qDebug("VncServer::onStdErr() called in bad state."); return; } QByteArray data(_process->readAllStandardError()); } void VncServer::onError(QProcess::ProcessError error) { this->stop(); emit started(0, _ropass, _rwpass); } void VncServer::onFinished(int exitCode) { this->stop(); emit started(0, _ropass, _rwpass); }