mirror of
https://github.com/KDE/krfb
synced 2026-07-01 15:31:19 -07:00
Change the way rfb events are handled so that they are properly integrated with the Qt event mechanism.
Changes include: - Use a QSocketNotifier on each rfb socket that we know about, so that we don't have to poll the sockets using a timer. - Use a server registration mechanism in RfbServerManager so that the manager can update all the servers at once and delete them properly before shutting down. - Send updates to the clients periodically from the server manager and start/stop the update timer when clients connect/disconnect. This makes cpu usage drop dramatically when krfb is idle listening for incoming connections. - Let RfbServer handle the screen pointer. - Other minor adjustments (sorry for not making a separate commit) svn path=/trunk/KDE/kdenetwork/krfb/; revision=1195287
This commit is contained in:
@@ -79,25 +79,15 @@ static bool doCheckPassword(const QString &p, unsigned char *ochallenge, const c
|
||||
|
||||
//***********
|
||||
|
||||
static InvitationsRfbServer *s_server = 0;
|
||||
|
||||
void InvitationsRfbServer::init()
|
||||
{
|
||||
if (!s_server) {
|
||||
s_server = new InvitationsRfbServer;
|
||||
s_server->setListeningPort(KrfbConfig::port());
|
||||
s_server->setListeningAddress("0.0.0.0"); // Listen on all available network addresses
|
||||
s_server->setPasswordRequired(true);
|
||||
QTimer::singleShot(0, s_server, SLOT(startAndCheck()));
|
||||
}
|
||||
}
|
||||
|
||||
void InvitationsRfbServer::cleanup()
|
||||
{
|
||||
if (s_server) {
|
||||
delete s_server;
|
||||
s_server = 0;
|
||||
}
|
||||
InvitationsRfbServer *server;
|
||||
server = new InvitationsRfbServer;
|
||||
server->setListeningPort(KrfbConfig::port());
|
||||
server->setListeningAddress("0.0.0.0"); // Listen on all available network addresses
|
||||
server->setPasswordRequired(true);
|
||||
QTimer::singleShot(0, server, SLOT(startAndCheck()));
|
||||
}
|
||||
|
||||
RfbClient* InvitationsRfbServer::newClient(rfbClientPtr client)
|
||||
|
||||
@@ -27,7 +27,6 @@ class InvitationsRfbServer : public RfbServer
|
||||
Q_OBJECT
|
||||
public:
|
||||
static void init();
|
||||
static void cleanup();
|
||||
|
||||
protected:
|
||||
InvitationsRfbServer() : RfbServer(0) {}
|
||||
|
||||
@@ -128,9 +128,6 @@ int main(int argc, char *argv[])
|
||||
sigaddset(&sigs, SIGPIPE);
|
||||
sigprocmask(SIG_BLOCK, &sigs, 0);
|
||||
|
||||
int ret = app.exec();
|
||||
|
||||
//cleanup
|
||||
InvitationsRfbServer::cleanup();
|
||||
return app.exec();
|
||||
}
|
||||
|
||||
|
||||
@@ -21,20 +21,42 @@
|
||||
#include "connectiondialog.h"
|
||||
#include "krfbconfig.h"
|
||||
#include "sockethelpers.h"
|
||||
#include <QtCore/QSocketNotifier>
|
||||
#include <KDebug>
|
||||
#include <KNotification>
|
||||
#include <poll.h>
|
||||
|
||||
struct RfbClient::Private
|
||||
{
|
||||
Private(rfbClientPtr client) :
|
||||
connected(false),
|
||||
controlEnabled(false),
|
||||
client(client)
|
||||
{}
|
||||
|
||||
bool connected;
|
||||
bool controlEnabled;
|
||||
rfbClientPtr client;
|
||||
QSocketNotifier *notifier;
|
||||
};
|
||||
|
||||
RfbClient::RfbClient(rfbClientPtr client, QObject* parent)
|
||||
: QObject(parent),
|
||||
m_connected(false),
|
||||
m_controlEnabled(false),
|
||||
m_client(client)
|
||||
: QObject(parent), d(new Private(client))
|
||||
{
|
||||
d->notifier = new QSocketNotifier(client->sock, QSocketNotifier::Read, this);
|
||||
d->notifier->setEnabled(false);
|
||||
connect(d->notifier, SIGNAL(activated(int)), this, SLOT(onSocketActivated()));
|
||||
}
|
||||
|
||||
RfbClient::~RfbClient()
|
||||
{
|
||||
kDebug();
|
||||
delete d;
|
||||
}
|
||||
|
||||
QString RfbClient::name()
|
||||
{
|
||||
return peerAddress(m_client->sock) + ":" + QString::number(peerPort(m_client->sock));
|
||||
return peerAddress(d->client->sock) + ":" + QString::number(peerPort(d->client->sock));
|
||||
}
|
||||
|
||||
//static
|
||||
@@ -45,17 +67,52 @@ bool RfbClient::controlCanBeEnabled()
|
||||
|
||||
bool RfbClient::controlEnabled() const
|
||||
{
|
||||
return m_controlEnabled;
|
||||
return d->controlEnabled;
|
||||
}
|
||||
|
||||
void RfbClient::setControlEnabled(bool enabled)
|
||||
{
|
||||
if (controlCanBeEnabled() && m_controlEnabled != enabled) {
|
||||
m_controlEnabled = enabled;
|
||||
if (controlCanBeEnabled() && d->controlEnabled != enabled) {
|
||||
d->controlEnabled = enabled;
|
||||
Q_EMIT controlEnabledChanged(enabled);
|
||||
}
|
||||
}
|
||||
|
||||
rfbClientPtr RfbClient::rfbClient() const
|
||||
{
|
||||
return d->client;
|
||||
}
|
||||
|
||||
void RfbClient::update()
|
||||
{
|
||||
rfbUpdateClient(d->client);
|
||||
|
||||
//This is how we handle disconnection.
|
||||
//if rfbUpdateClient() finds out that it can't write to the socket,
|
||||
//it closes it and sets it to -1. So, we just have to check this here
|
||||
//and call rfbClientConnectionGone() if necessary. This will call
|
||||
//the clientGoneHook which in turn will remove this RfbClient instance
|
||||
//from the server manager and will call deleteLater() to delete it
|
||||
if (d->client->sock == -1) {
|
||||
kDebug() << "disconnected during update";
|
||||
d->notifier->setEnabled(false);
|
||||
rfbClientConnectionGone(d->client);
|
||||
}
|
||||
}
|
||||
|
||||
void RfbClient::setOnHold(bool onHold)
|
||||
{
|
||||
d->client->onHold = onHold;
|
||||
d->notifier->setEnabled(!onHold);
|
||||
}
|
||||
|
||||
void RfbClient::closeConnection()
|
||||
{
|
||||
d->notifier->setEnabled(false);
|
||||
rfbCloseClient(d->client);
|
||||
rfbClientConnectionGone(d->client);
|
||||
}
|
||||
|
||||
rfbNewClientAction RfbClient::doHandle()
|
||||
{
|
||||
kDebug();
|
||||
@@ -84,14 +141,45 @@ rfbNewClientAction RfbClient::doHandle()
|
||||
return RFB_CLIENT_ON_HOLD;
|
||||
}
|
||||
|
||||
bool RfbClient::isConnected() const
|
||||
{
|
||||
return d->connected;
|
||||
}
|
||||
|
||||
void RfbClient::setStatusConnected()
|
||||
{
|
||||
if (!m_connected) {
|
||||
m_connected = true;
|
||||
if (!d->connected) {
|
||||
d->connected = true;
|
||||
Q_EMIT connected(this);
|
||||
}
|
||||
}
|
||||
|
||||
void RfbClient::onSocketActivated()
|
||||
{
|
||||
//Process not only one, but all pending messages.
|
||||
//poll() idea/code copied from vino:
|
||||
// Copyright (C) 2003 Sun Microsystems, Inc.
|
||||
// License: GPL v2 or later
|
||||
struct pollfd pollfd = { d->client->sock, POLLIN|POLLPRI, 0 };
|
||||
|
||||
while(poll(&pollfd, 1, 0) == 1) {
|
||||
rfbProcessClientMessage(d->client);
|
||||
|
||||
//This is how we handle disconnection.
|
||||
//if rfbProcessClientMessage() finds out that it can't read the socket,
|
||||
//it closes it and sets it to -1. So, we just have to check this here
|
||||
//and call rfbClientConnectionGone() if necessary. This will call
|
||||
//the clientGoneHook which in turn will remove this RfbClient instance
|
||||
//from the server manager and will call deleteLater() to delete it
|
||||
if (d->client->sock == -1) {
|
||||
kDebug() << "disconnected from socket signal";
|
||||
d->notifier->setEnabled(false);
|
||||
rfbClientConnectionGone(d->client);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RfbClient::dialogAccepted()
|
||||
{
|
||||
ConnectionDialog *dialog = qobject_cast<ConnectionDialog *>(sender());
|
||||
@@ -101,8 +189,7 @@ void RfbClient::dialogAccepted()
|
||||
return;
|
||||
}
|
||||
|
||||
// rfbStartOnHoldClient(cl);
|
||||
m_client->onHold = false;
|
||||
setOnHold(false);
|
||||
setControlEnabled(dialog->cbAllowRemoteControl->isChecked());
|
||||
setStatusConnected();
|
||||
}
|
||||
@@ -110,7 +197,7 @@ void RfbClient::dialogAccepted()
|
||||
void RfbClient::dialogRejected()
|
||||
{
|
||||
kDebug() << "refused connection";
|
||||
rfbRefuseOnHoldClient(m_client);
|
||||
closeConnection();
|
||||
}
|
||||
|
||||
#include "rfbclient.moc"
|
||||
|
||||
@@ -29,6 +29,7 @@ class RfbClient : public QObject
|
||||
Q_PROPERTY(bool controlEnabled READ controlEnabled WRITE setControlEnabled NOTIFY controlEnabledChanged)
|
||||
public:
|
||||
RfbClient(rfbClientPtr client, QObject *parent = 0);
|
||||
virtual ~RfbClient();
|
||||
|
||||
/** Returns a name for the client, to be shown to the user */
|
||||
virtual QString name();
|
||||
@@ -38,28 +39,38 @@ public:
|
||||
void setControlEnabled(bool enabled);
|
||||
|
||||
///returns the internal rfbClient
|
||||
rfbClientPtr rfbClient() const { return m_client; }
|
||||
rfbClientPtr rfbClient() const;
|
||||
|
||||
public Q_SLOTS:
|
||||
void setOnHold(bool onHold);
|
||||
void closeConnection();
|
||||
|
||||
Q_SIGNALS:
|
||||
void controlEnabledChanged(bool enabled);
|
||||
void connected(RfbClient *self);
|
||||
|
||||
protected:
|
||||
friend class RfbServer;
|
||||
friend class RfbServerManager;
|
||||
///called by RfbServerManager to begin handling the client
|
||||
|
||||
///called by RfbServer to begin handling the client
|
||||
virtual rfbNewClientAction doHandle();
|
||||
|
||||
bool isConnected() const { return m_connected; }
|
||||
///called by RfbServerManager to send framebuffer updates
|
||||
///and check for possible disconnection
|
||||
void update();
|
||||
|
||||
bool isConnected() const;
|
||||
void setStatusConnected(); ///call to declare the client as connected
|
||||
|
||||
private Q_SLOTS:
|
||||
void onSocketActivated();
|
||||
void dialogAccepted();
|
||||
void dialogRejected();
|
||||
|
||||
private:
|
||||
bool m_connected;
|
||||
bool m_controlEnabled;
|
||||
rfbClientPtr m_client;
|
||||
struct Private;
|
||||
Private *const d;
|
||||
};
|
||||
|
||||
#endif // RFBCLIENT_H
|
||||
|
||||
@@ -20,13 +20,16 @@
|
||||
#include "rfbserver.h"
|
||||
#include "events.h"
|
||||
#include "rfbservermanager.h"
|
||||
#include <QtCore/QSocketNotifier>
|
||||
#include <KDebug>
|
||||
|
||||
struct RfbServer::Private
|
||||
{
|
||||
QByteArray listeningAddress;
|
||||
int listeningPort;
|
||||
bool passwordRequired;
|
||||
int id;
|
||||
rfbScreenInfoPtr screen;
|
||||
QSocketNotifier *notifier;
|
||||
};
|
||||
|
||||
RfbServer::RfbServer(QObject *parent)
|
||||
@@ -35,13 +38,21 @@ RfbServer::RfbServer(QObject *parent)
|
||||
d->listeningAddress = "0.0.0.0";
|
||||
d->listeningPort = 0;
|
||||
d->passwordRequired = true;
|
||||
d->id = -1;
|
||||
d->screen = NULL;
|
||||
d->notifier = NULL;
|
||||
|
||||
RfbServerManager::instance()->registerServer(this);
|
||||
}
|
||||
|
||||
RfbServer::~RfbServer()
|
||||
{
|
||||
stop();
|
||||
if (d->screen) {
|
||||
rfbScreenCleanup(d->screen);
|
||||
}
|
||||
delete d;
|
||||
|
||||
RfbServerManager::instance()->unregisterServer(this);
|
||||
}
|
||||
|
||||
void RfbServer::handleKeyboardEvent(RfbClient* client, rfbBool down, rfbKeySym keySym)
|
||||
@@ -102,19 +113,177 @@ void RfbServer::setPasswordRequired(bool passwordRequired)
|
||||
|
||||
bool RfbServer::start()
|
||||
{
|
||||
if (d->id == -1) {
|
||||
return (d->id = RfbServerManager::instance()->startServer(this)) != -1;
|
||||
if (!d->screen) {
|
||||
d->screen = RfbServerManager::instance()->newScreen();
|
||||
|
||||
// server hooks
|
||||
d->screen->screenData = this;
|
||||
d->screen->newClientHook = newClientHook;
|
||||
d->screen->kbdAddEvent = keyboardHook;
|
||||
d->screen->ptrAddEvent = pointerHook;
|
||||
d->screen->passwordCheck = passwordCheck;
|
||||
d->screen->setXCutText = clipboardHook;
|
||||
} else {
|
||||
return false; //server has already started
|
||||
//if we already have a screen, stop listening first
|
||||
rfbShutdownServer(d->screen, false);
|
||||
}
|
||||
|
||||
if (listeningAddress() != "0.0.0.0") {
|
||||
strncpy(d->screen->thisHost, listeningAddress().data(), 254);
|
||||
}
|
||||
|
||||
if (listeningPort() == 0) {
|
||||
d->screen->autoPort = 1;
|
||||
}
|
||||
|
||||
d->screen->port = listeningPort();
|
||||
|
||||
// Disable/Enable password checking
|
||||
if (passwordRequired()) {
|
||||
d->screen->authPasswdData = (void *)1;
|
||||
} else {
|
||||
d->screen->authPasswdData = (void *)0;
|
||||
}
|
||||
|
||||
kDebug() << "Starting server. Listen port:" << listeningPort()
|
||||
<< "Listen Address:" << listeningAddress()
|
||||
<< "Password enabled:" << passwordRequired();
|
||||
|
||||
rfbInitServer(d->screen);
|
||||
|
||||
if (!rfbIsActive(d->screen)) {
|
||||
kDebug() << "Failed to start server";
|
||||
rfbShutdownServer(d->screen, false);
|
||||
return false;
|
||||
};
|
||||
|
||||
d->notifier = new QSocketNotifier(d->screen->listenSock, QSocketNotifier::Read, this);
|
||||
d->notifier->setEnabled(true);
|
||||
connect(d->notifier, SIGNAL(activated(int)), this, SLOT(onListenSocketActivated()));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void RfbServer::stop(bool disconnectClients)
|
||||
{
|
||||
RfbServerManager::instance()->stopServer(d->id, disconnectClients);
|
||||
if (disconnectClients) {
|
||||
d->id = -1;
|
||||
if (d->screen) {
|
||||
rfbShutdownServer(d->screen, disconnectClients);
|
||||
if (d->notifier) {
|
||||
d->notifier->setEnabled(false);
|
||||
d->notifier->deleteLater();
|
||||
d->notifier = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RfbServer::updateScreen(const QList<QRect> & modifiedTiles)
|
||||
{
|
||||
if (d->screen) {
|
||||
QList<QRect>::const_iterator it = modifiedTiles.constBegin();
|
||||
for(; it != modifiedTiles.constEnd(); ++it) {
|
||||
rfbMarkRectAsModified(d->screen, it->x(), it->y(), it->right(), it->bottom());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Code copied from vino's bundled libvncserver:
|
||||
* Copyright (C) 2000, 2001 Const Kaplinsky. All Rights Reserved.
|
||||
* Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
|
||||
* License: GPL v2 or later
|
||||
*/
|
||||
void krfb_rfbSetCursorPosition(rfbScreenInfoPtr screen, rfbClientPtr client, int x, int y)
|
||||
{
|
||||
rfbClientIteratorPtr iterator;
|
||||
rfbClientPtr cl;
|
||||
|
||||
if (x == screen->cursorX || y == screen->cursorY)
|
||||
return;
|
||||
|
||||
LOCK(screen->cursorMutex);
|
||||
screen->cursorX = x;
|
||||
screen->cursorY = y;
|
||||
UNLOCK(screen->cursorMutex);
|
||||
|
||||
/* Inform all clients about this cursor movement. */
|
||||
iterator = rfbGetClientIterator(screen);
|
||||
while ((cl = rfbClientIteratorNext(iterator)) != NULL) {
|
||||
cl->cursorWasMoved = TRUE;
|
||||
}
|
||||
rfbReleaseClientIterator(iterator);
|
||||
|
||||
/* The cursor was moved by this client, so don't send CursorPos. */
|
||||
if (client) {
|
||||
client->cursorWasMoved = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
void RfbServer::updateCursorPosition(const QPoint & position)
|
||||
{
|
||||
if (d->screen) {
|
||||
krfb_rfbSetCursorPosition(d->screen, NULL, position.x(), position.y());
|
||||
}
|
||||
}
|
||||
|
||||
void RfbServer::onListenSocketActivated()
|
||||
{
|
||||
rfbProcessNewConnection(d->screen);
|
||||
}
|
||||
|
||||
//static
|
||||
rfbNewClientAction RfbServer::newClientHook(rfbClientPtr cl)
|
||||
{
|
||||
kDebug() << "New client";
|
||||
RfbServer *server = static_cast<RfbServer*>(cl->screen->screenData);
|
||||
|
||||
RfbClient *client = server->newClient(cl);
|
||||
RfbServerManager::instance()->addClient(client);
|
||||
|
||||
//clientData is used by the static callbacks to determine their context
|
||||
cl->clientData = client;
|
||||
cl->clientGoneHook = clientGoneHook;
|
||||
|
||||
return client->doHandle();
|
||||
}
|
||||
|
||||
//static
|
||||
void RfbServer::clientGoneHook(rfbClientPtr cl)
|
||||
{
|
||||
kDebug() << "client gone";
|
||||
RfbClient *client = static_cast<RfbClient*>(cl->clientData);
|
||||
|
||||
RfbServerManager::instance()->removeClient(client);
|
||||
client->deleteLater();
|
||||
}
|
||||
|
||||
//static
|
||||
rfbBool RfbServer::passwordCheck(rfbClientPtr cl, const char *encryptedPassword, int len)
|
||||
{
|
||||
RfbServer *server = static_cast<RfbServer*>(cl->screen->screenData);
|
||||
RfbClient *client = static_cast<RfbClient*>(cl->clientData);
|
||||
return server->checkPassword(client, encryptedPassword, len);
|
||||
}
|
||||
|
||||
//static
|
||||
void RfbServer::keyboardHook(rfbBool down, rfbKeySym keySym, rfbClientPtr cl)
|
||||
{
|
||||
RfbServer *server = static_cast<RfbServer*>(cl->screen->screenData);
|
||||
RfbClient *client = static_cast<RfbClient*>(cl->clientData);
|
||||
server->handleKeyboardEvent(client, down ? true : false, keySym);
|
||||
}
|
||||
|
||||
//static
|
||||
void RfbServer::pointerHook(int bm, int x, int y, rfbClientPtr cl)
|
||||
{
|
||||
RfbServer *server = static_cast<RfbServer*>(cl->screen->screenData);
|
||||
RfbClient *client = static_cast<RfbClient*>(cl->clientData);
|
||||
server->handleMouseEvent(client, bm, x, y);
|
||||
}
|
||||
|
||||
//static
|
||||
void RfbServer::clipboardHook(char *str, int len, rfbClientPtr cl)
|
||||
{
|
||||
//TODO implement me
|
||||
}
|
||||
|
||||
#include "rfbserver.moc"
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
#include "rfb.h"
|
||||
#include "rfbclient.h"
|
||||
#include <QtCore/QRect>
|
||||
|
||||
class RfbServer : public QObject
|
||||
{
|
||||
@@ -30,12 +31,6 @@ public:
|
||||
RfbServer(QObject *parent = 0);
|
||||
virtual ~RfbServer();
|
||||
|
||||
virtual RfbClient *newClient(rfbClientPtr client) = 0;
|
||||
|
||||
virtual void handleKeyboardEvent(RfbClient *client, rfbBool down, rfbKeySym keySym);
|
||||
virtual void handleMouseEvent(RfbClient *client, int buttonMask, int x, int y);
|
||||
virtual bool checkPassword(RfbClient *client, const char *encryptedPassword, int len);
|
||||
|
||||
QByteArray listeningAddress() const;
|
||||
int listeningPort() const;
|
||||
bool passwordRequired() const;
|
||||
@@ -48,7 +43,28 @@ public Q_SLOTS:
|
||||
bool start();
|
||||
void stop(bool disconnectClients = true);
|
||||
|
||||
void updateScreen(const QList<QRect> & modifiedTiles);
|
||||
void updateCursorPosition(const QPoint & position);
|
||||
|
||||
private Q_SLOTS:
|
||||
void onListenSocketActivated();
|
||||
|
||||
protected:
|
||||
virtual RfbClient *newClient(rfbClientPtr client) = 0;
|
||||
|
||||
virtual void handleKeyboardEvent(RfbClient *client, rfbBool down, rfbKeySym keySym);
|
||||
virtual void handleMouseEvent(RfbClient *client, int buttonMask, int x, int y);
|
||||
virtual bool checkPassword(RfbClient *client, const char *encryptedPassword, int len);
|
||||
|
||||
private:
|
||||
static rfbNewClientAction newClientHook(rfbClientPtr cl);
|
||||
static void clientGoneHook(rfbClientPtr cl);
|
||||
|
||||
static rfbBool passwordCheck(rfbClientPtr cl, const char *encryptedPassword, int len);
|
||||
static void keyboardHook(rfbBool down, rfbKeySym keySym, rfbClientPtr cl);
|
||||
static void pointerHook(int bm, int x, int y, rfbClientPtr cl);
|
||||
static void clipboardHook(char *str, int len, rfbClientPtr cl);
|
||||
|
||||
Q_DISABLE_COPY(RfbServer)
|
||||
|
||||
struct Private;
|
||||
|
||||
@@ -75,71 +75,6 @@ static const char *mask =
|
||||
" xxxxx "
|
||||
" xxx ";
|
||||
|
||||
/* copied from vino's bundled libvncserver...
|
||||
* Copyright (C) 2000, 2001 Const Kaplinsky. All Rights Reserved.
|
||||
* Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
|
||||
*/
|
||||
static void krfb_rfbSetCursorPosition(rfbScreenInfoPtr screen, rfbClientPtr client, int x, int y)
|
||||
{
|
||||
rfbClientIteratorPtr iterator;
|
||||
rfbClientPtr cl;
|
||||
|
||||
if (x == screen->cursorX || y == screen->cursorY)
|
||||
return;
|
||||
|
||||
LOCK(screen->cursorMutex);
|
||||
screen->cursorX = x;
|
||||
screen->cursorY = y;
|
||||
UNLOCK(screen->cursorMutex);
|
||||
|
||||
/* Inform all clients about this cursor movement. */
|
||||
iterator = rfbGetClientIterator(screen);
|
||||
while ((cl = rfbClientIteratorNext(iterator)) != NULL) {
|
||||
cl->cursorWasMoved = TRUE;
|
||||
}
|
||||
rfbReleaseClientIterator(iterator);
|
||||
|
||||
/* The cursor was moved by this client, so don't send CursorPos. */
|
||||
if (client) {
|
||||
client->cursorWasMoved = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
struct RfbClientData
|
||||
{
|
||||
RfbClientData(RfbClient *c, RfbServer *s)
|
||||
: client(c), server(s)
|
||||
{}
|
||||
|
||||
RfbClient *client;
|
||||
RfbServer *server;
|
||||
};
|
||||
|
||||
static rfbBool passwordCheck(rfbClientPtr cl,
|
||||
const char *encryptedPassword,
|
||||
int len)
|
||||
{
|
||||
RfbClientData *data = static_cast<RfbClientData*>(cl->clientData);
|
||||
return data->server->checkPassword(data->client, encryptedPassword, len);
|
||||
}
|
||||
|
||||
static void keyboardHook(rfbBool down, rfbKeySym keySym, rfbClientPtr cl)
|
||||
{
|
||||
RfbClientData *data = static_cast<RfbClientData*>(cl->clientData);
|
||||
data->server->handleKeyboardEvent(data->client, down ? true : false, keySym);
|
||||
}
|
||||
|
||||
static void pointerHook(int bm, int x, int y, rfbClientPtr cl)
|
||||
{
|
||||
RfbClientData *data = static_cast<RfbClientData*>(cl->clientData);
|
||||
data->server->handleMouseEvent(data->client, bm, x, y);
|
||||
}
|
||||
|
||||
static void clipboardHook(char *str, int len, rfbClientPtr cl)
|
||||
{
|
||||
//TODO implement me
|
||||
}
|
||||
|
||||
|
||||
struct RfbServerManagerStatic
|
||||
{
|
||||
@@ -156,18 +91,12 @@ RfbServerManager* RfbServerManager::instance()
|
||||
|
||||
struct RfbServerManager::Private
|
||||
{
|
||||
Private() : nextServerId(0) {}
|
||||
|
||||
QSharedPointer<FrameBuffer> fb;
|
||||
rfbCursorPtr myCursor;
|
||||
QByteArray desktopName;
|
||||
QTimer rfbProcessEventTimer;
|
||||
|
||||
QTimer rfbUpdateTimer;
|
||||
QSet<RfbServer*> servers;
|
||||
QSet<RfbClient*> clients;
|
||||
|
||||
int nextServerId;
|
||||
QHash<int, RfbServer*> servers;
|
||||
QHash<int, rfbScreenInfoPtr> screens;
|
||||
};
|
||||
|
||||
|
||||
@@ -192,33 +121,26 @@ void RfbServerManager::init()
|
||||
d->desktopName = QString("%1@%2 (shared desktop)") //FIXME check if we can use utf8
|
||||
.arg(KUser().loginName(),QHostInfo::localHostName()).toLatin1();
|
||||
|
||||
/* 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()));
|
||||
d->rfbProcessEventTimer.start(20);
|
||||
|
||||
connect(&d->rfbUpdateTimer, SIGNAL(timeout()), SLOT(updateScreens()));
|
||||
connect(qApp, SIGNAL(aboutToQuit()), SLOT(cleanup()));
|
||||
}
|
||||
|
||||
void RfbServerManager::processRfbEvents()
|
||||
void RfbServerManager::updateScreens()
|
||||
{
|
||||
QHashIterator<int, rfbScreenInfoPtr> it(d->screens);
|
||||
while(it.hasNext()) {
|
||||
it.next();
|
||||
rfbScreenInfoPtr screen = it.value();
|
||||
QList<QRect> rects = d->fb->modifiedTiles();
|
||||
QPoint currentCursorPos = QCursor::pos();
|
||||
|
||||
//update the cursor position
|
||||
QPoint currentCursorPos = QCursor::pos();
|
||||
krfb_rfbSetCursorPosition(screen, NULL, currentCursorPos.x(), currentCursorPos.y());
|
||||
Q_FOREACH(RfbServer *server, d->servers) {
|
||||
server->updateScreen(rects);
|
||||
server->updateCursorPosition(currentCursorPos);
|
||||
}
|
||||
|
||||
foreach(const QRect & r, d->fb->modifiedTiles()) {
|
||||
rfbMarkRectAsModified(screen, r.x(), r.y(), r.right(), r.bottom());
|
||||
}
|
||||
rfbProcessEvents(screen, 0);
|
||||
//update() might disconnect some of the clients, which will synchronously
|
||||
//call the removeClient() method and will change d->clients, so we need
|
||||
//to copy the set here to avoid problems.
|
||||
QSet<RfbClient*> clients = d->clients;
|
||||
Q_FOREACH(RfbClient *client, clients) {
|
||||
client->update();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -226,34 +148,37 @@ void RfbServerManager::cleanup()
|
||||
{
|
||||
kDebug();
|
||||
|
||||
QHashIterator<int, rfbScreenInfoPtr> it(d->screens);
|
||||
while(it.hasNext()) {
|
||||
it.next();
|
||||
rfbScreenInfoPtr screen = it.value();
|
||||
rfbShutdownServer(screen, true);
|
||||
rfbScreenCleanup(screen);
|
||||
//copy because d->servers is going to be modified while we delete the servers
|
||||
QSet<RfbServer*> servers = d->servers;
|
||||
Q_FOREACH(RfbServer *server, servers) {
|
||||
delete server;
|
||||
}
|
||||
|
||||
Q_ASSERT(d->servers.isEmpty());
|
||||
Q_ASSERT(d->clients.isEmpty());
|
||||
|
||||
d->myCursor->cleanup = true;
|
||||
rfbFreeCursor(d->myCursor);
|
||||
d->fb.clear();
|
||||
d->rfbProcessEventTimer.stop();
|
||||
d->screens.clear();
|
||||
d->servers.clear();
|
||||
}
|
||||
|
||||
int RfbServerManager::startServer(RfbServer *server)
|
||||
void RfbServerManager::registerServer(RfbServer* server)
|
||||
{
|
||||
kDebug() << "Starting server. Listen port:" << server->listeningPort()
|
||||
<< "Listen Address:" << server->listeningAddress()
|
||||
<< "Password enabled:" << server->passwordRequired();
|
||||
d->servers.insert(server);
|
||||
}
|
||||
|
||||
void RfbServerManager::unregisterServer(RfbServer* server)
|
||||
{
|
||||
d->servers.remove(server);
|
||||
}
|
||||
|
||||
rfbScreenInfoPtr RfbServerManager::newScreen()
|
||||
{
|
||||
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) {
|
||||
@@ -263,78 +188,16 @@ int RfbServerManager::startServer(RfbServer *server)
|
||||
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();
|
||||
|
||||
if (server->listeningAddress() != "0.0.0.0") {
|
||||
strncpy(screen->thisHost, server->listeningAddress().data(), 254);
|
||||
}
|
||||
|
||||
if (server->listeningPort() == 0) {
|
||||
screen->autoPort = 1;
|
||||
}
|
||||
|
||||
screen->port = server->listeningPort();
|
||||
|
||||
// Disable/Enable password checking
|
||||
if (server->passwordRequired()) {
|
||||
screen->authPasswdData = (void *)1;
|
||||
} else {
|
||||
screen->authPasswdData = (void *)0;
|
||||
}
|
||||
|
||||
// server hooks
|
||||
screen->newClientHook = newClientHook;
|
||||
|
||||
screen->kbdAddEvent = keyboardHook;
|
||||
screen->ptrAddEvent = pointerHook;
|
||||
screen->passwordCheck = passwordCheck;
|
||||
screen->setXCutText = clipboardHook;
|
||||
|
||||
screen->desktopName = d->desktopName.constData();
|
||||
screen->cursor = d->myCursor;
|
||||
|
||||
rfbInitServer(screen);
|
||||
|
||||
if (!rfbIsActive(screen)) {
|
||||
kDebug() << "Failed to start server";
|
||||
rfbShutdownServer(screen, true);
|
||||
rfbScreenCleanup(screen);
|
||||
return -1;
|
||||
};
|
||||
|
||||
server->setListeningPort(localPort(screen->listenSock));
|
||||
server->setListeningAddress(localAddress(screen->listenSock).toAscii());
|
||||
|
||||
d->nextServerId++;
|
||||
d->servers.insert(d->nextServerId, server);
|
||||
d->screens.insert(d->nextServerId, screen);
|
||||
|
||||
kDebug() << "Server started. Listen port:" << server->listeningPort()
|
||||
<< "Listen Address:" << server->listeningAddress();
|
||||
|
||||
return d->nextServerId;
|
||||
}
|
||||
|
||||
void RfbServerManager::stopServer(int id, bool disconnectClients)
|
||||
{
|
||||
if (d->screens.contains(id)) {
|
||||
rfbScreenInfoPtr screen = d->screens.value(id);
|
||||
rfbShutdownServer(screen, disconnectClients);
|
||||
|
||||
/* If we disconnect all clients, cleanup the
|
||||
* internal data as they are not needed anymore */
|
||||
if (disconnectClients) {
|
||||
d->servers.remove(id);
|
||||
d->screens.remove(id);
|
||||
rfbScreenCleanup(screen);
|
||||
}
|
||||
}
|
||||
return screen;
|
||||
}
|
||||
|
||||
void RfbServerManager::addClient(RfbClient* cc)
|
||||
@@ -342,8 +205,12 @@ void RfbServerManager::addClient(RfbClient* cc)
|
||||
if (d->clients.size() == 0) {
|
||||
kDebug() << "Starting framebuffer monitor";
|
||||
d->fb->startMonitor();
|
||||
d->rfbUpdateTimer.start(50);
|
||||
}
|
||||
d->clients.insert(cc);
|
||||
|
||||
QObject::connect(cc, SIGNAL(connected(RfbClient*)),
|
||||
this, SIGNAL(clientConnected(RfbClient*)));
|
||||
}
|
||||
|
||||
void RfbServerManager::removeClient(RfbClient* cc)
|
||||
@@ -352,43 +219,12 @@ void RfbServerManager::removeClient(RfbClient* cc)
|
||||
if (d->clients.size() == 0) {
|
||||
kDebug() << "Stopping framebuffer monitor";
|
||||
d->fb->stopMonitor();
|
||||
d->rfbUpdateTimer.stop();
|
||||
}
|
||||
}
|
||||
|
||||
//static
|
||||
rfbNewClientAction RfbServerManager::newClientHook(rfbClientPtr cl)
|
||||
{
|
||||
kDebug() << "New client";
|
||||
|
||||
int serverid = instance()->d->screens.key(cl->screen);
|
||||
RfbServer *server = instance()->d->servers.value(serverid);
|
||||
|
||||
RfbClient *client = server->newClient(cl);
|
||||
instance()->addClient(client);
|
||||
|
||||
//clientData is used by the static callbacks to determine their context
|
||||
cl->clientData = new RfbClientData(client, server);
|
||||
cl->clientGoneHook = clientGoneHook;
|
||||
|
||||
QObject::connect(client, SIGNAL(connected(RfbClient*)),
|
||||
instance(), SIGNAL(clientConnected(RfbClient*)));
|
||||
return client->doHandle();
|
||||
}
|
||||
|
||||
//static
|
||||
void RfbServerManager::clientGoneHook(rfbClientPtr cl)
|
||||
{
|
||||
kDebug() << "client gone";
|
||||
|
||||
RfbClientData *data = static_cast<RfbClientData*>(cl->clientData);
|
||||
|
||||
if (data->client->isConnected()) {
|
||||
Q_EMIT instance()->clientDisconnected(data->client);
|
||||
if (cc->isConnected()) {
|
||||
Q_EMIT clientDisconnected(cc);
|
||||
}
|
||||
instance()->removeClient(data->client);
|
||||
|
||||
data->client->deleteLater();
|
||||
delete data;
|
||||
}
|
||||
|
||||
#include "rfbservermanager.moc"
|
||||
|
||||
@@ -39,20 +39,18 @@ Q_SIGNALS:
|
||||
|
||||
private Q_SLOTS:
|
||||
void init();
|
||||
void processRfbEvents();
|
||||
void updateScreens();
|
||||
void cleanup();
|
||||
|
||||
private:
|
||||
/** Returns the id of the server, which should be >0. -1 means failed to start. */
|
||||
int startServer(RfbServer *server);
|
||||
void stopServer(int id, bool disconnectClients);
|
||||
void registerServer(RfbServer *server);
|
||||
void unregisterServer(RfbServer *server);
|
||||
|
||||
rfbScreenInfoPtr newScreen();
|
||||
|
||||
void addClient(RfbClient *cc);
|
||||
void removeClient(RfbClient *cc);
|
||||
|
||||
static rfbNewClientAction newClientHook(rfbClientPtr cl);
|
||||
static void clientGoneHook(rfbClientPtr cl);
|
||||
|
||||
RfbServerManager();
|
||||
virtual ~RfbServerManager();
|
||||
Q_DISABLE_COPY(RfbServerManager);
|
||||
|
||||
@@ -101,9 +101,9 @@ void TubesRfbClient::setContact(const Tp::ContactPtr & contact)
|
||||
//we were previously on hold, so we now need to act if
|
||||
//the parent's doHandle() says we must do something else
|
||||
if (action == RFB_CLIENT_ACCEPT) {
|
||||
rfbStartOnHoldClient(rfbClient());
|
||||
setOnHold(false);
|
||||
} else if (action == RFB_CLIENT_REFUSE) {
|
||||
rfbRefuseOnHoldClient(rfbClient());
|
||||
closeConnection();
|
||||
} //else if action == RFB_CLIENT_ON_HOLD there is nothing to do
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user