summaryrefslogblamecommitdiffstats
path: root/src/client/vnc/vncserver.cpp
blob: 2b49b8e58699eff1eaecc35de4f5efc14e086f31 (plain) (tree)






























































































































































































                                                                                                                         
/*
 * vncserver.cpp
 *
 *  Created on: 24.01.2013
 *      Author: sr
 */

#include <QProcess>
#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
}

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 << "-autoport" << QString::number(54112);
	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
 */

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);
}