summaryrefslogblamecommitdiffstats
path: root/src/client/vnc/vncserver.cpp
blob: 77beda2d68a5316108c612e60b8ef9588426c963 (plain) (tree)
1
2
3
4
5
6
7
8
9






                          

                       
                   
                         


                         

                                



                                                                                






                                     




                                                                                







                                            


                                                                                

                               
                                                                           

  



                                                                                
 



                                                                                
 


                                                                                








































                                                                                                                         

                    
                                                      

                                     

                                                           









                                                                      
                                              
                                                             

 


                                                                                
























                                                                                        
 
  


            


                                                                                
                     
               
   






                                                                
 
  


        



                                                                                


























                                                                                                         


                                                                                









                                                                     



                                                                                





                                                     



                                                                                




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


#include <QApplication>
#include <QProcess>
#include <QDesktopWidget>
#include "vncserver.h"
#include "../util/util.h"

VncServer* VncServer::me = NULL;

/***************************************************************************//**
 * @brief VncServer::instance
 * @return
 */
VncServer* VncServer::instance()
{
	if (me == NULL)
		me = new VncServer();
	return me;
}

/***************************************************************************//**
 * @brief makePassword
 * @param len
 * @return
 */
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);
}

/***************************************************************************//**
 * @brief Ugly hack to get an el-cheapo platform independent sleep
 */
struct Sleeper : public QThread
{
	static void msleep(unsigned long msecs) { QThread::msleep(msecs); }
};

/***************************************************************************//**
 * @brief VncServer::VncServer
 */
VncServer::VncServer() : _process(NULL), _port(0), _timerId(0){}

/***************************************************************************//**
 * @brief VncServer::~VncServer
 */
VncServer::~VncServer(){}

/***************************************************************************//**
 * @brief VncServer::start
 */
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
	const QDesktopWidget desktop;
	const QRect primaryRect = desktop.screenGeometry();

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

/***************************************************************************//**
 * @brief VncServer::stop
 */
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
 */


/***************************************************************************//**
 * @brief Timer event, currently only used to assume VNC server setup failed
 * after 3 seconds...
 * @param event
 */
void VncServer::timerEvent(QTimerEvent *event)
{
	// Error timeout (3s), tell server that vnc setup failed
	this->stop();
	emit started(0, _ropass, _rwpass);
}


/*
 * Slots
 */


/***************************************************************************//**
 * @brief VncServer::onStdOut
 */
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;
			}
		}
	}
}

/***************************************************************************//**
 * @brief VncServer::onStdErr
 */
void VncServer::onStdErr()
{
	if (_process == NULL)
	{
		qDebug("VncServer::onStdErr() called in bad state.");
		return;
	}
	QByteArray data(_process->readAllStandardError());
}

/***************************************************************************//**
 * @brief VncServer::onError
 * @param error
 */
void VncServer::onError(QProcess::ProcessError error)
{
	this->stop();
	emit started(0, _ropass, _rwpass);
}

/***************************************************************************//**
 * @brief VncServer::onFinished
 * @param exitCode
 */
void VncServer::onFinished(int exitCode)
{
	this->stop();
	emit started(0, _ropass, _rwpass);
}