Make RFB server and COnnectionCOntroller classes abstract and make one implementation of them for the standard rfb use case.

svn path=/trunk/KDE/kdenetwork/krfb/; revision=1189033
This commit is contained in:
George Goldberg
2010-10-23 19:30:32 +00:00
parent 47e2db27de
commit a8da333e3b
12 changed files with 836 additions and 465 deletions

View File

@@ -83,18 +83,20 @@ add_subdirectory (framebuffers)
set(krfb_SRCS
main.cpp
trayicon.cpp
krfbserver.cpp
manageinvitationsdialog.cpp
invitationmanager.cpp
invitedialog.cpp
invitation.cpp
connectiondialog.cpp
personalinvitedialog.cpp
connectioncontroller.cpp
events.cpp
framebuffermanager.cpp
servermanager.cpp
sockethelpers.cpp
abstractrfbserver.cpp
abstractconnectioncontroller.cpp
krfbserver.cpp
krfbconnectioncontroller.cpp
)
kde4_add_kcfg_files(krfb_SRCS krfbconfig.kcfgc)

View File

@@ -0,0 +1,143 @@
/* This file is part of the KDE project
* Copyright (C) 2009 Collabora Ltd <info@collabora.co.uk>
* @author George Goldberg <george.goldberg@collabora.co.uk>
* Copyright (C) 2007 Alessandro Praduroux <pradu@pradu.it>
* Copyright (C) 2001-2003 by Tim Jansen <tim@tjansen.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
// RFB.H Why do you have to redefine the whole of fscking c++???
#include <KDebug>
#include "abstractconnectioncontroller.h"
#include "abstractrfbserver.h"
#include "connectiondialog.h"
#include "events.h"
#include <string.h>
static void clientGoneHook(rfbClientPtr cl)
{
AbstractConnectionController *cc = static_cast<AbstractConnectionController *>(cl->clientData);
cc->handleClientGone();
}
bool checkPassword(const QString &p, unsigned char *ochallenge, const char *response, int len)
{
if ((len == 0) && (p.length() == 0)) {
return true;
}
char passwd[MAXPWLEN];
unsigned char challenge[CHALLENGESIZE];
memcpy(challenge, ochallenge, CHALLENGESIZE);
bzero(passwd, MAXPWLEN);
if (!p.isNull()) {
strncpy(passwd, p.toLatin1(),
(MAXPWLEN <= p.length()) ? MAXPWLEN : p.length());
}
rfbEncryptBytes(challenge, passwd);
return memcmp(challenge, response, len) == 0;
}
AbstractConnectionController::AbstractConnectionController(struct _rfbClientRec *_cl,
AbstractRfbServer *parent)
: QObject(parent),
cl(_cl)
{
kDebug();
// Set the rfbClientRec client data to point to this ConnectionController so the callbacks
// can get the right object.
cl->clientData = (void*)this;
// Set the client gone hook. The ConnectionController is responsible for determining what
// actions to take based on the state of the client in handleClientGone().
cl->clientGoneHook = clientGoneHook;
}
AbstractConnectionController::~AbstractConnectionController()
{
kDebug();
}
void AbstractConnectionController::dialogAccepted()
{
ConnectionDialog *dialog = qobject_cast<ConnectionDialog*>(sender());
if (!dialog) {
kWarning() << "Wrong type of sender.";
return;
}
// rfbStartOnHoldClient(cl);
cl->onHold = false;
setControlEnabled(dialog->cbAllowRemoteControl->isChecked());
setControlCanBeEnabled(dialog->cbAllowRemoteControl->isChecked());
emit sessionEstablished(remoteIp);
}
void AbstractConnectionController::dialogRejected()
{
kDebug() << "refused connection";
rfbRefuseOnHoldClient(cl);
}
void AbstractConnectionController::handleKeyEvent(bool down, rfbKeySym keySym)
{
if (controlEnabled) {
KeyboardEvent ev(down, keySym);
ev.exec();
}
}
void AbstractConnectionController::handlePointerEvent(int bm, int x, int y)
{
if (controlEnabled) {
PointerEvent ev(bm, x, y);
ev.exec();
}
}
void AbstractConnectionController::clipboardToServer(const QString &s)
{
ClipboardEvent ev(this, s);
ev.exec();
}
void AbstractConnectionController::setControlEnabled(bool enable)
{
if (m_controlCanBeEnabled) {
controlEnabled = enable;
}
}
void AbstractConnectionController::setControlCanBeEnabled(bool canBeEnabled)
{
m_controlCanBeEnabled = canBeEnabled;
}
bool AbstractConnectionController::controlCanBeEnabled() const
{
return m_controlCanBeEnabled;
}
#include "abstractconnectioncontroller.moc"

View File

@@ -0,0 +1,72 @@
/* This file is part of the KDE project
* Copyright (C) 2009 Collabora Ltd <info@collabora.co.uk>
* @author George Goldberg <george.goldberg@collabora.co.uk>
* Copyright (C) 2007 Alessandro Praduroux <pradu@pradu.it>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef KRFB_ABSTRACTCONNECTIONCONTROLLER_H
#define KRFB_ABSTRACTCONNECTIONCONTROLLER_H
#include <QtCore/QObject>
#include <rfb/rfb.h>
class AbstractRfbServer;
bool checkPassword(const QString &p, unsigned char *ochallenge, const char *response, int len);
class AbstractConnectionController : public QObject
{
Q_OBJECT
public:
AbstractConnectionController(struct _rfbClientRec *_cl, AbstractRfbServer *parent);
virtual ~AbstractConnectionController();
virtual bool handleCheckPassword(rfbClientPtr cl, const char *response, int len) = 0;
virtual void handleKeyEvent(bool down, rfbKeySym keySym);
virtual void handlePointerEvent(int bm, int x, int y);
virtual void handleClientGone() = 0;
virtual void clipboardToServer(const QString &);
virtual enum rfbNewClientAction handleNewClient() = 0;
virtual void setControlEnabled(bool enable);
virtual void setControlCanBeEnabled(bool canBeEnabled);
virtual bool controlCanBeEnabled() const;
Q_SIGNALS:
void sessionEstablished(QString);
void clientDisconnected(AbstractConnectionController *);
protected Q_SLOTS:
void dialogAccepted();
void dialogRejected();
protected:
QString remoteIp;
struct _rfbClientRec *cl;
bool controlEnabled;
bool m_controlCanBeEnabled;
};
#endif // Header Guard

386
abstractrfbserver.cpp Normal file
View File

@@ -0,0 +1,386 @@
/* This file is part of the KDE project
* Copyright (C) 2009 Collabora Ltd <info@collabora.co.uk>
* @author George Goldberg <george.goldberg@collabora.co.uk>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
// FUCKING RFB.H DIE DAMMIT
#include "servermanager.h"
#include "abstractrfbserver.h"
#include "abstractconnectioncontroller.h"
#include "framebuffer.h"
#include "invitationmanager.h"
#include "krfbconfig.h"
#include "sockethelpers.h"
#include <QtCore/QPointer>
#include <QtCore/QSharedPointer>
#include <QtCore/QTimer>
#include <KDebug>
#include <KLocale>
#include <KMessageBox>
#include <X11/Xutil.h>
#include <X11/extensions/XTest.h>
static const char* cur=
" "
" x "
" xx "
" xxx "
" xxxx "
" xxxxx "
" xxxxxx "
" xxxxxxx "
" xxxxxxxx "
" xxxxxxxxx "
" xxxxxxxxxx "
" xxxxx "
" xx xxx "
" x xxx "
" xxx "
" xxx "
" xxx "
" xxx "
" ";
static const char* mask=
"xx "
"xxx "
"xxxx "
"xxxxx "
"xxxxxx "
"xxxxxxx "
"xxxxxxxx "
"xxxxxxxxx "
"xxxxxxxxxx "
"xxxxxxxxxxx "
"xxxxxxxxxxxx "
"xxxxxxxxxx "
"xxxxxxxx "
"xxxxxxxx "
"xx xxxxx "
" xxxxx "
" xxxxx "
" xxxxx "
" xxx ";
static rfbCursorPtr myCursor;
static enum rfbNewClientAction newClientHook(struct _rfbClientRec *cl)
{
AbstractRfbServer *server = ServerManager::instance()->serverForClient(cl);
return server->handleNewClient(cl);
}
static rfbBool passwordCheck(rfbClientPtr cl,
const char* encryptedPassword,
int len)
{
AbstractConnectionController *cc = static_cast<AbstractConnectionController *>(cl->clientData);
return cc->handleCheckPassword(cl, encryptedPassword, len);
}
static void keyboardHook(rfbBool down, rfbKeySym keySym, rfbClientPtr cl)
{
AbstractConnectionController *cc = static_cast<AbstractConnectionController *>(cl->clientData);
cc->handleKeyEvent(down ? true : false, keySym);
}
static void pointerHook(int bm, int x, int y, rfbClientPtr cl)
{
AbstractConnectionController *cc = static_cast<AbstractConnectionController *>(cl->clientData);
cc->handlePointerEvent(bm, x, y);
}
static void clipboardHook(char* str,int len, rfbClientPtr cl)
{
AbstractConnectionController *cc = static_cast<AbstractConnectionController *>(cl->clientData);
cc->clipboardToServer(QString::fromUtf8(str, len));
}
class AbstractRfbServer::AbstractRfbServerPrivate {
public:
AbstractRfbServerPrivate()
: port(0), screen(0), numClients(0), listeningPort(0),
passwordRequired(true)
{
address = "0.0.0.0";
desktopName = "Shared Desktop";
}
// Parameters for startListening();
QByteArray address;
int port;
QSharedPointer<FrameBuffer> fb;
rfbScreenInfoPtr screen;
QByteArray desktopName;
QTimer rfbProcessEventTimer;
int numClients;
QList< QPointer<AbstractConnectionController> > controllers;
QString listeningAddress;
unsigned int listeningPort;
bool passwordRequired;
};
AbstractRfbServer::AbstractRfbServer()
: d(new AbstractRfbServerPrivate)
{
kDebug();
}
AbstractRfbServer::~AbstractRfbServer()
{
kDebug();
delete d;
}
void AbstractRfbServer::startListening()
{
if (d->fb.isNull()) {
kWarning() << "Cannot start a rfb server without a valid framebuffer.";
return;
}
rfbScreenInfoPtr screen;
int w = d->fb->width();
int h = d->fb->height();
int depth = d->fb->depth();
int bpp = depth >> 3;
if (bpp != 1 && bpp != 2 && bpp != 4) bpp = 4;
kDebug() << "bpp: " << bpp;
rfbLogEnable(0);
screen = rfbGetScreen(0, 0, w, h, 8, 3, bpp);
screen->paddedWidthInBytes = d->fb->paddedWidth();
d->fb->getServerFormat(screen->serverFormat);
screen->frameBuffer = d->fb->data();
d->screen = screen;
if (d->address != "0.0.0.0") {
d->address.resize(254);
strcpy(screen->thisHost, d->address.data());
}
if (d->port == 0) {
screen->autoPort = 1;
}
screen->port = d->port;
// Disable/Enable password checking
if (d->passwordRequired) {
d->screen->authPasswdData = (void *)1;
} else {
d->screen->authPasswdData = (void *)0;
}
// server hooks
screen->newClientHook = newClientHook;
screen->kbdAddEvent = keyboardHook;
screen->ptrAddEvent = pointerHook;
screen->newClientHook = newClientHook;
screen->passwordCheck = passwordCheck;
screen->setXCutText = clipboardHook;
screen->desktopName = d->desktopName.constData();
if (!myCursor) {
myCursor = rfbMakeXCursor(19, 19, (char*) cur, (char*) mask);
}
screen->cursor = myCursor;
rfbInitServer(screen);
if (!rfbIsActive(screen)) {
KMessageBox::error(0,i18n("Address already in use"),"krfb");
shutdown();
qApp->quit();
return;
};
d->listeningPort = localPort(screen->listenSock);
d->listeningAddress = localAddress(screen->listenSock);
kDebug() << "Listen port:" << d->listeningPort << "Listen Address:" << d->listeningAddress;
/* Integrate the rfb event mechanism with qt's event loop.
* Call processRfbEvents() every time the qt event loop is run,
* so that it also processes and delivers rfb events and call
* shutdown() when QApplication exits to shutdown the rfb server
* before the X11 connection goes down.
*/
connect(&d->rfbProcessEventTimer, SIGNAL(timeout()), SLOT(processRfbEvents()));
connect(qApp, SIGNAL(aboutToQuit()), SLOT(shutdown()));
d->rfbProcessEventTimer.start(0);
}
void AbstractRfbServer::setListeningAddress(const QByteArray &address)
{
d->address = address;
}
void AbstractRfbServer::setListeningPort(int port)
{
d->port = port;
}
void AbstractRfbServer::setFrameBuffer(QSharedPointer<FrameBuffer> frameBuffer)
{
d->fb = frameBuffer;
}
void AbstractRfbServer::setDesktopName(const QByteArray &desktopName)
{
d->desktopName = desktopName;
}
void AbstractRfbServer::setPasswordRequired(bool passwordRequired)
{
d->passwordRequired = passwordRequired;
}
void AbstractRfbServer::processRfbEvents()
{
foreach(const QRect &r, d->fb->modifiedTiles()) {
rfbMarkRectAsModified(d->screen, r.x(), r.y(), r.right(), r.bottom());
}
rfbProcessEvents(d->screen, 100);
}
void AbstractRfbServer::shutdown()
{
rfbShutdownServer(d->screen, true);
d->fb.clear();
d->listeningPort = 0;
d->listeningAddress.clear();
}
QString AbstractRfbServer::listeningAddress() const
{
return d->listeningAddress;
}
unsigned int AbstractRfbServer::listeningPort() const
{
kDebug() << "Stored listening port:" << d->listeningPort;
if (d->screen && d->screen->listenSock) {
kDebug() << "Actual listening port:" << localPort(d->screen->listenSock);
kDebug() << d->screen->thisHost;
}
return d->listeningPort;
}
bool AbstractRfbServer::checkX11Capabilities() {
int bp1, bp2, majorv, minorv;
Bool r = XTestQueryExtension(QX11Info::display(), &bp1, &bp2,
&majorv, &minorv);
if ((!r) || (((majorv*1000)+minorv) < 2002)) {
KMessageBox::error(0,
i18n("Your X11 Server does not support the required XTest extension version 2.2. Sharing your desktop is not possible."),
i18n("Desktop Sharing Error"));
return false;
}
return true;
}
void AbstractRfbServer::updatePassword()
{
if (!d->screen) return;
QString pw = KrfbConfig::uninvitedConnectionPassword();
kDebug() << "password: " << pw << " allow " <<
KrfbConfig::allowUninvitedConnections() <<
" invitations " << InvitationManager::self()->activeInvitations() << endl;
if (pw.isEmpty() && InvitationManager::self()->activeInvitations() == 0) {
kDebug() << "no password from now on";
d->screen->authPasswdData = (void *)0;
} else {
kDebug() << "Ask for password to accept connections";
d->screen->authPasswdData = (void *)1;
}
}
void AbstractRfbServer::clientDisconnected(AbstractConnectionController *cc)
{
kDebug() << "clients--: " << d->numClients;
if (!--d->numClients) {
d->fb->stopMonitor();
kDebug() << "stopMonitor: d->numClients = " << d->numClients;
}
disconnect(cc, SIGNAL(clientDisconnected(AbstractConnectionController*)),this, SLOT(clientDisconnected(AbstractConnectionController*)));
Q_EMIT sessionFinished();
}
void AbstractRfbServer::enableDesktopControl(bool enable)
{
foreach (QPointer<AbstractConnectionController> ptr, d->controllers) {
if (ptr) {
if (ptr->controlCanBeEnabled()) {
ptr->setControlEnabled(enable);
}
}
}
}
void AbstractRfbServer::appendController(AbstractConnectionController *c)
{
d->controllers.append(c);
}
int AbstractRfbServer::numClients() const
{
return d->numClients;
}
void AbstractRfbServer::incrementNumClients()
{
d->numClients++;
}
void AbstractRfbServer::startFrameBufferMonitor()
{
d->fb->startMonitor();
}
void AbstractRfbServer::addController(AbstractConnectionController *cc)
{
if (d->numClients++ == 0)
d->fb->startMonitor();
d->controllers.append(cc);
}
#include "abstractrfbserver.moc"

87
abstractrfbserver.h Normal file
View File

@@ -0,0 +1,87 @@
/* This file is part of the KDE project
* Copyright (C) 2009 Collabora Ltd <info@collabora.co.uk>
* @author George Goldberg <george.goldberg@collabora.co.uk>
* Copyright (C) 2007 Alessandro Praduroux <pradu@pradu.it>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef KRFB_ABSTRACTRFBSERVER_H
#define KRFB_ABSTRACTRFBSERVER_H
#include "framebuffer.h"
#include <QtCore/QObject>
#include <QtCore/QSharedPointer>
#include <rfb/rfb.h>
class AbstractConnectionController;
class AbstractRfbServer : public QObject
{
Q_OBJECT
friend class ServerManager;
public:
virtual ~AbstractRfbServer();
virtual enum rfbNewClientAction handleNewClient(struct _rfbClientRec *cl) = 0;
virtual bool checkX11Capabilities();
Q_SIGNALS:
void sessionEstablished(QString);
void sessionFinished();
void desktopControlSettingChanged(bool);
public Q_SLOTS:
virtual void processRfbEvents();
virtual void shutdown();
virtual void enableDesktopControl(bool);
virtual void updateSettings() = 0;
virtual void updatePassword();
virtual void clientDisconnected(AbstractConnectionController *);
virtual QString listeningAddress() const;
virtual unsigned int listeningPort() const;
protected:
AbstractRfbServer();
virtual void setListeningAddress(const QByteArray &address);
virtual void setListeningPort(int port);
virtual void setFrameBuffer(QSharedPointer<FrameBuffer> frameBuffer);
virtual void setDesktopName(const QByteArray &desktopName);
virtual void setPasswordRequired(bool passwordRequired);
virtual void startListening();
virtual void appendController(AbstractConnectionController *c);
virtual int numClients() const;
virtual void startFrameBufferMonitor();
virtual void incrementNumClients();
void addController(AbstractConnectionController *cc);
private:
Q_DISABLE_COPY(AbstractRfbServer)
class AbstractRfbServerPrivate;
AbstractRfbServerPrivate * const d;
};
#endif // Header guard

View File

@@ -1,68 +0,0 @@
/* This file is part of the KDE project
Copyright (C) 2007 Alessandro Praduroux <pradu@pradu.it>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
*/
#ifndef CONNECTIONCONTROLLER_H
#define CONNECTIONCONTROLLER_H
#include <QObject>
#include <rfb/rfb.h>
class KrfbServer;
/**
@author Alessandro Praduroux <pradu@pradu.it>
*/
class ConnectionController : public QObject
{
Q_OBJECT
public:
ConnectionController(struct _rfbClientRec *_cl, KrfbServer *parent);
~ConnectionController();
bool handleCheckPassword(rfbClientPtr cl, const char *response, int len);
void handleNegotiationFinished(struct _rfbClientRec *cl);
void handleKeyEvent(bool down , rfbKeySym keySym );
void handlePointerEvent( int bm, int x, int y);
void handleClientGone();
void clipboardToServer(const QString &);
enum rfbNewClientAction handleNewClient();
void setControlEnabled(bool enable);
void setControlCanBeEnabled(bool canBeEnabled);
bool controlCanBeEnabled() const;
Q_SIGNALS:
void sessionEstablished(QString);
void notification(QString, QString);
void clientDisconnected(ConnectionController *);
protected Q_SLOTS:
void dialogAccepted();
void dialogRejected();
private:
QString remoteIp;
struct _rfbClientRec *cl;
bool controlEnabled;
bool m_controlCanBeEnabled;
/*
int fd;
KrfbServer *server;
rfbScreenInfoPtr screen;
rfbClientPtr client;
QTcpSocket *tcpConn;
*/
};
#endif

View File

@@ -10,6 +10,8 @@
#include "events.h"
#include "abstractconnectioncontroller.h"
#include <QApplication>
#include <QX11Info>
@@ -171,7 +173,7 @@ void PointerEvent::exec() {
}
ClipboardEvent::ClipboardEvent(ConnectionController *c, const QString &ctext)
ClipboardEvent::ClipboardEvent(AbstractConnectionController *c, const QString &ctext)
:controller(c),text(ctext)
{
}

View File

@@ -17,7 +17,7 @@
#include <X11/Xlib.h>
class ConnectionController;
class AbstractConnectionController;
class QCursor;
@@ -60,10 +60,10 @@ public:
};
class ClipboardEvent : public VNCEvent {
ConnectionController *controller;
AbstractConnectionController *controller;
QString text;
public:
ClipboardEvent(ConnectionController *c, const QString &text);
ClipboardEvent(AbstractConnectionController *c, const QString &text);
virtual void exec();
};

View File

@@ -1,14 +1,26 @@
/* This file is part of the KDE project
Copyright (C) 2009 Collabora Ltd <info@collabora.co.uk>
@author George Goldberg <george.goldberg@collabora.co.uk>
Copyright (C) 2007 Alessandro Praduroux <pradu@pradu.it>
(C) 2001-2003 by Tim Jansen <tim@tjansen.de>
Copyright (C) 2001-2003 by Tim Jansen <tim@tjansen.de>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "connectioncontroller.h"
#include "connectioncontroller.moc"
#include "krfbconnectioncontroller.h"
#include <QX11Info>
#include <QHostInfo>
@@ -35,48 +47,20 @@
#include <X11/Xutil.h>
#include <strings.h>
static void clientGoneHook(rfbClientPtr cl)
KrfbConnectionController::KrfbConnectionController(struct _rfbClientRec *_cl,
AbstractRfbServer * parent)
: AbstractConnectionController(_cl, parent),
m_clientGoneRequiresAction(false)
{
ConnectionController *cc = static_cast<ConnectionController *>(cl->clientData);
cc->handleClientGone();
kDebug();
}
static bool checkPassword(const QString &p, unsigned char *ochallenge, const char *response, int len)
KrfbConnectionController::~KrfbConnectionController()
{
if ((len == 0) && (p.length() == 0)) {
return true;
}
char passwd[MAXPWLEN];
unsigned char challenge[CHALLENGESIZE];
memcpy(challenge, ochallenge, CHALLENGESIZE);
bzero(passwd, MAXPWLEN);
if (!p.isNull()) {
strncpy(passwd, p.toLatin1(),
(MAXPWLEN <= p.length()) ? MAXPWLEN : p.length());
}
rfbEncryptBytes(challenge, passwd);
return memcmp(challenge, response, len) == 0;
kDebug();
}
ConnectionController::ConnectionController(struct _rfbClientRec *_cl, KrfbServer * parent)
: QObject(parent), cl(_cl)
{
cl->clientData = (void*)this;
}
ConnectionController::~ConnectionController()
{
}
enum rfbNewClientAction ConnectionController::handleNewClient()
enum rfbNewClientAction KrfbConnectionController::handleNewClient()
{
kDebug();
@@ -94,7 +78,7 @@ enum rfbNewClientAction ConnectionController::handleNewClient()
// In the remaining cases, the connection will be at least partially established, so we need
// the clientGoneHook to be called when the connection ends.
cl->clientGoneHook = clientGoneHook;
m_clientGoneRequiresAction = true;
if (!askOnConnect) {
KNotification::event("NewConnectionAutoAccepted",
@@ -121,7 +105,7 @@ enum rfbNewClientAction ConnectionController::handleNewClient()
return RFB_CLIENT_ON_HOLD;
}
bool ConnectionController::handleCheckPassword(rfbClientPtr cl, const char *response, int len)
bool KrfbConnectionController::handleCheckPassword(rfbClientPtr cl, const char *response, int len)
{
bool allowUninvited = KrfbConfig::allowUninvitedConnections();
QString password = KrfbConfig::uninvitedConnectionPassword();
@@ -163,70 +147,15 @@ bool ConnectionController::handleCheckPassword(rfbClientPtr cl, const char *resp
return true;
}
void ConnectionController::handleKeyEvent(bool down, rfbKeySym keySym)
void KrfbConnectionController::handleClientGone()
{
if (controlEnabled) {
KeyboardEvent ev(down, keySym);
ev.exec();
if (m_clientGoneRequiresAction) {
emit clientDisconnected(this);
kDebug() << "client gone";
deleteLater();
}
}
void ConnectionController::handlePointerEvent(int bm, int x, int y)
{
if (controlEnabled) {
PointerEvent ev(bm, x, y);
ev.exec();
}
}
void ConnectionController::handleClientGone()
{
emit clientDisconnected(this);
kDebug() << "client gone";
deleteLater();
}
void ConnectionController::clipboardToServer(const QString &s)
{
ClipboardEvent ev(this, s);
ev.exec();
}
void ConnectionController::dialogAccepted()
{
ConnectionDialog *dialog = qobject_cast<ConnectionDialog*>(sender());
if (!dialog) {
kWarning() << "Wrong type of sender.";
return;
}
// rfbStartOnHoldClient(cl);
cl->onHold = false;
setControlEnabled(dialog->cbAllowRemoteControl->isChecked());
setControlCanBeEnabled(dialog->cbAllowRemoteControl->isChecked());
emit sessionEstablished(remoteIp);
}
void ConnectionController::dialogRejected()
{
kDebug() << "refused connection";
rfbRefuseOnHoldClient(cl);
}
void ConnectionController::setControlEnabled(bool enable)
{
controlEnabled = enable;
}
void ConnectionController::setControlCanBeEnabled(bool canBeEnabled)
{
m_controlCanBeEnabled = canBeEnabled;
}
bool ConnectionController::controlCanBeEnabled() const
{
return m_controlCanBeEnabled;
}
#include "krfbconnectioncontroller.moc"

View File

@@ -0,0 +1,47 @@
/* This file is part of the KDE project
Copyright (C) 2009 Collabora Ltd <info@collabora.co.uk>
@author George Goldberg <george.goldberg@collabora.co.uk>
Copyright (C) 2007 Alessandro Praduroux <pradu@pradu.it>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef KRFB_KRFBCONNECTIONCONTROLLER_H
#define KRFB_KRFBCONNECTIONCONTROLLER_H
#include "abstractconnectioncontroller.h"
class KrfbConnectionController : public AbstractConnectionController
{
Q_OBJECT
public:
KrfbConnectionController(struct _rfbClientRec *_cl, AbstractRfbServer *parent);
virtual ~KrfbConnectionController();
virtual bool handleCheckPassword(rfbClientPtr cl, const char *response, int len);
virtual void handleClientGone();
virtual enum rfbNewClientAction handleNewClient();
private:
bool m_clientGoneRequiresAction;
};
#endif // Header Guard

View File

@@ -8,10 +8,14 @@
version 2 of the License, or (at your option) any later version.
*/
// FUCKING RFB.H POS FUCK YOU
#include "servermanager.h"
#include "krfbserver.h"
#include "krfbserver.moc"
#include "krfbconnectioncontroller.h"
#include <QTcpServer>
#include <QTcpSocket>
#include <QTimer>
@@ -27,117 +31,27 @@
#include <KMessageBox>
#include <dnssd/publicservice.h>
#include "connectioncontroller.h"
#include "abstractconnectioncontroller.h"
#include "framebuffer.h"
#include "framebuffermanager.h"
#include "krfbconfig.h"
#include "invitationmanager.h"
#include "servermanager.h"
#include "sockethelpers.h"
#include <X11/Xutil.h>
#include <X11/extensions/XTest.h>
static const char* cur=
" "
" x "
" xx "
" xxx "
" xxxx "
" xxxxx "
" xxxxxx "
" xxxxxxx "
" xxxxxxxx "
" xxxxxxxxx "
" xxxxxxxxxx "
" xxxxx "
" xx xxx "
" x xxx "
" xxx "
" xxx "
" xxx "
" xxx "
" ";
static const char* mask=
"xx "
"xxx "
"xxxx "
"xxxxx "
"xxxxxx "
"xxxxxxx "
"xxxxxxxx "
"xxxxxxxxx "
"xxxxxxxxxx "
"xxxxxxxxxxx "
"xxxxxxxxxxxx "
"xxxxxxxxxx "
"xxxxxxxx "
"xxxxxxxx "
"xx xxxxx "
" xxxxx "
" xxxxx "
" xxxxx "
" xxx ";
static rfbCursorPtr myCursor;
static enum rfbNewClientAction newClientHook(struct _rfbClientRec *cl)
{
KrfbServer *server = ServerManager::instance()->serverForClient(cl);
return server->handleNewClient(cl);
}
static rfbBool passwordCheck(rfbClientPtr cl,
const char* encryptedPassword,
int len)
{
ConnectionController *cc = static_cast<ConnectionController *>(cl->clientData);
return cc->handleCheckPassword(cl, encryptedPassword, len);
}
static void keyboardHook(rfbBool down, rfbKeySym keySym, rfbClientPtr cl)
{
ConnectionController *cc = static_cast<ConnectionController *>(cl->clientData);
cc->handleKeyEvent(down ? true : false, keySym);
}
static void pointerHook(int bm, int x, int y, rfbClientPtr cl)
{
ConnectionController *cc = static_cast<ConnectionController *>(cl->clientData);
cc->handlePointerEvent(bm, x, y);
}
static void clipboardHook(char* str,int len, rfbClientPtr cl)
{
ConnectionController *cc = static_cast<ConnectionController *>(cl->clientData);
cc->clipboardToServer(QString::fromUtf8(str, len));
}
class KrfbServer::KrfbServerP {
class KrfbServer::KrfbServerPrivate {
public:
KrfbServerP() : screen(0), numClients(0), listeningPort(0) {};
QSharedPointer<FrameBuffer> fb;
QList< QPointer<ConnectionController> > controllers;
rfbScreenInfoPtr screen;
int numClients;
QByteArray desktopName;
QTimer rfbProcessEventTimer;
QString listeningAddress;
unsigned int listeningPort;
KrfbServerPrivate() {};
};
KrfbServer::KrfbServer()
:d(new KrfbServerP)
: AbstractRfbServer(),
d(new KrfbServerPrivate)
{
kDebug() << "starting ";
d->fb = FrameBufferManager::instance()->frameBuffer(QApplication::desktop()->winId());
QTimer::singleShot(0, this, SLOT(startListening()));
QTimer::singleShot(0, this, SLOT(doStartListening()));
connect(InvitationManager::self(), SIGNAL(invitationNumChanged(int)),SLOT(updatePassword()));
}
@@ -147,125 +61,29 @@ KrfbServer::~KrfbServer()
}
void KrfbServer::startListening()
void KrfbServer::doStartListening()
{
rfbScreenInfoPtr screen;
int port = KrfbConfig::port();
int w = d->fb->width();
int h = d->fb->height();
int depth = d->fb->depth();
int bpp = depth >> 3;
if (bpp != 1 && bpp != 2 && bpp != 4) bpp = 4;
kDebug() << "bpp: " << bpp;
rfbLogEnable(0);
screen = rfbGetScreen(0, 0, w, h, 8, 3, bpp);
screen->paddedWidthInBytes = d->fb->paddedWidth();
d->fb->getServerFormat(screen->serverFormat);
screen->frameBuffer = d->fb->data();
d->screen = screen;
screen->autoPort = 0;
screen->port = port;
// server hooks
screen->newClientHook = newClientHook;
screen->kbdAddEvent = keyboardHook;
screen->ptrAddEvent = pointerHook;
screen->newClientHook = newClientHook;
screen->passwordCheck = passwordCheck;
screen->setXCutText = clipboardHook;
d->desktopName = i18n("%1@%2 (shared desktop)", KUser().loginName(), QHostInfo::localHostName()).toLatin1();
screen->desktopName = d->desktopName.constData();
if (!myCursor) {
myCursor = rfbMakeXCursor(19, 19, (char*) cur, (char*) mask);
}
screen->cursor = myCursor;
// configure passwords and desktop control here
updateSettings();
rfbInitServer(screen);
if (!rfbIsActive(screen)) {
KMessageBox::error(0,i18n("Address already in use"),"krfb");
shutdown();
qApp->quit();
return;
};
d->listeningPort = localPort(screen->listenSock);
d->listeningAddress = localAddress(screen->listenSock);
kDebug() << "Listen port:" << d->listeningPort << "Listen Address:" << d->listeningAddress;
// Set up the parameters for the server before we get it to start listening.
setFrameBuffer(FrameBufferManager::instance()->frameBuffer(QApplication::desktop()->winId()));
setListeningPort(KrfbConfig::port());
setListeningAddress("0.0.0.0"); // Listen on all available network addresses
setDesktopName(i18n("%1@%2 (shared desktop)",
KUser().loginName(),
QHostInfo::localHostName()).toLatin1());
if (KrfbConfig::publishService()) {
DNSSD::PublicService *service = new DNSSD::PublicService(i18n("%1@%2 (shared desktop)", KUser().loginName(), QHostInfo::localHostName()),"_rfb._tcp",port);
DNSSD::PublicService *service = new DNSSD::PublicService(i18n("%1@%2 (shared desktop)",
KUser().loginName(),
QHostInfo::localHostName()),
"_rfb._tcp",
listeningPort());
service->publishAsync();
}
/* Integrate the rfb event mechanism with qt's event loop.
* Call processRfbEvents() every time the qt event loop is run,
* so that it also processes and delivers rfb events and call
* shutdown() when QApplication exits to shutdown the rfb server
* before the X11 connection goes down.
*/
connect(&d->rfbProcessEventTimer, SIGNAL(timeout()), SLOT(processRfbEvents()));
connect(qApp, SIGNAL(aboutToQuit()), SLOT(shutdown()));
d->rfbProcessEventTimer.start(0);
}
startListening();
void KrfbServer::processRfbEvents()
{
foreach(const QRect &r, d->fb->modifiedTiles()) {
rfbMarkRectAsModified(d->screen, r.x(), r.y(), r.right(), r.bottom());
}
rfbProcessEvents(d->screen, 100);
}
void KrfbServer::shutdown()
{
rfbShutdownServer(d->screen, true);
// framebuffer has to be deleted before X11 connection goes down
d->fb.clear();
d->listeningPort = 0;
d->listeningAddress.clear();
}
void KrfbServer::enableDesktopControl(bool enable)
{
foreach (QPointer<ConnectionController> ptr, d->controllers) {
if (ptr) {
if (ptr->controlCanBeEnabled()) {
ptr->setControlEnabled(enable);
}
}
}
}
enum rfbNewClientAction KrfbServer::handleNewClient(struct _rfbClientRec * cl)
{
ConnectionController *cc = new ConnectionController(cl, this);
if (d->numClients++ == 0)
d->fb->startMonitor();
d->controllers.append(cc);
cc->setControlEnabled(KrfbConfig::allowDesktopControl());
cc->setControlCanBeEnabled(KrfbConfig::allowDesktopControl());
connect(cc, SIGNAL(sessionEstablished(QString)), SIGNAL(sessionEstablished(QString)));
connect(cc, SIGNAL(clientDisconnected(ConnectionController *)),SLOT(clientDisconnected(ConnectionController *)));
return cc->handleNewClient();
// configure passwords and desktop control here
updateSettings();
}
void KrfbServer::updateSettings()
@@ -274,57 +92,17 @@ void KrfbServer::updateSettings()
updatePassword();
}
void KrfbServer::updatePassword()
enum rfbNewClientAction KrfbServer::handleNewClient(struct _rfbClientRec * cl)
{
KrfbConnectionController *cc = new KrfbConnectionController(cl, this);
if (!d->screen) return;
QString pw = KrfbConfig::uninvitedConnectionPassword();
kDebug() << "password: " << pw << " allow " <<
KrfbConfig::allowUninvitedConnections() <<
" invitations " << InvitationManager::self()->activeInvitations() << endl;
cc->setControlEnabled(KrfbConfig::allowDesktopControl());
cc->setControlCanBeEnabled(KrfbConfig::allowDesktopControl());
if (pw.isEmpty() && InvitationManager::self()->activeInvitations() == 0) {
kDebug() << "no password from now on";
d->screen->authPasswdData = (void *)0;
} else {
kDebug() << "Ask for password to accept connections";
d->screen->authPasswdData = (void *)1;
}
connect(cc, SIGNAL(sessionEstablished(QString)), SIGNAL(sessionEstablished(QString)));
connect(cc, SIGNAL(clientDisconnected(AbstractConnectionController *)),SLOT(clientDisconnected(AbstractConnectionController *)));
return cc->handleNewClient();
}
bool KrfbServer::checkX11Capabilities() {
int bp1, bp2, majorv, minorv;
Bool r = XTestQueryExtension(QX11Info::display(), &bp1, &bp2,
&majorv, &minorv);
if ((!r) || (((majorv*1000)+minorv) < 2002)) {
KMessageBox::error(0,
i18n("Your X11 Server does not support the required XTest extension version 2.2. Sharing your desktop is not possible."),
i18n("Desktop Sharing Error"));
return false;
}
return true;
}
void KrfbServer::clientDisconnected(ConnectionController *cc)
{
kDebug() << "clients--: " << d->numClients;
if (!--d->numClients) {
d->fb->stopMonitor();
kDebug() << "stopMonitor: d->numClients = " << d->numClients;
}
disconnect(cc, SIGNAL(clientDisconnected(ConnectionController*)),this, SLOT(clientDisconnected(ConnectionController*)));
Q_EMIT sessionFinished();
}
QString KrfbServer::listeningAddress() const
{
return d->listeningAddress;
}
unsigned int KrfbServer::listeningPort() const
{
return d->listeningPort;
}

View File

@@ -1,58 +1,51 @@
/* This file is part of the KDE project
Copyright (C) 2009 Collabora Ltd <info@collabora.co.uk>
@author George Goldberg <george.goldberg@collabora.co.uk>
Copyright (C) 2007 Alessandro Praduroux <pradu@pradu.it>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef KRFBSERVER_H
#define KRFBSERVER_H
#ifndef KRFB_KRFBSERVER_H
#define KRFB_KRFBSERVER_H
#include <QObject>
#include <rfb/rfb.h>
#include "abstractrfbserver.h"
class ConnectionController;
/**
This class implements the listening server for the RFB protocol.
@author Alessandro Praduroux <pradu@pradu.it>
*/
class KrfbServer : public QObject
class KrfbServer : public AbstractRfbServer
{
Q_OBJECT
friend class ServerManager;
public:
~KrfbServer();
virtual ~KrfbServer();
enum rfbNewClientAction handleNewClient(struct _rfbClientRec *cl);
bool checkX11Capabilities();
signals:
void sessionEstablished(QString);
void sessionFinished();
void desktopControlSettingChanged(bool);
virtual enum rfbNewClientAction handleNewClient(struct _rfbClientRec *cl);
public Q_SLOTS:
void doStartListening();
void startListening();
void processRfbEvents();
void shutdown();
void enableDesktopControl(bool);
void updateSettings();
void updatePassword();
void clientDisconnected(ConnectionController *);
QString listeningAddress() const;
unsigned int listeningPort() const;
virtual void updateSettings();
private:
KrfbServer();
class KrfbServerP;
KrfbServerP * const d;
class KrfbServerPrivate;
KrfbServerPrivate * const d;
};
#endif
#endif // Header guard