Browse Source

Merge branch 'vncserver' of https://github.com/CendioOssman/tigervnc

tags/v1.9.90
Pierre Ossman 5 years ago
parent
commit
f9de17665a

+ 0
- 2
common/network/Socket.h View File

@@ -151,8 +151,6 @@ namespace network {
// there is no timeout and checkTimeouts() should be called the next time
// an event occurs.
virtual int checkTimeouts() = 0;

virtual bool getDisable() {return false;};
};

}

+ 12
- 6
common/rfb/SConnection.cxx View File

@@ -260,13 +260,14 @@ void SConnection::throwConnFailedException(const char* format, ...)
throw ConnFailedException(str);
}

void SConnection::writeConnFailedFromScratch(const char* msg,
rdr::OutStream* os)
void SConnection::setAccessRights(AccessRights ar)
{
os->writeBytes("RFB 003.003\n", 12);
os->writeU32(0);
os->writeString(msg);
os->flush();
accessRights = ar;
}

bool SConnection::accessCheck(AccessRights ar) const
{
return (accessRights & ar) == ar;
}

void SConnection::setEncodings(int nEncodings, const rdr::S32* encodings)
@@ -342,6 +343,11 @@ void SConnection::clientInit(bool shared)
state_ = RFBSTATE_NORMAL;
}

void SConnection::close(const char* reason)
{
state_ = RFBSTATE_CLOSING;
}

void SConnection::setPixelFormat(const PixelFormat& pf)
{
SMsgHandler::setPixelFormat(pf);

+ 18
- 16
common/rfb/SConnection.h View File

@@ -69,6 +69,13 @@ namespace rfb {
void approveConnection(bool accept, const char* reason=0);


// Methods to terminate the connection

// close() shuts down the connection to the client and awaits
// cleanup of the SConnection object by the server
virtual void close(const char* reason);


// Overridden from SMsgHandler

virtual void setEncodings(int nEncodings, const rdr::S32* encodings);
@@ -118,8 +125,10 @@ namespace rfb {
virtual void enableContinuousUpdates(bool enable,
int x, int y, int w, int h);

// Other methods

// setAccessRights() allows a security package to limit the access rights
// of a VNCSConnectionST to the server. How the access rights are treated
// of a SConnection to the server. How the access rights are treated
// is up to the derived class.

typedef rdr::U16 AccessRights;
@@ -132,27 +141,14 @@ namespace rfb {
static const AccessRights AccessDefault; // The default rights, INCLUDING FUTURE ONES
static const AccessRights AccessNoQuery; // Connect without local user accepting
static const AccessRights AccessFull; // All of the available AND FUTURE rights
virtual void setAccessRights(AccessRights ar) = 0;

// Other methods
virtual void setAccessRights(AccessRights ar);
virtual bool accessCheck(AccessRights ar) const;

// authenticated() returns true if the client has authenticated
// successfully.
bool authenticated() { return (state_ == RFBSTATE_INITIALISATION ||
state_ == RFBSTATE_NORMAL); }

// throwConnFailedException() prints a message to the log, sends a conn
// failed message to the client (if possible) and throws a
// ConnFailedException.
void throwConnFailedException(const char* format, ...) __printf_attr(2, 3);

// writeConnFailedFromScratch() sends a conn failed message to an OutStream
// without the need to negotiate the protocol version first. It actually
// does this by assuming that the client will understand version 3.3 of the
// protocol.
static void writeConnFailedFromScratch(const char* msg,
rdr::OutStream* os);

SMsgReader* reader() { return reader_; }
SMsgWriter* writer() { return writer_; }

@@ -176,6 +172,11 @@ namespace rfb {
rdr::S32 getPreferredEncoding() { return preferredEncoding; }

protected:
// throwConnFailedException() prints a message to the log, sends a conn
// failed message to the client (if possible) and throws a
// ConnFailedException.
void throwConnFailedException(const char* format, ...) __printf_attr(2, 3);

void setState(stateEnum s) { state_ = s; }

void setReader(SMsgReader *r) { reader_ = r; }
@@ -201,6 +202,7 @@ namespace rfb {
SSecurity* ssecurity;
stateEnum state_;
rdr::S32 preferredEncoding;
AccessRights accessRights;
};
}
#endif

+ 16
- 2
common/rfb/SDesktop.h View File

@@ -44,6 +44,8 @@
#include <rfb/screenTypes.h>
#include <rfb/util.h>

namespace network { class Socket; }

namespace rfb {

class VNCServer;
@@ -56,14 +58,22 @@ namespace rfb {
// set via the VNCServer's setPixelBuffer() method by the time this call
// returns.

virtual void start(VNCServer* __unused_attr vs) {}
virtual void start(VNCServer* vs) = 0;

// stop() is called by the server when there are no longer any
// authenticated clients, and therefore the desktop can cease any
// expensive tasks. No further calls to the VNCServer passed to start()
// can be made once stop has returned.

virtual void stop() {}
virtual void stop() = 0;

// queryConnection() is called when a connection has been
// successfully authenticated. The sock and userName arguments
// identify the socket and the name of the authenticated user, if
// any. At some point later VNCServer::approveConnection() should
// be called to either accept or reject the client.
virtual void queryConnection(network::Socket* sock,
const char* userName) = 0;

// setScreenLayout() requests to reconfigure the framebuffer and/or
// the layout of screens.
@@ -112,6 +122,10 @@ namespace rfb {
server->setPixelBuffer(0);
server = 0;
}
virtual void queryConnection(network::Socket* sock,
const char* userName) {
server->approveConnection(sock, true, NULL);
}

protected:
VNCServer* server;

+ 75
- 191
common/rfb/VNCSConnectionST.cxx View File

@@ -52,27 +52,22 @@ VNCSConnectionST::VNCSConnectionST(VNCServerST* server_, network::Socket *s,
losslessTimer(this), server(server_), updates(false),
updateRenderedCursor(false), removeRenderedCursor(false),
continuousUpdates(false), encodeManager(this), pointerEventTime(0),
clientHasCursor(false),
accessRights(AccessDefault), startTime(time(0))
clientHasCursor(false)
{
setStreams(&sock->inStream(), &sock->outStream());
peerEndpoint.buf = sock->getPeerEndpoint();
VNCServerST::connectionsLog.write(1,"accepted: %s", peerEndpoint.buf);

// Configure the socket
setSocketTimeouts();
lastEventTime = time(0);

server->clients.push_front(this);
}


VNCSConnectionST::~VNCSConnectionST()
{
// If we reach here then VNCServerST is deleting us!
VNCServerST::connectionsLog.write(1,"closed: %s (%s)",
peerEndpoint.buf,
(closeReason.buf) ? closeReason.buf : "");
if (closeReason.buf)
vlog.info("closing %s: %s", peerEndpoint.buf, closeReason.buf);

// Release any keys the client still had pressed
while (!pressedKeys.empty()) {
@@ -84,30 +79,23 @@ VNCSConnectionST::~VNCSConnectionST()

vlog.debug("Releasing key 0x%x / 0x%x on client disconnect",
keysym, keycode);
server->desktop->keyEvent(keysym, keycode, false);
server->keyEvent(keysym, keycode, false);
}

if (server->pointerClient == this)
server->pointerClient = 0;

// Remove this client from the server
server->clients.remove(this);

delete [] fenceData;
}


// Methods called from VNCServerST
// SConnection methods

bool VNCSConnectionST::init()
bool VNCSConnectionST::accessCheck(AccessRights ar) const
{
try {
initialiseProtocol();
} catch (rdr::Exception& e) {
close(e.str());
return false;
}
return true;
// Reverse connections are user initiated, so they are implicitly
// allowed to bypass the query
if (reverseConnection)
ar &= ~AccessNoQuery;

return SConnection::accessCheck(ar);
}

void VNCSConnectionST::close(const char* reason)
@@ -118,15 +106,26 @@ void VNCSConnectionST::close(const char* reason)
else
vlog.debug("second close: %s (%s)", peerEndpoint.buf, reason);

if (authenticated()) {
server->lastDisconnectTime = time(0);
}

// Just shutdown the socket and mark our state as closing. Eventually the
// calling code will call VNCServerST's removeSocket() method causing us to
// be deleted.
sock->shutdown();
setState(RFBSTATE_CLOSING);

SConnection::close(reason);
}


// Methods called from VNCServerST

bool VNCSConnectionST::init()
{
try {
initialiseProtocol();
} catch (rdr::Exception& e) {
close(e.str());
return false;
}
return true;
}


@@ -192,8 +191,9 @@ void VNCSConnectionST::pixelBufferChange()
{
try {
if (!authenticated()) return;
if (cp.width && cp.height && (server->pb->width() != cp.width ||
server->pb->height() != cp.height))
if (cp.width && cp.height &&
(server->getPixelBuffer()->width() != cp.width ||
server->getPixelBuffer()->height() != cp.height))
{
// We need to clip the next update to the new size, but also add any
// extra bits if it's bigger. If we wanted to do this exactly, something
@@ -210,11 +210,11 @@ void VNCSConnectionST::pixelBufferChange()
// updates.add_changed(Rect(0, cp.height, cp.width,
// server->pb->height()));

damagedCursorRegion.assign_intersect(server->pb->getRect());
damagedCursorRegion.assign_intersect(server->getPixelBuffer()->getRect());

cp.width = server->pb->width();
cp.height = server->pb->height();
cp.screenLayout = server->screenLayout;
cp.width = server->getPixelBuffer()->width();
cp.height = server->getPixelBuffer()->height();
cp.screenLayout = server->getScreenLayout();
if (state() == RFBSTATE_NORMAL) {
// We should only send EDS to client asking for both
if (!writer()->writeExtendedDesktopSize()) {
@@ -226,12 +226,12 @@ void VNCSConnectionST::pixelBufferChange()
}

// Drop any lossy tracking that is now outside the framebuffer
encodeManager.pruneLosslessRefresh(Region(server->pb->getRect()));
encodeManager.pruneLosslessRefresh(Region(server->getPixelBuffer()->getRect()));
}
// Just update the whole screen at the moment because we're too lazy to
// work out what's actually changed.
updates.clear();
updates.add_changed(server->pb->getRect());
updates.add_changed(server->getPixelBuffer()->getRect());
writeFramebufferUpdate();
} catch(rdr::Exception &e) {
close(e.str());
@@ -269,7 +269,7 @@ void VNCSConnectionST::bellOrClose()
void VNCSConnectionST::serverCutTextOrClose(const char *str, int len)
{
try {
if (!(accessRights & AccessCutText)) return;
if (!accessCheck(AccessCutText)) return;
if (!rfb::Server::sendCutText) return;
if (state() == RFBSTATE_NORMAL)
writer()->writeServerCutText(str, len);
@@ -388,7 +388,7 @@ bool VNCSConnectionST::needRenderedCursor()
if (!cp.supportsLocalCursorWithAlpha &&
!cp.supportsLocalCursor && !cp.supportsLocalXCursor)
return true;
if (!server->cursorPos.equals(pointerEventPos) &&
if (!server->getCursorPos().equals(pointerEventPos) &&
(time(0) - pointerEventTime) > 0)
return true;

@@ -414,82 +414,36 @@ void VNCSConnectionST::authSuccess()
{
lastEventTime = time(0);

server->startDesktop();

// - Set the connection parameters appropriately
cp.width = server->pb->width();
cp.height = server->pb->height();
cp.screenLayout = server->screenLayout;
cp.width = server->getPixelBuffer()->width();
cp.height = server->getPixelBuffer()->height();
cp.screenLayout = server->getScreenLayout();
cp.setName(server->getName());
cp.setLEDState(server->ledState);
cp.setLEDState(server->getLEDState());
// - Set the default pixel format
cp.setPF(server->pb->getPF());
cp.setPF(server->getPixelBuffer()->getPF());
char buffer[256];
cp.pf().print(buffer, 256);
vlog.info("Server default pixel format %s", buffer);

// - Mark the entire display as "dirty"
updates.add_changed(server->pb->getRect());
startTime = time(0);
updates.add_changed(server->getPixelBuffer()->getRect());
}

void VNCSConnectionST::queryConnection(const char* userName)
{
// - Authentication succeeded - clear from blacklist
CharArray name; name.buf = sock->getPeerAddress();
server->blHosts->clearBlackmark(name.buf);

// - Special case to provide a more useful error message
if (rfb::Server::neverShared && !rfb::Server::disconnectClients &&
server->authClientCount() > 0) {
approveConnection(false, "The server is already in use");
return;
}

// - Does the client have the right to bypass the query?
if (reverseConnection ||
!(rfb::Server::queryConnect || sock->requiresQuery()) ||
(accessRights & AccessNoQuery))
{
approveConnection(true);
return;
}

// - Get the server to display an Accept/Reject dialog, if required
// If a dialog is displayed, the result will be PENDING, and the
// server will call approveConnection at a later time
CharArray reason;
VNCServerST::queryResult qr = server->queryConnection(sock, userName,
&reason.buf);
if (qr == VNCServerST::PENDING)
return;

// - If server returns ACCEPT/REJECT then pass result to SConnection
approveConnection(qr == VNCServerST::ACCEPT, reason.buf);
server->queryConnection(this, userName);
}

void VNCSConnectionST::clientInit(bool shared)
{
lastEventTime = time(0);
if (rfb::Server::alwaysShared || reverseConnection) shared = true;
if (!(accessRights & AccessNonShared)) shared = true;
if (!accessCheck(AccessNonShared)) shared = true;
if (rfb::Server::neverShared) shared = false;
if (!shared) {
if (rfb::Server::disconnectClients && (accessRights & AccessNonShared)) {
// - Close all the other connected clients
vlog.debug("non-shared connection - closing clients");
server->closeClients("Non-shared connection requested", getSock());
} else {
// - Refuse this connection if there are existing clients, in addition to
// this one
if (server->authClientCount() > 1) {
close("Server is already in use");
return;
}
}
}
SConnection::clientInit(shared);
server->clientReady(this, shared);
}

void VNCSConnectionST::setPixelFormat(const PixelFormat& pf)
@@ -504,36 +458,29 @@ void VNCSConnectionST::setPixelFormat(const PixelFormat& pf)
void VNCSConnectionST::pointerEvent(const Point& pos, int buttonMask)
{
pointerEventTime = lastEventTime = time(0);
server->lastUserInputTime = lastEventTime;
if (!(accessRights & AccessPtrEvents)) return;
if (!accessCheck(AccessPtrEvents)) return;
if (!rfb::Server::acceptPointerEvents) return;
if (!server->pointerClient || server->pointerClient == this) {
pointerEventPos = pos;
if (buttonMask)
server->pointerClient = this;
else
server->pointerClient = 0;
server->desktop->pointerEvent(pointerEventPos, buttonMask);
}
pointerEventPos = pos;
server->pointerEvent(this, pointerEventPos, buttonMask);
}


class VNCSConnectionSTShiftPresser {
public:
VNCSConnectionSTShiftPresser(SDesktop* desktop_)
: desktop(desktop_), pressed(false) {}
VNCSConnectionSTShiftPresser(VNCServerST* server_)
: server(server_), pressed(false) {}
~VNCSConnectionSTShiftPresser() {
if (pressed) {
vlog.debug("Releasing fake Shift_L");
desktop->keyEvent(XK_Shift_L, 0, false);
server->keyEvent(XK_Shift_L, 0, false);
}
}
void press() {
vlog.debug("Pressing fake Shift_L");
desktop->keyEvent(XK_Shift_L, 0, true);
server->keyEvent(XK_Shift_L, 0, true);
pressed = true;
}
SDesktop* desktop;
VNCServerST* server;
bool pressed;
};

@@ -543,8 +490,7 @@ void VNCSConnectionST::keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down) {
rdr::U32 lookup;

lastEventTime = time(0);
server->lastUserInputTime = lastEventTime;
if (!(accessRights & AccessKeyEvents)) return;
if (!accessCheck(AccessKeyEvents)) return;
if (!rfb::Server::acceptKeyEvents) return;

if (down)
@@ -552,18 +498,8 @@ void VNCSConnectionST::keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down) {
else
vlog.debug("Key released: 0x%x / 0x%x", keysym, keycode);

// Remap the key if required
if (server->keyRemapper) {
rdr::U32 newkey;
newkey = server->keyRemapper->remapKey(keysym);
if (newkey != keysym) {
vlog.debug("Key remapped to 0x%x", newkey);
keysym = newkey;
}
}

// Avoid lock keys if we don't know the server state
if ((server->ledState == ledUnknown) &&
if ((server->getLEDState() == ledUnknown) &&
((keysym == XK_Caps_Lock) ||
(keysym == XK_Num_Lock) ||
(keysym == XK_Scroll_Lock))) {
@@ -581,7 +517,7 @@ void VNCSConnectionST::keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down) {
return;
}

if (down && (server->ledState != ledUnknown)) {
if (down && (server->getLEDState() != ledUnknown)) {
// CapsLock synchronisation heuristic
// (this assumes standard interaction between CapsLock the Shift
// keys and normal characters)
@@ -591,12 +527,12 @@ void VNCSConnectionST::keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down) {

uppercase = (keysym >= XK_A) && (keysym <= XK_Z);
shift = isShiftPressed();
lock = server->ledState & ledCapsLock;
lock = server->getLEDState() & ledCapsLock;

if (lock == (uppercase == shift)) {
vlog.debug("Inserting fake CapsLock to get in sync with client");
server->desktop->keyEvent(XK_Caps_Lock, 0, true);
server->desktop->keyEvent(XK_Caps_Lock, 0, false);
server->keyEvent(XK_Caps_Lock, 0, true);
server->keyEvent(XK_Caps_Lock, 0, false);
}
}

@@ -611,7 +547,7 @@ void VNCSConnectionST::keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down) {
number = ((keysym >= XK_KP_0) && (keysym <= XK_KP_9)) ||
(keysym == XK_KP_Separator) || (keysym == XK_KP_Decimal);
shift = isShiftPressed();
lock = server->ledState & ledNumLock;
lock = server->getLEDState() & ledNumLock;

if (shift) {
// We don't know the appropriate NumLock state for when Shift
@@ -625,15 +561,15 @@ void VNCSConnectionST::keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down) {
//
} else if (lock == (number == shift)) {
vlog.debug("Inserting fake NumLock to get in sync with client");
server->desktop->keyEvent(XK_Num_Lock, 0, true);
server->desktop->keyEvent(XK_Num_Lock, 0, false);
server->keyEvent(XK_Num_Lock, 0, true);
server->keyEvent(XK_Num_Lock, 0, false);
}
}
}
}

// Turn ISO_Left_Tab into shifted Tab.
VNCSConnectionSTShiftPresser shiftPresser(server->desktop);
VNCSConnectionSTShiftPresser shiftPresser(server);
if (keysym == XK_ISO_Left_Tab) {
if (!isShiftPressed())
shiftPresser.press();
@@ -659,21 +595,21 @@ void VNCSConnectionST::keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down) {
return;
}

server->desktop->keyEvent(keysym, keycode, down);
server->keyEvent(keysym, keycode, down);
}

void VNCSConnectionST::clientCutText(const char* str, int len)
{
if (!(accessRights & AccessCutText)) return;
if (!accessCheck(AccessCutText)) return;
if (!rfb::Server::acceptCutText) return;
server->desktop->clientCutText(str, len);
server->clientCutText(str, len);
}

void VNCSConnectionST::framebufferUpdateRequest(const Rect& r,bool incremental)
{
Rect safeRect;

if (!(accessRights & AccessView)) return;
if (!accessCheck(AccessView)) return;

SConnection::framebufferUpdateRequest(r, incremental);

@@ -712,30 +648,12 @@ void VNCSConnectionST::setDesktopSize(int fb_width, int fb_height,
{
unsigned int result;

if (!(accessRights & AccessSetDesktopSize)) return;
if (!accessCheck(AccessSetDesktopSize)) return;
if (!rfb::Server::acceptSetDesktopSize) return;

// Don't bother the desktop with an invalid configuration
if (!layout.validate(fb_width, fb_height)) {
writer()->writeExtendedDesktopSize(reasonClient, resultInvalid,
fb_width, fb_height, layout);
return;
}

// FIXME: the desktop will call back to VNCServerST and an extra set
// of ExtendedDesktopSize messages will be sent. This is okay
// protocol-wise, but unnecessary.
result = server->desktop->setScreenLayout(fb_width, fb_height, layout);

result = server->setDesktopSize(this, fb_width, fb_height, layout);
writer()->writeExtendedDesktopSize(reasonClient, result,
fb_width, fb_height, layout);

// Only notify other clients on success
if (result == resultSuccess) {
if (server->screenLayout != layout)
throw Exception("Desktop configured a different screen layout than requested");
server->notifyScreenLayoutChange(this);
}
}

void VNCSConnectionST::fence(rdr::U32 flags, unsigned len, const char data[])
@@ -1001,7 +919,7 @@ void VNCSConnectionST::writeDataUpdate()

bogusCopiedCursor = damagedCursorRegion;
bogusCopiedCursor.translate(ui.copy_delta);
bogusCopiedCursor.assign_intersect(server->pb->getRect());
bogusCopiedCursor.assign_intersect(server->getPixelBuffer()->getRect());
if (!ui.copied.intersect(bogusCopiedCursor).is_empty()) {
updates.add_changed(bogusCopiedCursor);
needNewUpdateInfo = true;
@@ -1124,7 +1042,7 @@ void VNCSConnectionST::screenLayoutChange(rdr::U16 reason)
if (!authenticated())
return;

cp.screenLayout = server->screenLayout;
cp.screenLayout = server->getScreenLayout();

if (state() != RFBSTATE_NORMAL)
return;
@@ -1148,7 +1066,7 @@ void VNCSConnectionST::setCursor()
cp.setCursor(emptyCursor);
clientHasCursor = false;
} else {
cp.setCursor(*server->cursor);
cp.setCursor(*server->getCursor());
clientHasCursor = true;
}

@@ -1194,37 +1112,3 @@ void VNCSConnectionST::setSocketTimeouts()
sock->inStream().setTimeout(timeoutms);
sock->outStream().setTimeout(timeoutms);
}

char* VNCSConnectionST::getStartTime()
{
char* result = ctime(&startTime);
result[24] = '\0';
return result;
}

void VNCSConnectionST::setStatus(int status)
{
switch (status) {
case 0:
accessRights = accessRights | AccessPtrEvents | AccessKeyEvents | AccessView;
break;
case 1:
accessRights = (accessRights & ~(AccessPtrEvents | AccessKeyEvents)) | AccessView;
break;
case 2:
accessRights = accessRights & ~(AccessPtrEvents | AccessKeyEvents | AccessView);
break;
}
framebufferUpdateRequest(server->pb->getRect(), false);
}
int VNCSConnectionST::getStatus()
{
if ((accessRights & (AccessPtrEvents | AccessKeyEvents | AccessView)) == 0x0007)
return 0;
if ((accessRights & (AccessPtrEvents | AccessKeyEvents | AccessView)) == 0x0001)
return 1;
if ((accessRights & (AccessPtrEvents | AccessKeyEvents | AccessView)) == 0x0000)
return 2;
return 4;
}


+ 12
- 37
common/rfb/VNCSConnectionST.h View File

@@ -43,21 +43,18 @@ namespace rfb {
VNCSConnectionST(VNCServerST* server_, network::Socket* s, bool reverse);
virtual ~VNCSConnectionST();

// SConnection methods

virtual bool accessCheck(AccessRights ar) const;
virtual void close(const char* reason);

// Methods called from VNCServerST. None of these methods ever knowingly
// throw an exception.

// Unless otherwise stated, the SConnectionST may not be valid after any of
// these methods are called, since they catch exceptions and may have
// called close() which deletes the object.

// init() must be called to initialise the protocol. If it fails it
// returns false, and close() will have been called.
bool init();

// close() shuts down the socket to the client and deletes the
// SConnectionST object.
void close(const char* reason);

// processMessages() processes incoming messages from the client, invoking
// various callbacks as a result. It continues to process messages until
// reading might block. shutdown() will be called on the connection's
@@ -78,14 +75,14 @@ namespace rfb {
void serverCutTextOrClose(const char *str, int len);
void setDesktopNameOrClose(const char *name);
void setLEDStateOrClose(unsigned int state);
void approveConnectionOrClose(bool accept, const char* reason);

// checkIdleTimeout() returns the number of milliseconds left until the
// idle timeout expires. If it has expired, the connection is closed and
// zero is returned. Zero is also returned if there is no idle timeout.
int checkIdleTimeout();

// The following methods never throw exceptions nor do they ever delete the
// SConnectionST object.
// The following methods never throw exceptions

// getComparerState() returns if this client would like the framebuffer
// comparer to be enabled.
@@ -103,32 +100,18 @@ namespace rfb {
bool needRenderedCursor();

network::Socket* getSock() { return sock; }

// Change tracking

void add_changed(const Region& region) { updates.add_changed(region); }
void add_copied(const Region& dest, const Point& delta) {
updates.add_copied(dest, delta);
}

const char* getPeerEndpoint() const {return peerEndpoint.buf;}

// approveConnectionOrClose() is called some time after
// VNCServerST::queryConnection() has returned with PENDING to accept or
// reject the connection. The accept argument should be true for
// acceptance, or false for rejection, in which case a string reason may
// also be given.

void approveConnectionOrClose(bool accept, const char* reason);

char* getStartTime();

void setStatus(int status);
int getStatus();

private:
// SConnection callbacks

// These methods are invoked as callbacks from processMsg(). Note that
// none of these methods should call any of the above methods which may
// delete the SConnectionST object.
// These methods are invoked as callbacks from processMsg()

virtual void authSuccess();
virtual void queryConnection(const char* userName);
@@ -148,12 +131,6 @@ namespace rfb {
virtual void supportsContinuousUpdates();
virtual void supportsLEDState();

// setAccessRights() allows a security package to limit the access rights
// of a VNCSConnectioST to the server. These access rights are applied
// such that the actual rights granted are the minimum of the server's
// default access settings and the connection's access settings.
virtual void setAccessRights(AccessRights ar) {accessRights=ar;}

// Timer callbacks
virtual bool handleTimeout(Timer* t);

@@ -178,6 +155,7 @@ namespace rfb {
void setLEDState(unsigned int state);
void setSocketTimeouts();

private:
network::Socket* sock;
CharArray peerEndpoint;
bool reverseConnection;
@@ -209,10 +187,7 @@ namespace rfb {
Point pointerEventPos;
bool clientHasCursor;

AccessRights accessRights;

CharArray closeReason;
time_t startTime;
};
}
#endif

+ 17
- 2
common/rfb/VNCServer.h View File

@@ -22,13 +22,16 @@
#ifndef __RFB_VNCSERVER_H__
#define __RFB_VNCSERVER_H__

#include <network/Socket.h>

#include <rfb/UpdateTracker.h>
#include <rfb/SSecurity.h>
#include <rfb/ScreenSet.h>

namespace rfb {

class VNCServer : public UpdateTracker {
class VNCServer : public UpdateTracker,
public network::SocketServer {
public:
// blockUpdates()/unblockUpdates() tells the server that the pixel buffer
// is currently in flux and may not be accessed. The attributes of the
@@ -50,7 +53,7 @@ namespace rfb {
virtual void setScreenLayout(const ScreenSet& layout) = 0;

// getPixelBuffer() returns a pointer to the PixelBuffer object.
virtual PixelBuffer* getPixelBuffer() const = 0;
virtual const PixelBuffer* getPixelBuffer() const = 0;

// serverCutText() tells the server that the cut text has changed. This
// will normally be sent to all clients.
@@ -59,10 +62,22 @@ namespace rfb {
// bell() tells the server that it should make all clients make a bell sound.
virtual void bell() = 0;

// approveConnection() is called some time after
// SDesktop::queryConnection() has been called, to accept or reject
// the connection. The accept argument should be true for
// acceptance, or false for rejection, in which case a string
// reason may also be given.
virtual void approveConnection(network::Socket* sock, bool accept,
const char* reason = NULL) = 0;

// - Close all currently-connected clients, by calling
// their close() method with the supplied reason.
virtual void closeClients(const char* reason) = 0;

// getConnection() gets the SConnection for a particular Socket. If
// the Socket is not recognised then null is returned.
virtual SConnection* getConnection(network::Socket* sock) = 0;

// setCursor() tells the server that the cursor has changed. The
// cursorData argument contains width*height rgba quadruplets with
// non-premultiplied alpha.

+ 166
- 54
common/rfb/VNCServerST.cxx View File

@@ -53,7 +53,7 @@

#include <rfb/ComparingUpdateTracker.h>
#include <rfb/KeyRemapper.h>
#include <rfb/ListConnInfo.h>
#include <rfb/LogWriter.h>
#include <rfb/Security.h>
#include <rfb/ServerCore.h>
#include <rfb/VNCServerST.h>
@@ -66,7 +66,7 @@
using namespace rfb;

static LogWriter slog("VNCServerST");
LogWriter VNCServerST::connectionsLog("Connections");
static LogWriter connectionsLog("Connections");

//
// -=- VNCServerST Implementation
@@ -80,9 +80,8 @@ VNCServerST::VNCServerST(const char* name_, SDesktop* desktop_)
name(strDup(name_)), pointerClient(0), comparer(0),
cursor(new Cursor(0, 0, Point(), NULL)),
renderedCursorInvalid(false),
queryConnectionHandler(0), keyRemapper(&KeyRemapper::defInstance),
lastConnectionTime(0), disableclients(false),
frameTimer(this)
keyRemapper(&KeyRemapper::defInstance),
lastConnectionTime(0), frameTimer(this)
{
lastUserInputTime = lastDisconnectTime = time(0);
slog.debug("creating single-threaded server %s", name.buf);
@@ -99,9 +98,11 @@ VNCServerST::~VNCServerST()
stopFrameClock();

// Delete all the clients, and their sockets, and any closing sockets
// NB: Deleting a client implicitly removes it from the clients list
while (!clients.empty()) {
delete clients.front();
VNCSConnectionST* client;
client = clients.front();
clients.pop_front();
delete client;
}

// Stop the desktop object if active, *only* after deleting all clients!
@@ -125,8 +126,13 @@ void VNCServerST::addSocket(network::Socket* sock, bool outgoing)
if (blHosts->isBlackmarked(address.buf)) {
connectionsLog.error("blacklisted: %s", address.buf);
try {
SConnection::writeConnFailedFromScratch("Too many security failures",
&sock->outStream());
rdr::OutStream& os = sock->outStream();

// Shortest possible way to tell a client it is not welcome
os.writeBytes("RFB 003.003\n", 12);
os.writeU32(0);
os.writeString("Too many security failures");
os.flush();
} catch (rdr::Exception&) {
}
sock->shutdown();
@@ -134,11 +140,16 @@ void VNCServerST::addSocket(network::Socket* sock, bool outgoing)
return;
}

CharArray name;
name.buf = sock->getPeerEndpoint();
connectionsLog.status("accepted: %s", name.buf);

if (clients.empty()) {
lastConnectionTime = time(0);
}

VNCSConnectionST* client = new VNCSConnectionST(this, sock, outgoing);
clients.push_front(client);
client->init();
}

@@ -147,9 +158,22 @@ void VNCServerST::removeSocket(network::Socket* sock) {
std::list<VNCSConnectionST*>::iterator ci;
for (ci = clients.begin(); ci != clients.end(); ci++) {
if ((*ci)->getSock() == sock) {
clients.remove(*ci);

// - Release the cursor if this client owns it
if (pointerClient == *ci)
pointerClient = NULL;

if ((*ci)->authenticated())
lastDisconnectTime = time(0);

// - Delete the per-Socket resources
delete *ci;

CharArray name;
name.buf = sock->getPeerEndpoint();
connectionsLog.status("closed: %s", name.buf);

// - Check that the desktop object is still required
if (authClientCount() == 0)
stopDesktop();
@@ -467,6 +491,81 @@ void VNCServerST::setLEDState(unsigned int state)
}
}

// Event handlers

void VNCServerST::keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down)
{
lastUserInputTime = time(0);

// Remap the key if required
if (keyRemapper) {
rdr::U32 newkey;
newkey = keyRemapper->remapKey(keysym);
if (newkey != keysym) {
slog.debug("Key remapped to 0x%x", newkey);
keysym = newkey;
}
}

desktop->keyEvent(keysym, keycode, down);
}

void VNCServerST::pointerEvent(VNCSConnectionST* client,
const Point& pos, int buttonMask)
{
lastUserInputTime = time(0);

// Let one client own the cursor whilst buttons are pressed in order
// to provide a bit more sane user experience
if ((pointerClient != NULL) && (pointerClient != client))
return;

if (buttonMask)
pointerClient = client;
else
pointerClient = NULL;

desktop->pointerEvent(pos, buttonMask);
}

void VNCServerST::clientCutText(const char* str, int len)
{
desktop->clientCutText(str, len);
}

unsigned int VNCServerST::setDesktopSize(VNCSConnectionST* requester,
int fb_width, int fb_height,
const ScreenSet& layout)
{
unsigned int result;
std::list<VNCSConnectionST*>::iterator ci, ci_next;

// Don't bother the desktop with an invalid configuration
if (!layout.validate(fb_width, fb_height))
return resultInvalid;

// FIXME: the desktop will call back to VNCServerST and an extra set
// of ExtendedDesktopSize messages will be sent. This is okay
// protocol-wise, but unnecessary.
result = desktop->setScreenLayout(fb_width, fb_height, layout);
if (result != resultSuccess)
return result;

// Sanity check
if (screenLayout != layout)
throw Exception("Desktop configured a different screen layout than requested");

// Notify other clients
for (ci=clients.begin();ci!=clients.end();ci=ci_next) {
ci_next = ci; ci_next++;
if ((*ci) == requester)
continue;
(*ci)->screenLayoutChangeOrClose(reasonOtherClient);
}

return resultSuccess;
}

// Other public methods

void VNCServerST::approveConnection(network::Socket* sock, bool accept,
@@ -504,7 +603,7 @@ void VNCServerST::getSockets(std::list<network::Socket*>* sockets)
}
}

SConnection* VNCServerST::getSConnection(network::Socket* sock) {
SConnection* VNCServerST::getConnection(network::Socket* sock) {
std::list<VNCSConnectionST*>::iterator ci;
for (ci = clients.begin(); ci != clients.end(); ci++) {
if ((*ci)->getSock() == sock)
@@ -534,6 +633,63 @@ bool VNCServerST::handleTimeout(Timer* t)
return false;
}

void VNCServerST::queryConnection(VNCSConnectionST* client,
const char* userName)
{
// - Authentication succeeded - clear from blacklist
CharArray name;
name.buf = client->getSock()->getPeerAddress();
blHosts->clearBlackmark(name.buf);

// - Prepare the desktop for that the client will start requiring
// resources after this
startDesktop();

// - Special case to provide a more useful error message
if (rfb::Server::neverShared &&
!rfb::Server::disconnectClients &&
authClientCount() > 0) {
approveConnection(client->getSock(), false,
"The server is already in use");
return;
}

// - Are we configured to do queries?
if (!rfb::Server::queryConnect &&
!client->getSock()->requiresQuery()) {
approveConnection(client->getSock(), true, NULL);
return;
}

// - Does the client have the right to bypass the query?
if (client->accessCheck(SConnection::AccessNoQuery))
{
approveConnection(client->getSock(), true, NULL);
return;
}

desktop->queryConnection(client->getSock(), userName);
}

void VNCServerST::clientReady(VNCSConnectionST* client, bool shared)
{
if (!shared) {
if (rfb::Server::disconnectClients &&
client->accessCheck(SConnection::AccessNonShared)) {
// - Close all the other connected clients
slog.debug("non-shared connection - closing clients");
closeClients("Non-shared connection requested", client->getSock());
} else {
// - Refuse this connection if there are existing clients, in addition to
// this one
if (authClientCount() > 1) {
client->close("Server is already in use");
return;
}
}
}
}

// -=- Internal methods

void VNCServerST::startDesktop()
@@ -689,50 +845,6 @@ const RenderedCursor* VNCServerST::getRenderedCursor()
return &renderedCursor;
}

void VNCServerST::getConnInfo(ListConnInfo * listConn)
{
listConn->Clear();
listConn->setDisable(getDisable());
if (clients.empty())
return;
std::list<VNCSConnectionST*>::iterator i;
for (i = clients.begin(); i != clients.end(); i++)
listConn->addInfo((void*)(*i), (*i)->getSock()->getPeerAddress(),
(*i)->getStartTime(), (*i)->getStatus());
}

void VNCServerST::setConnStatus(ListConnInfo* listConn)
{
setDisable(listConn->getDisable());
if (listConn->Empty() || clients.empty()) return;
for (listConn->iBegin(); !listConn->iEnd(); listConn->iNext()) {
VNCSConnectionST* conn = (VNCSConnectionST*)listConn->iGetConn();
std::list<VNCSConnectionST*>::iterator i;
for (i = clients.begin(); i != clients.end(); i++) {
if ((*i) == conn) {
int status = listConn->iGetStatus();
if (status == 3) {
(*i)->close(0);
} else {
(*i)->setStatus(status);
}
break;
}
}
}
}

void VNCServerST::notifyScreenLayoutChange(VNCSConnectionST* requester)
{
std::list<VNCSConnectionST*>::iterator ci, ci_next;
for (ci=clients.begin();ci!=clients.end();ci=ci_next) {
ci_next = ci; ci_next++;
if ((*ci) == requester)
continue;
(*ci)->screenLayoutChangeOrClose(reasonOtherClient);
}
}

bool VNCServerST::getComparerState()
{
if (rfb::Server::compareFB == 0)

+ 53
- 96
common/rfb/VNCServerST.h View File

@@ -28,11 +28,9 @@

#include <rfb/SDesktop.h>
#include <rfb/VNCServer.h>
#include <rfb/LogWriter.h>
#include <rfb/Blacklist.h>
#include <rfb/Cursor.h>
#include <rfb/Timer.h>
#include <network/Socket.h>
#include <rfb/ScreenSet.h>

namespace rfb {
@@ -44,8 +42,7 @@ namespace rfb {
class KeyRemapper;

class VNCServerST : public VNCServer,
public Timer::Callback,
public network::SocketServer {
public Timer::Callback {
public:
// -=- Constructors

@@ -93,102 +90,70 @@ namespace rfb {
virtual void setPixelBuffer(PixelBuffer* pb, const ScreenSet& layout);
virtual void setPixelBuffer(PixelBuffer* pb);
virtual void setScreenLayout(const ScreenSet& layout);
virtual PixelBuffer* getPixelBuffer() const { return pb; }
virtual const PixelBuffer* getPixelBuffer() const { return pb; }
virtual void serverCutText(const char* str, int len);

virtual void approveConnection(network::Socket* sock, bool accept,
const char* reason);
virtual void closeClients(const char* reason) {closeClients(reason, 0);}
virtual SConnection* getConnection(network::Socket* sock);

virtual void add_changed(const Region &region);
virtual void add_copied(const Region &dest, const Point &delta);
virtual void setCursor(int width, int height, const Point& hotspot,
const rdr::U8* data);
virtual void setCursorPos(const Point& p);
virtual void setName(const char* name_);
virtual void setLEDState(unsigned state);

virtual void bell();

// - Close all currently-connected clients, by calling
// their close() method with the supplied reason.
virtual void closeClients(const char* reason) {closeClients(reason, 0);}

// VNCServerST-only methods

// Methods to get the currently set server state

const ScreenSet& getScreenLayout() const { return screenLayout; }
const Cursor* getCursor() const { return cursor; }
const Point& getCursorPos() const { return cursorPos; }
const char* getName() const { return name.buf; }
unsigned getLEDState() const { return ledState; }

// Event handlers
void keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down);
void pointerEvent(VNCSConnectionST* client, const Point& pos, int buttonMask);
void clientCutText(const char* str, int len);

unsigned int setDesktopSize(VNCSConnectionST* requester,
int fb_width, int fb_height,
const ScreenSet& layout);

// closeClients() closes all RFB sessions, except the specified one (if
// any), and logs the specified reason for closure.
void closeClients(const char* reason, network::Socket* sock);

// getSConnection() gets the SConnection for a particular Socket. If
// the Socket is not recognised then null is returned.
// queryConnection() does some basic checks and then passes on the
// request to the desktop.
void queryConnection(VNCSConnectionST* client, const char* userName);

SConnection* getSConnection(network::Socket* sock);
// clientReady() is called by a VNCSConnectionST instance when the
// client has completed the handshake and is ready for normal
// communication.
void clientReady(VNCSConnectionST* client, bool shared);

// getName() returns the name of this VNC Server. NB: The value returned
// is the server's internal buffer which may change after any other methods
// are called - take a copy if necessary.
const char* getName() const {return name.buf;}
// Estimated time until the next time new updates will be pushed
// to clients
int msToNextUpdate();

// setName() specifies the desktop name that the server should provide to
// clients
virtual void setName(const char* name_);
// Part of the framebuffer that has been modified but is not yet
// ready to be sent to clients
Region getPendingRegion();

// A QueryConnectionHandler, if supplied, is passed details of incoming
// connections to approve, reject, or query the user about.
//
// queryConnection() is called when a connection has been
// successfully authenticated. The sock and userName arguments identify
// the socket and the name of the authenticated user, if any. It should
// return ACCEPT if the connection should be accepted, REJECT if it should
// be rejected, or PENDING if a decision cannot yet be reached. If REJECT
// is returned, *reason can be set to a string describing the reason - this
// will be delete[]ed when it is finished with. If PENDING is returned,
// approveConnection() must be called some time later to accept or reject
// the connection.
enum queryResult { ACCEPT, REJECT, PENDING };
struct QueryConnectionHandler {
virtual ~QueryConnectionHandler() {}
virtual queryResult queryConnection(network::Socket* sock,
const char* userName,
char** reason) = 0;
};
void setQueryConnectionHandler(QueryConnectionHandler* qch) {
queryConnectionHandler = qch;
}

// queryConnection is called as described above, and either passes the
// request on to the registered handler, or accepts the connection if
// no handler has been specified.
virtual queryResult queryConnection(network::Socket* sock,
const char* userName,
char** reason) {
return queryConnectionHandler
? queryConnectionHandler->queryConnection(sock, userName, reason)
: ACCEPT;
}

// approveConnection() is called by the active QueryConnectionHandler,
// some time after queryConnection() has returned with PENDING, to accept
// or reject the connection. The accept argument should be true for
// acceptance, or false for rejection, in which case a string reason may
// also be given.
void approveConnection(network::Socket* sock, bool accept,
const char* reason);

// setBlacklist() is called to replace the VNCServerST's internal
// Blacklist instance with another instance. This allows a single
// Blacklist to be shared by multiple VNCServerST instances.
void setBlacklist(Blacklist* bl) {blHosts = bl ? bl : &blacklist;}

// setKeyRemapper() replaces the VNCServerST's default key remapper.
// NB: A null pointer is valid here.
void setKeyRemapper(KeyRemapper* kr) { keyRemapper = kr; }

void getConnInfo(ListConnInfo * listConn);
void setConnStatus(ListConnInfo* listConn);

bool getDisable() { return disableclients;};
void setDisable(bool disable) { disableclients = disable;};
// getRenderedCursor() returns an up to date version of the server
// side rendered cursor buffer
const RenderedCursor* getRenderedCursor();

protected:

friend class VNCSConnectionST;

// Timer callbacks
virtual bool handleTimeout(Timer* t);

@@ -197,7 +162,17 @@ namespace rfb {
void startDesktop();
void stopDesktop();

static LogWriter connectionsLog;
// - Check how many of the clients are authenticated.
int authClientCount();

bool needRenderedCursor();
void startFrameClock();
void stopFrameClock();
void writeUpdate();

bool getComparerState();

protected:
Blacklist blacklist;
Blacklist* blHosts;

@@ -221,30 +196,12 @@ namespace rfb {
RenderedCursor renderedCursor;
bool renderedCursorInvalid;

// - Check how many of the clients are authenticated.
int authClientCount();

bool needRenderedCursor();
void startFrameClock();
void stopFrameClock();
int msToNextUpdate();
void writeUpdate();
Region getPendingRegion();
const RenderedCursor* getRenderedCursor();

void notifyScreenLayoutChange(VNCSConnectionST *requester);

bool getComparerState();

QueryConnectionHandler* queryConnectionHandler;
KeyRemapper* keyRemapper;

time_t lastUserInputTime;
time_t lastDisconnectTime;
time_t lastConnectionTime;

bool disableclients;

Timer frameTimer;
};


+ 52
- 1
unix/x0vncserver/XDesktop.cxx View File

@@ -18,6 +18,10 @@
* USA.
*/

#include <assert.h>

#include <rfb/LogWriter.h>

#include <x0vncserver/XDesktop.h>

#include <X11/XKBlib.h>
@@ -53,6 +57,10 @@ BoolParameter rawKeyboard("RawKeyboard",
"Send keyboard events straight through and "
"avoid mapping them to the current keyboard "
"layout", false);
IntParameter queryConnectTimeout("QueryConnectTimeout",
"Number of seconds to show the Accept Connection dialog before "
"rejecting the connection",
10);

static rfb::LogWriter vlog("XDesktop");

@@ -63,6 +71,7 @@ static const char * ledNames[XDESKTOP_N_LEDS] = {

XDesktop::XDesktop(Display* dpy_, Geometry *geometry_)
: dpy(dpy_), geometry(geometry_), pb(0), server(0),
queryConnectDialog(0), queryConnectSock(0),
oldButtonMask(0), haveXtest(false), haveDamage(false),
maxButtons(0), running(false), ledMasks(), ledState(0),
codeMap(0), codeMapLen(0)
@@ -227,7 +236,7 @@ void XDesktop::start(VNCServer* vs) {
pb = new XPixelBuffer(dpy, factory, geometry->getRect());
vlog.info("Allocated %s", pb->getImage()->classDesc());

server = (VNCServerST *)vs;
server = vs;
server->setPixelBuffer(pb, computeScreenLayout());

#ifdef HAVE_XDAMAGE
@@ -254,6 +263,9 @@ void XDesktop::stop() {
XDamageDestroy(dpy, damage);
#endif

delete queryConnectDialog;
queryConnectDialog = 0;

server->setPixelBuffer(0);
server = 0;

@@ -265,6 +277,30 @@ bool XDesktop::isRunning() {
return running;
}

void XDesktop::queryConnection(network::Socket* sock,
const char* userName)
{
assert(isRunning());

if (queryConnectSock) {
server->approveConnection(sock, false, "Another connection is currently being queried.");
return;
}

if (!userName)
userName = "(anonymous)";

queryConnectSock = sock;

CharArray address(sock->getPeerAddress());
delete queryConnectDialog;
queryConnectDialog = new QueryConnectDialog(dpy, address.buf,
userName,
queryConnectTimeout,
this);
queryConnectDialog->map();
}

void XDesktop::pointerEvent(const Point& pos, int buttonMask) {
#ifdef HAVE_XTEST
if (!haveXtest) return;
@@ -686,6 +722,21 @@ bool XDesktop::handleGlobalEvent(XEvent* ev) {
return false;
}

void XDesktop::queryApproved()
{
assert(isRunning());
server->approveConnection(queryConnectSock, true, 0);
queryConnectSock = 0;
}

void XDesktop::queryRejected()
{
assert(isRunning());
server->approveConnection(queryConnectSock, false,
"Connection rejected by local user");
queryConnectSock = 0;
}

bool XDesktop::setCursor()
{
XFixesCursorImage *cim;

+ 15
- 3
unix/x0vncserver/XDesktop.h View File

@@ -21,7 +21,7 @@
#ifndef __XDESKTOP_H__
#define __XDESKTOP_H__

#include <rfb/VNCServerST.h>
#include <rfb/SDesktop.h>
#include <tx/TXWindow.h>
#include <unixcommon.h>

@@ -30,13 +30,17 @@
#include <X11/extensions/Xdamage.h>
#endif

#include <vncconfig/QueryConnectDialog.h>

class Geometry;
class XPixelBuffer;

// number of XKb indicator leds to handle
#define XDESKTOP_N_LEDS 3

class XDesktop : public rfb::SDesktop, public TXGlobalEventHandler
class XDesktop : public rfb::SDesktop,
public TXGlobalEventHandler,
public QueryResultCallback
{
public:
XDesktop(Display* dpy_, Geometry *geometry);
@@ -46,6 +50,8 @@ public:
virtual void start(rfb::VNCServer* vs);
virtual void stop();
bool isRunning();
virtual void queryConnection(network::Socket* sock,
const char* userName);
virtual void pointerEvent(const rfb::Point& pos, int buttonMask);
KeyCode XkbKeysymToKeycode(Display* dpy, KeySym keysym);
virtual void keyEvent(rdr::U32 keysym, rdr::U32 xtcode, bool down);
@@ -56,11 +62,17 @@ public:
// -=- TXGlobalEventHandler interface
virtual bool handleGlobalEvent(XEvent* ev);

// -=- QueryResultCallback interface
virtual void queryApproved();
virtual void queryRejected();

protected:
Display* dpy;
Geometry* geometry;
XPixelBuffer* pb;
rfb::VNCServerST* server;
rfb::VNCServer* server;
QueryConnectDialog* queryConnectDialog;
network::Socket* queryConnectSock;
int oldButtonMask;
bool haveXtest;
bool haveDamage;

+ 0
- 52
unix/x0vncserver/x0vncserver.cxx View File

@@ -33,8 +33,6 @@
#include <network/TcpSocket.h>
#include <network/UnixSocket.h>

#include <vncconfig/QueryConnectDialog.h>

#include <signal.h>
#include <X11/X.h>
#include <X11/Xlib.h>
@@ -61,10 +59,6 @@ StringParameter displayname("display", "The X display", "");
IntParameter rfbport("rfbport", "TCP port to listen for RFB protocol",5900);
StringParameter rfbunixpath("rfbunixpath", "Unix socket to listen for RFB protocol", "");
IntParameter rfbunixmode("rfbunixmode", "Unix socket access mode", 0600);
IntParameter queryConnectTimeout("QueryConnectTimeout",
"Number of seconds to show the Accept Connection dialog before "
"rejecting the connection",
10);
StringParameter hostsFile("HostsFile", "File with IP access control rules", "");

//
@@ -79,50 +73,6 @@ static void CleanupSignalHandler(int sig)
}


class QueryConnHandler : public VNCServerST::QueryConnectionHandler,
public QueryResultCallback {
public:
QueryConnHandler(Display* dpy, VNCServerST* vs)
: display(dpy), server(vs), queryConnectDialog(0), queryConnectSock(0) {}
~QueryConnHandler() { delete queryConnectDialog; }

// -=- VNCServerST::QueryConnectionHandler interface
virtual VNCServerST::queryResult queryConnection(network::Socket* sock,
const char* userName,
char** reason) {
if (queryConnectSock) {
*reason = strDup("Another connection is currently being queried.");
return VNCServerST::REJECT;
}
if (!userName) userName = "(anonymous)";
queryConnectSock = sock;
CharArray address(sock->getPeerAddress());
delete queryConnectDialog;
queryConnectDialog = new QueryConnectDialog(display, address.buf,
userName, queryConnectTimeout,
this);
queryConnectDialog->map();
return VNCServerST::PENDING;
}

// -=- QueryResultCallback interface
virtual void queryApproved() {
server->approveConnection(queryConnectSock, true, 0);
queryConnectSock = 0;
}
virtual void queryRejected() {
server->approveConnection(queryConnectSock, false,
"Connection rejected by local user");
queryConnectSock = 0;
}
private:
Display* display;
VNCServerST* server;
QueryConnectDialog* queryConnectDialog;
network::Socket* queryConnectSock;
};


class FileTcpFilter : public TcpFilter
{

@@ -307,8 +257,6 @@ int main(int argc, char** argv)
XDesktop desktop(dpy, &geo);

VNCServerST server("x0vncserver", &desktop);
QueryConnHandler qcHandler(dpy, &server);
server.setQueryConnectionHandler(&qcHandler);

if (rfbunixpath.getValueStr()[0] != '\0') {
listeners.push_back(new network::UnixListener(rfbunixpath, rfbunixmode));

+ 17
- 11
unix/xserver/hw/vnc/XserverDesktop.cc View File

@@ -81,7 +81,6 @@ XserverDesktop::XserverDesktop(int screenIndex_,

server = new VNCServerST(name, this);
setFramebuffer(width, height, fbptr, stride);
server->setQueryConnectionHandler(this);

for (std::list<SocketListener*>::iterator i = listeners.begin();
i != listeners.end();
@@ -145,22 +144,31 @@ void XserverDesktop::refreshScreenLayout()
server->setScreenLayout(::computeScreenLayout(&outputIdMap));
}

rfb::VNCServerST::queryResult
XserverDesktop::queryConnection(network::Socket* sock,
const char* userName,
char** reason)
void XserverDesktop::start(rfb::VNCServer* vs)
{
// We already own the server object, and we always keep it in a
// ready state
assert(vs == server);
}

void XserverDesktop::stop()
{
}

void XserverDesktop::queryConnection(network::Socket* sock,
const char* userName)
{
int count;

if (queryConnectTimer.isStarted()) {
*reason = strDup("Another connection is currently being queried.");
return rfb::VNCServerST::REJECT;
server->approveConnection(sock, false, "Another connection is currently being queried.");
return;
}

count = vncNotifyQueryConnect();
if (count == 0) {
*reason = strDup("Unable to query the local user to accept the connection.");
return rfb::VNCServerST::REJECT;
server->approveConnection(sock, false, "Unable to query the local user to accept the connection.");
return;
}

queryConnectAddress.replaceBuf(sock->getPeerAddress());
@@ -171,8 +179,6 @@ XserverDesktop::queryConnection(network::Socket* sock,
queryConnectSocket = sock;

queryConnectTimer.start(queryConnectTimeout * 1000);

return rfb::VNCServerST::PENDING;
}

void XserverDesktop::bell()

+ 6
- 8
unix/xserver/hw/vnc/XserverDesktop.h View File

@@ -34,7 +34,7 @@
#include <rfb/SDesktop.h>
#include <rfb/PixelBuffer.h>
#include <rfb/Configuration.h>
#include <rfb/VNCServerST.h>
#include <rfb/Timer.h>
#include <unixcommon.h>
#include "Input.h"

@@ -45,7 +45,6 @@ namespace rfb {
namespace network { class SocketListener; class Socket; class SocketServer; }

class XserverDesktop : public rfb::SDesktop, public rfb::FullFramePixelBuffer,
public rfb::VNCServerST::QueryConnectionHandler,
public rfb::Timer::Callback {
public:

@@ -86,6 +85,10 @@ public:
const char* rejectMsg=0);

// rfb::SDesktop callbacks
virtual void start(rfb::VNCServer* vs);
virtual void stop();
virtual void queryConnection(network::Socket* sock,
const char* userName);
virtual void pointerEvent(const rfb::Point& pos, int buttonMask);
virtual void keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down);
virtual void clientCutText(const char* str, int len);
@@ -95,11 +98,6 @@ public:
// rfb::PixelBuffer callbacks
virtual void grabRegion(const rfb::Region& r);

// rfb::VNCServerST::QueryConnectionHandler callback
virtual rfb::VNCServerST::queryResult queryConnection(network::Socket* sock,
const char* userName,
char** reason);

protected:
bool handleListenerEvent(int fd,
std::list<network::SocketListener*>* sockets,
@@ -113,7 +111,7 @@ protected:
private:

int screenIndex;
rfb::VNCServerST* server;
rfb::VNCServer* server;
std::list<network::SocketListener*> listeners;
bool directFbptr;


+ 17
- 1
win/rfb_win32/SDisplay.cxx View File

@@ -20,6 +20,8 @@
//
// The SDisplay class encapsulates a particular system display.

#include <assert.h>

#include <rfb_win32/SDisplay.h>
#include <rfb_win32/Service.h>
#include <rfb_win32/TsSessions.h>
@@ -66,7 +68,7 @@ SDisplay::SDisplay()
: server(0), pb(0), device(0),
core(0), ptr(0), kbd(0), clipboard(0),
inputs(0), monitor(0), cleanDesktop(0), cursor(0),
statusLocation(0), ledState(0)
statusLocation(0), queryConnectionHandler(0), ledState(0)
{
updateEvent.h = CreateEvent(0, TRUE, FALSE, 0);
}
@@ -139,6 +141,20 @@ void SDisplay::stop()
}


void SDisplay::queryConnection(network::Socket* sock,
const char* userName)
{
assert(server != NULL);

if (queryConnectionHandler) {
queryConnectionHandler->queryConnection(sock, userName);
return;
}

server->approveConnection(sock, true);
}


void SDisplay::startCore() {

// Currently, we just check whether we're in the console session, and

+ 18
- 0
win/rfb_win32/SDisplay.h View File

@@ -52,6 +52,13 @@ namespace rfb {
virtual const char* methodName() const = 0;
};

class QueryConnectionHandler {
public:
virtual ~QueryConnectionHandler() {}
virtual void queryConnection(network::Socket* sock,
const char* userName) = 0;
};

class SDisplay : public SDesktop,
WMMonitor::Notifier,
Clipboard::Notifier,
@@ -65,6 +72,8 @@ namespace rfb {

virtual void start(VNCServer* vs);
virtual void stop();
virtual void queryConnection(network::Socket* sock,
const char* userName);
virtual void pointerEvent(const Point& pos, int buttonmask);
virtual void keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down);
virtual void clientCutText(const char* str, int len);
@@ -86,6 +95,12 @@ namespace rfb {

void setStatusLocation(bool* status) {statusLocation = status;}

// -=- Set handler for incoming connections

void setQueryConnectionHandler(QueryConnectionHandler* qch) {
queryConnectionHandler = qch;
}

static IntParameter updateMethod;
static BoolParameter disableLocalInputs;
static StringParameter disconnectAction;
@@ -150,6 +165,9 @@ namespace rfb {
// -=- Where to write the active/inactive indicator to
bool* statusLocation;

// -=- Whom to query incoming connections
QueryConnectionHandler* queryConnectionHandler;

unsigned ledState;
};


+ 28
- 1
win/rfb_win32/SocketManager.cxx View File

@@ -78,6 +78,7 @@ void SocketManager::addListener(network::SocketListener* sock_,
li.sock = sock_;
li.server = srvr;
li.notifier = acn;
li.disable = false;
listeners[event] = li;
}

@@ -128,6 +129,32 @@ void SocketManager::remSocket(network::Socket* sock_) {
throw rdr::Exception("Socket not registered");
}

bool SocketManager::getDisable(network::SocketServer* srvr)
{
std::map<HANDLE,ListenInfo>::iterator i;
for (i=listeners.begin(); i!=listeners.end(); i++) {
if (i->second.server == srvr) {
return i->second.disable;
}
}
throw rdr::Exception("Listener not registered");
}

void SocketManager::setDisable(network::SocketServer* srvr, bool disable)
{
bool found = false;
std::map<HANDLE,ListenInfo>::iterator i;
for (i=listeners.begin(); i!=listeners.end(); i++) {
if (i->second.server == srvr) {
i->second.disable = disable;
// There might be multiple sockets for the same server, so
// continue iterating
found = true;
}
}
if (!found)
throw rdr::Exception("Listener not registered");
}

int SocketManager::checkTimeouts() {
int timeout = EventManager::checkTimeouts();
@@ -164,7 +191,7 @@ void SocketManager::processEvent(HANDLE event) {
WSAEnumNetworkEvents(li.sock->getFd(), event, &network_events);
if (network_events.lNetworkEvents & FD_ACCEPT) {
network::Socket* new_sock = li.sock->accept();
if (new_sock && li.server->getDisable()) {
if (new_sock && li.disable) {
delete new_sock;
new_sock = 0;
}

+ 4
- 0
win/rfb_win32/SocketManager.h View File

@@ -65,6 +65,9 @@ namespace rfb {
// the SocketServer.
void addSocket(network::Socket* sock_, network::SocketServer* srvr, bool outgoing=true);

bool getDisable(network::SocketServer* srvr);
void setDisable(network::SocketServer* srvr, bool disable);

protected:
virtual int checkTimeouts();
virtual void processEvent(HANDLE event);
@@ -78,6 +81,7 @@ namespace rfb {
network::SocketListener* sock;
network::SocketServer* server;
AddressChangeNotifier* notifier;
bool disable;
};
std::map<HANDLE, ListenInfo> listeners;
std::map<HANDLE, ConnInfo> connections;

+ 6
- 7
win/winvnc/ControlPanel.cxx View File

@@ -19,10 +19,9 @@ void ControlPanel::initDialog()
{
TCHAR *ColumnsStrings[] = {
(TCHAR *) "IP address",
(TCHAR *) "Time connected",
(TCHAR *) "Status"
};
InitLVColumns(IDC_LIST_CONNECTIONS, handle, 120, 3, ColumnsStrings,
InitLVColumns(IDC_LIST_CONNECTIONS, handle, 120, 2, ColumnsStrings,
LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM,
LVS_EX_FULLROWSELECT, LVCFMT_LEFT);
SendCommand(4, -1);
@@ -74,7 +73,7 @@ bool ControlPanel::onCommand(int cmd)
}

void ControlPanel::UpdateListView(rfb::ListConnInfo* LCInfo)
void ControlPanel::UpdateListView(ListConnInfo* LCInfo)
{
getSelConnInfo();
DeleteAllLVItem(IDC_LIST_CONNECTIONS, handle);
@@ -85,12 +84,12 @@ void ControlPanel::UpdateListView(rfb::ListConnInfo* LCInfo)

ListConn.Copy(LCInfo);

char* ItemString[3];
char* ItemString[2];
int i = 0;

for (ListConn.iBegin(); !ListConn.iEnd(); ListConn.iNext()) {
ListConn.iGetCharInfo(ItemString);
InsertLVItem(IDC_LIST_CONNECTIONS, handle, i, (TCHAR **) ItemString, 3);
InsertLVItem(IDC_LIST_CONNECTIONS, handle, i, (TCHAR **) ItemString, 2);
for (ListSelConn.iBegin(); !ListSelConn.iEnd(); ListSelConn.iNext()) {
if (ListSelConn.iGetConn() == ListConn.iGetConn())
SelectLVItem(IDC_LIST_CONNECTIONS, handle, i);
@@ -141,6 +140,8 @@ void ControlPanel::SendCommand(DWORD command, int data)
{
COPYDATASTRUCT copyData;
copyData.dwData = command;
copyData.cbData = 0;
copyData.lpData = 0;
getSelConnInfo();
if (data != -1) {
ListConnStatus.Copy(&ListSelConn);
@@ -149,8 +150,6 @@ void ControlPanel::SendCommand(DWORD command, int data)
} else {
ListConnStatus.Clear();
}
copyData.cbData = 0;
copyData.lpData = &ListConnStatus;
SendMessage(m_hSTIcon, WM_COPYDATA, 0, (LPARAM)&copyData);
}


+ 6
- 6
win/winvnc/ControlPanel.h View File

@@ -11,10 +11,10 @@

#include <list>
#include <winvnc/resource.h>
#include <winvnc/ListConnInfo.h>
#include <rfb_win32/Dialog.h>
#include <rfb_win32/ListViewControl.h>
#include <rfb_win32/Win32Util.h>
#include <rfb/ListConnInfo.h>

namespace winvnc {
@@ -27,19 +27,19 @@ namespace winvnc {
virtual bool showDialog();
virtual void initDialog();
virtual bool onCommand(int cmd);
void UpdateListView(rfb::ListConnInfo* LCInfo);
void UpdateListView(ListConnInfo* LCInfo);
HWND GetHandle() {return handle;};
void SendCommand(DWORD command, int data);
~ControlPanel();
rfb::ListConnInfo ListConnStatus;
ListConnInfo ListConnStatus;
protected:
virtual BOOL dialogProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
void getSelConnInfo();
HWND m_hSTIcon;
rfb::ListConnInfo ListConn;
rfb::ListConnInfo ListSelConn;
ListConnInfo ListConn;
ListConnInfo ListSelConn;
bool stop_updating;
};
};

#endif
#endif

common/rfb/ListConnInfo.h → win/winvnc/ListConnInfo.h View File

@@ -24,7 +24,7 @@

#include <rfb/util.h>

namespace rfb {
namespace winvnc {

struct ListConnInfo {
ListConnInfo() : disableClients(false) {}
@@ -32,7 +32,6 @@ namespace rfb {
void Clear() {
conn.clear();
IP_address.clear();
time_conn.clear();
status.clear();
}

@@ -41,7 +40,6 @@ namespace rfb {
void iBegin() {
ci = conn.begin();
Ii = IP_address.begin();
ti = time_conn.begin();
si = status.begin();
}

@@ -50,32 +48,29 @@ namespace rfb {
void iNext() {
ci++;
Ii++;
ti++;
si++;
}

void addInfo(void* Conn, char* IP, char* Time, int Status) {
void addInfo(void* Conn, char* IP, int Status) {
conn.push_back(Conn);
IP_address.push_back(strDup(IP));
time_conn.push_back(strDup(Time));
IP_address.push_back(rfb::strDup(IP));
status.push_back(Status);
}

void iGetCharInfo(char* buf[3]) {
void iGetCharInfo(char* buf[2]) {
buf[0] = *Ii;
buf[1] = *ti;
switch (*si) {
case 0:
buf[2] = strDup("Full control");
buf[1] = rfb::strDup("Full control");
break;
case 1:
buf[2] = strDup("View only");
buf[1] = rfb::strDup("View only");
break;
case 2:
buf[2] = strDup("Stop updating");
buf[1] = rfb::strDup("Stop updating");
break;
default:
buf[2] = strDup("Unknown");
buf[1] = rfb::strDup("Unknown");
}
}

@@ -95,9 +90,9 @@ namespace rfb {
}

void iAdd (ListConnInfo* InputList) {
char* buf[3];
char* buf[2];
InputList->iGetCharInfo(buf);
addInfo(InputList->iGetConn(), buf[0], buf[1], InputList->iGetStatus());
addInfo(InputList->iGetConn(), buf[0], InputList->iGetStatus());
}

void setDisable(bool disable) {disableClients = disable;}
@@ -113,11 +108,9 @@ namespace rfb {
private:
std::list<void*> conn;
std::list<char*> IP_address;
std::list<char*> time_conn;
std::list<int> status;
std::list<void*>::iterator ci;
std::list<char*>::iterator Ii;
std::list<char*>::iterator ti;
std::list<int>::iterator si;
bool disableClients;
};

+ 2
- 2
win/winvnc/STrayIcon.cxx View File

@@ -184,7 +184,7 @@ public:
case 2:
return thread.server.disconnectClients("IPC disconnect") ? 1 : 0;
case 3:
thread.server.setClientsStatus((rfb::ListConnInfo *)command->lpData);
thread.server.setClientsStatus(&CPanel->ListConnStatus);
case 4:
thread.server.getClientsInfo(&LCInfo);
CPanel->UpdateListView(&LCInfo);
@@ -230,7 +230,7 @@ protected:
LaunchProcess vncConnect;
STrayIconThread& thread;
ControlPanel * CPanel;
rfb::ListConnInfo LCInfo;
ListConnInfo LCInfo;
};



+ 1
- 0
win/winvnc/VNCServerService.cxx View File

@@ -19,6 +19,7 @@
// -=- WinVNC Version 4.0 Service-Mode implementation

#include <winvnc/VNCServerService.h>
#include <rfb/LogWriter.h>
#include <rfb_win32/TsSessions.h>
#include <rfb_win32/ModuleFileName.h>
#include <windows.h>

+ 93
- 15
win/winvnc/VNCServerWin32.cxx View File

@@ -20,6 +20,7 @@

#include <winvnc/VNCServerWin32.h>
#include <winvnc/resource.h>
#include <winvnc/ListConnInfo.h>
#include <winvnc/STrayIcon.h>

#include <os/Mutex.h>
@@ -71,9 +72,7 @@ VNCServerWin32::VNCServerWin32()

// Initialise the desktop
desktop.setStatusLocation(&isDesktopStarted);

// Initialise the VNC server
vncServer.setQueryConnectionHandler(this);
desktop.setQueryConnectionHandler(this);

// Register the desktop's event to be handled
sockMgr.addEvent(desktop.getUpdateEvent(), &desktop);
@@ -241,27 +240,27 @@ bool VNCServerWin32::addNewClient(const char* client) {
return false;
}

bool VNCServerWin32::getClientsInfo(rfb::ListConnInfo* LCInfo) {
bool VNCServerWin32::getClientsInfo(ListConnInfo* LCInfo) {
return queueCommand(GetClientsInfo, LCInfo, 0);
}

bool VNCServerWin32::setClientsStatus(rfb::ListConnInfo* LCInfo) {
bool VNCServerWin32::setClientsStatus(ListConnInfo* LCInfo) {
return queueCommand(SetClientsStatus, LCInfo, 0);
}

VNCServerST::queryResult VNCServerWin32::queryConnection(network::Socket* sock,
const char* userName,
char** reason)
void VNCServerWin32::queryConnection(network::Socket* sock,
const char* userName)
{
if (queryOnlyIfLoggedOn && CurrentUserToken().noUserLoggedOn())
return VNCServerST::ACCEPT;
if (queryOnlyIfLoggedOn && CurrentUserToken().noUserLoggedOn()) {
vncServer.approveConnection(sock, true, NULL);
return;
}
if (queryConnectDialog) {
*reason = rfb::strDup("Another connection is currently being queried.");
return VNCServerST::REJECT;
vncServer.approveConnection(sock, false, "Another connection is currently being queried.");
return;
}
queryConnectDialog = new QueryConnectDialog(sock, userName, this);
queryConnectDialog->startDialog();
return VNCServerST::PENDING;
}

void VNCServerWin32::queryConnectionComplete() {
@@ -309,10 +308,10 @@ void VNCServerWin32::processEvent(HANDLE event_) {
sockMgr.addSocket((network::Socket*)commandData, &vncServer);
break;
case GetClientsInfo:
vncServer.getConnInfo((ListConnInfo*)commandData);
getConnInfo((ListConnInfo*)commandData);
break;
case SetClientsStatus:
vncServer.setConnStatus((ListConnInfo*)commandData);
setConnStatus((ListConnInfo*)commandData);
break;

case QueryConnectionComplete:
@@ -341,3 +340,82 @@ void VNCServerWin32::processEvent(HANDLE event_) {
}
}

void VNCServerWin32::getConnInfo(ListConnInfo * listConn)
{
std::list<network::Socket*> sockets;
std::list<network::Socket*>::iterator i;

listConn->Clear();
listConn->setDisable(sockMgr.getDisable(&vncServer));

vncServer.getSockets(&sockets);

for (i = sockets.begin(); i != sockets.end(); i++) {
rfb::SConnection* conn;
int status;

conn = vncServer.getConnection(*i);
if (!conn)
continue;

if (conn->accessCheck(rfb::SConnection::AccessPtrEvents |
rfb::SConnection::AccessKeyEvents |
rfb::SConnection::AccessView))
status = 0;
else if (conn->accessCheck(rfb::SConnection::AccessView))
status = 1;
else
status = 2;

listConn->addInfo((void*)(*i), (*i)->getPeerAddress(), status);
}
}

void VNCServerWin32::setConnStatus(ListConnInfo* listConn)
{
sockMgr.setDisable(&vncServer, listConn->getDisable());

if (listConn->Empty())
return;

for (listConn->iBegin(); !listConn->iEnd(); listConn->iNext()) {
network::Socket* sock;
rfb::SConnection* conn;
int status;

sock = (network::Socket*)listConn->iGetConn();

conn = vncServer.getConnection(sock);
if (!conn)
continue;

status = listConn->iGetStatus();
if (status == 3) {
conn->close(0);
} else {
rfb::SConnection::AccessRights ar;

ar = rfb::SConnection::AccessDefault;

switch (status) {
case 0:
ar |= rfb::SConnection::AccessPtrEvents |
rfb::SConnection::AccessKeyEvents |
rfb::SConnection::AccessView;
break;
case 1:
ar |= rfb::SConnection::AccessView;
ar &= ~(rfb::SConnection::AccessPtrEvents |
rfb::SConnection::AccessKeyEvents);
break;
case 2:
ar &= ~(rfb::SConnection::AccessPtrEvents |
rfb::SConnection::AccessKeyEvents |
rfb::SConnection::AccessView);
break;
}
conn->setAccessRights(ar);
conn->framebufferUpdateRequest(vncServer.getPixelBuffer()->getRect(), false);
}
}
}

+ 10
- 7
win/winvnc/VNCServerWin32.h View File

@@ -37,9 +37,10 @@ namespace os {

namespace winvnc {

class ListConnInfo;
class STrayIconThread;

class VNCServerWin32 : rfb::VNCServerST::QueryConnectionHandler,
class VNCServerWin32 : rfb::win32::QueryConnectionHandler,
rfb::win32::SocketManager::AddressChangeNotifier,
rfb::win32::RegConfig::Callback,
rfb::win32::EventHandler {
@@ -73,17 +74,16 @@ namespace winvnc {
// Where to read the configuration settings from
static const TCHAR* RegConfigPath;

bool getClientsInfo(rfb::ListConnInfo* LCInfo);
bool getClientsInfo(ListConnInfo* LCInfo);

bool setClientsStatus(rfb::ListConnInfo* LCInfo);
bool setClientsStatus(ListConnInfo* LCInfo);

protected:
// VNCServerST::QueryConnectionHandler interface
// QueryConnectionHandler interface
// Callback used to prompt user to accept or reject a connection.
// CALLBACK IN VNCServerST "HOST" THREAD
virtual rfb::VNCServerST::queryResult queryConnection(network::Socket* sock,
const char* userName,
char** reason);
virtual void queryConnection(network::Socket* sock,
const char* userName);

// SocketManager::AddressChangeNotifier interface
// Used to keep tray icon up to date
@@ -97,6 +97,9 @@ namespace winvnc {
// Used to perform queued commands
virtual void processEvent(HANDLE event);

void getConnInfo(ListConnInfo * listConn);
void setConnStatus(ListConnInfo* listConn);

protected:
// Perform a particular internal function in the server thread
typedef enum {NoCommand, DisconnectClients, AddClient, QueryConnectionComplete, SetClientsStatus, GetClientsInfo} Command;

Loading…
Cancel
Save