Merge branch 'connparams' of https://github.com/CendioOssman/tigervnc
diff --git a/.travis.yml b/.travis.yml
index 74878fc..ceafcbb 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -16,5 +16,5 @@
- popd
script:
- - cmake . && make
+ - cmake -DCMAKE_BUILD_TYPE=Debug . && make
- cd java && cmake . && make
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4fb3360..7a9a7ce 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -2,7 +2,7 @@
# Setup
#
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.11)
if(POLICY CMP0022)
cmake_policy(SET CMP0022 OLD)
endif()
@@ -43,9 +43,7 @@
endif()
if(NOT BUILD_TIMESTAMP)
- set(BUILD_TIMESTAMP "")
- execute_process(COMMAND "date" "+%Y-%m-%d %H:%M" OUTPUT_VARIABLE BUILD_TIMESTAMP)
- string(REGEX REPLACE "\n" "" BUILD_TIMESTAMP ${BUILD_TIMESTAMP})
+ STRING(TIMESTAMP BUILD_TIMESTAMP "%Y-%m-%d %H:%M" UTC)
endif()
# Default to optimised builds instead of debug ones. Our code has no bugs ;)
@@ -76,8 +74,8 @@
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wformat=2")
# Make sure we catch these issues whilst developing
IF(CMAKE_BUILD_TYPE MATCHES Debug)
- set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror")
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror -Werror=vla")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Werror=vla")
ENDIF()
option(ENABLE_ASAN "Enable address sanitizer support" OFF)
diff --git a/common/network/Socket.h b/common/network/Socket.h
index bfda8a5..d38feba 100644
--- a/common/network/Socket.h
+++ b/common/network/Socket.h
@@ -144,15 +144,6 @@
// This is only necessary if the Socket has been put in non-blocking
// mode and needs this callback to flush the buffer.
virtual void processSocketWriteEvent(network::Socket* sock) = 0;
-
- // checkTimeouts() allows the server to check socket timeouts, etc. The
- // return value is the number of milliseconds to wait before
- // checkTimeouts() should be called again. If this number is zero then
- // there is no timeout and checkTimeouts() should be called the next time
- // an event occurs.
- virtual int checkTimeouts() = 0;
-
- virtual bool getDisable() {return false;};
};
}
diff --git a/common/network/TcpSocket.cxx b/common/network/TcpSocket.cxx
index 51d77c7..9e277cb 100644
--- a/common/network/TcpSocket.cxx
+++ b/common/network/TcpSocket.cxx
@@ -736,7 +736,7 @@
buffer + 1, sizeof (buffer) - 2, NULL, 0, NI_NUMERICHOST);
strcat(buffer, "]");
addr.buf = rfb::strDup(buffer);
- } else if (p.address.u.sa.sa_family == AF_UNSPEC)
+ } else
addr.buf = rfb::strDup("");
char action;
diff --git a/common/rfb/CMsgReader.cxx b/common/rfb/CMsgReader.cxx
index 17152ab..3422ebf 100644
--- a/common/rfb/CMsgReader.cxx
+++ b/common/rfb/CMsgReader.cxx
@@ -208,7 +208,7 @@
if (width > maxCursorSize || height > maxCursorSize)
throw Exception("Too big cursor");
- rdr::U8 buf[width*height*4];
+ rdr::U8Array rgba(width*height*4);
if (width * height > 0) {
rdr::U8 pr, pg, pb;
@@ -233,7 +233,7 @@
is->readBytes(mask.buf, mask_len);
int maskBytesPerRow = (width+7)/8;
- out = buf;
+ out = rgba.buf;
for (y = 0;y < height;y++) {
for (x = 0;x < width;x++) {
int byte = y * maskBytesPerRow + x / 8;
@@ -259,7 +259,7 @@
}
}
- handler->setCursor(width, height, hotspot, buf);
+ handler->setCursor(width, height, hotspot, rgba.buf);
}
void CMsgReader::readSetCursor(int width, int height, const Point& hotspot)
@@ -273,7 +273,7 @@
rdr::U8Array mask(mask_len);
int x, y;
- rdr::U8 buf[width*height*4];
+ rdr::U8Array rgba(width*height*4);
rdr::U8* in;
rdr::U8* out;
@@ -282,7 +282,7 @@
int maskBytesPerRow = (width+7)/8;
in = data.buf;
- out = buf;
+ out = rgba.buf;
for (y = 0;y < height;y++) {
for (x = 0;x < width;x++) {
int byte = y * maskBytesPerRow + x / 8;
@@ -300,7 +300,7 @@
}
}
- handler->setCursor(width, height, hotspot, buf);
+ handler->setCursor(width, height, hotspot, rgba.buf);
}
void CMsgReader::readSetCursorWithAlpha(int width, int height, const Point& hotspot)
diff --git a/common/rfb/CSecurityTLS.cxx b/common/rfb/CSecurityTLS.cxx
index 72d148e..c6d1e31 100644
--- a/common/rfb/CSecurityTLS.cxx
+++ b/common/rfb/CSecurityTLS.cxx
@@ -94,9 +94,9 @@
delete [] homeDir;
if (!fileexists(caDefault.buf))
- X509CA.setDefaultStr(strdup(caDefault.buf));
+ X509CA.setDefaultStr(caDefault.buf);
if (!fileexists(crlDefault.buf))
- X509CRL.setDefaultStr(strdup(crlDefault.buf));
+ X509CRL.setDefaultStr(crlDefault.buf);
}
void CSecurityTLS::shutdown(bool needbye)
diff --git a/common/rfb/ComparingUpdateTracker.h b/common/rfb/ComparingUpdateTracker.h
index e62f2b2..ca1dcc3 100644
--- a/common/rfb/ComparingUpdateTracker.h
+++ b/common/rfb/ComparingUpdateTracker.h
@@ -50,7 +50,7 @@
bool firstCompare;
bool enabled;
- rdr::U32 totalPixels, missedPixels;
+ unsigned long long totalPixels, missedPixels;
};
}
diff --git a/common/rfb/Cursor.cxx b/common/rfb/Cursor.cxx
index 99df82d..d7b536d 100644
--- a/common/rfb/Cursor.cxx
+++ b/common/rfb/Cursor.cxx
@@ -76,7 +76,7 @@
}
// Floyd-Steinberg dithering
-static void dither(int width, int height, int* data)
+static void dither(int width, int height, rdr::S32* data)
{
for (int y = 0; y < height; y++) {
for (int x_ = 0; x_ < width; x_++) {
@@ -122,31 +122,33 @@
rdr::U8* Cursor::getBitmap() const
{
// First step is converting to luminance
- int luminance[width()*height()];
- int *lum_ptr = luminance;
+ rdr::S32Array luminance(width()*height());
+ rdr::S32 *lum_ptr = luminance.buf;
const rdr::U8 *data_ptr = data;
for (int y = 0; y < height(); y++) {
for (int x = 0; x < width(); x++) {
- // Use BT.709 coefficients for grayscale
- *lum_ptr = 0;
- *lum_ptr += (int)srgb_to_lin(data_ptr[0]) * 6947; // 0.2126
- *lum_ptr += (int)srgb_to_lin(data_ptr[1]) * 23436; // 0.7152
- *lum_ptr += (int)srgb_to_lin(data_ptr[2]) * 2366; // 0.0722
- *lum_ptr /= 32768;
+ rdr::S32 lum;
- lum_ptr++;
+ // Use BT.709 coefficients for grayscale
+ lum = 0;
+ lum += (rdr::U32)srgb_to_lin(data_ptr[0]) * 6947; // 0.2126
+ lum += (rdr::U32)srgb_to_lin(data_ptr[1]) * 23436; // 0.7152
+ lum += (rdr::U32)srgb_to_lin(data_ptr[2]) * 2366; // 0.0722
+ lum /= 32768;
+
+ *lum_ptr++ = lum;
data_ptr += 4;
}
}
// Then diterhing
- dither(width(), height(), luminance);
+ dither(width(), height(), luminance.buf);
// Then conversion to a bit mask
rdr::U8Array source((width()+7)/8*height());
memset(source.buf, 0, (width()+7)/8*height());
int maskBytesPerRow = (width() + 7) / 8;
- lum_ptr = luminance;
+ lum_ptr = luminance.buf;
data_ptr = data;
for (int y = 0; y < height(); y++) {
for (int x = 0; x < width(); x++) {
@@ -165,25 +167,24 @@
rdr::U8* Cursor::getMask() const
{
// First step is converting to integer array
- int alpha[width()*height()];
- int *alpha_ptr = alpha;
+ rdr::S32Array alpha(width()*height());
+ rdr::S32 *alpha_ptr = alpha.buf;
const rdr::U8 *data_ptr = data;
for (int y = 0; y < height(); y++) {
for (int x = 0; x < width(); x++) {
- *alpha_ptr = (int)data_ptr[3] * 65535 / 255;
- alpha_ptr++;
+ *alpha_ptr++ = (rdr::U32)data_ptr[3] * 65535 / 255;
data_ptr += 4;
}
}
// Then diterhing
- dither(width(), height(), alpha);
+ dither(width(), height(), alpha.buf);
// Then conversion to a bit mask
rdr::U8Array mask((width()+7)/8*height());
memset(mask.buf, 0, (width()+7)/8*height());
int maskBytesPerRow = (width() + 7) / 8;
- alpha_ptr = alpha;
+ alpha_ptr = alpha.buf;
data_ptr = data;
for (int y = 0; y < height(); y++) {
for (int x = 0; x < width(); x++) {
diff --git a/common/rfb/SConnection.cxx b/common/rfb/SConnection.cxx
index d0490de..690653a 100644
--- a/common/rfb/SConnection.cxx
+++ b/common/rfb/SConnection.cxx
@@ -277,13 +277,14 @@
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)
@@ -360,6 +361,11 @@
state_ = RFBSTATE_NORMAL;
}
+void SConnection::close(const char* reason)
+{
+ state_ = RFBSTATE_CLOSING;
+}
+
void SConnection::setPixelFormat(const PixelFormat& pf)
{
SMsgHandler::setPixelFormat(pf);
diff --git a/common/rfb/SConnection.h b/common/rfb/SConnection.h
index 47092e3..2630240 100644
--- a/common/rfb/SConnection.h
+++ b/common/rfb/SConnection.h
@@ -69,6 +69,13 @@
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 @@
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 @@
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 @@
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 @@
SSecurity* ssecurity;
stateEnum state_;
rdr::S32 preferredEncoding;
+ AccessRights accessRights;
};
}
#endif
diff --git a/common/rfb/SDesktop.h b/common/rfb/SDesktop.h
index 717ddbc..0060aa2 100644
--- a/common/rfb/SDesktop.h
+++ b/common/rfb/SDesktop.h
@@ -44,6 +44,8 @@
#include <rfb/screenTypes.h>
#include <rfb/util.h>
+namespace network { class Socket; }
+
namespace rfb {
class VNCServer;
@@ -56,14 +58,28 @@
// 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;
+
+ // terminate() is called by the server when it wishes to terminate
+ // itself, e.g. because it was configured to terminate when no one is
+ // using it.
+
+ virtual void terminate() = 0;
// setScreenLayout() requests to reconfigure the framebuffer and/or
// the layout of screens.
@@ -112,6 +128,10 @@
server->setPixelBuffer(0);
server = 0;
}
+ virtual void queryConnection(network::Socket* sock,
+ const char* userName) {
+ server->approveConnection(sock, true, NULL);
+ }
protected:
VNCServer* server;
diff --git a/common/rfb/SSecurityPlain.cxx b/common/rfb/SSecurityPlain.cxx
index 6d48b65..6f72432 100644
--- a/common/rfb/SSecurityPlain.cxx
+++ b/common/rfb/SSecurityPlain.cxx
@@ -41,7 +41,7 @@
bool PasswordValidator::validUser(const char* username)
{
- CharArray users(strDup(plainUsers.getValueStr())), user;
+ CharArray users(plainUsers.getValueStr()), user;
while (users.buf) {
strSplit(users.buf, ',', &user.buf, &users.buf);
diff --git a/common/rfb/TightDecoder.cxx b/common/rfb/TightDecoder.cxx
index fad4731..5b7c553 100644
--- a/common/rfb/TightDecoder.cxx
+++ b/common/rfb/TightDecoder.cxx
@@ -266,15 +266,16 @@
buflen -= 1;
if (pf.is888()) {
- rdr::U8 tightPalette[palSize * 3];
+ size_t len = palSize * 3;
+ rdr::U8Array tightPalette(len);
- assert(buflen >= sizeof(tightPalette));
+ assert(buflen >= len);
- memcpy(tightPalette, bufptr, sizeof(tightPalette));
- bufptr += sizeof(tightPalette);
- buflen -= sizeof(tightPalette);
+ memcpy(tightPalette.buf, bufptr, len);
+ bufptr += len;
+ buflen -= len;
- pf.bufferFromRGB(palette, tightPalette, palSize);
+ pf.bufferFromRGB(palette, tightPalette.buf, palSize);
} else {
size_t len;
diff --git a/common/rfb/VNCSConnectionST.cxx b/common/rfb/VNCSConnectionST.cxx
index a58fd09..ea5c52a 100644
--- a/common/rfb/VNCSConnectionST.cxx
+++ b/common/rfb/VNCSConnectionST.cxx
@@ -51,28 +51,31 @@
fenceDataLen(0), fenceData(NULL), congestionTimer(this),
losslessTimer(this), server(server_),
updateRenderedCursor(false), removeRenderedCursor(false),
- continuousUpdates(false), encodeManager(this), pointerEventTime(0),
- clientHasCursor(false),
- accessRights(AccessDefault), startTime(time(0))
+ continuousUpdates(false), encodeManager(this), idleTimer(this),
+ pointerEventTime(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);
+ // Kick off the idle timer
+ if (rfb::Server::idleTimeout) {
+ // minimum of 15 seconds while authenticating
+ if (rfb::Server::idleTimeout < 15)
+ idleTimer.start(secsToMillis(15));
+ else
+ idleTimer.start(secsToMillis(rfb::Server::idleTimeout));
+ }
}
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,19 +87,42 @@
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;
}
+// SConnection methods
+
+bool VNCSConnectionST::accessCheck(AccessRights ar) const
+{
+ // 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)
+{
+ // Log the reason for the close
+ if (!closeReason.buf)
+ closeReason.buf = strDup(reason);
+ else
+ vlog.debug("second close: %s (%s)", peerEndpoint.buf, reason);
+
+ // 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();
+
+ SConnection::close(reason);
+}
+
+
// Methods called from VNCServerST
bool VNCSConnectionST::init()
@@ -110,25 +136,6 @@
return true;
}
-void VNCSConnectionST::close(const char* reason)
-{
- // Log the reason for the close
- if (!closeReason.buf)
- closeReason.buf = strDup(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);
-}
-
void VNCSConnectionST::processMessages()
{
@@ -193,8 +200,8 @@
try {
if (!authenticated()) return;
if (client.width() && client.height() &&
- (server->pb->width() != client.width() ||
- server->pb->height() != client.height()))
+ (server->getPixelBuffer()->width() != client.width() ||
+ server->getPixelBuffer()->height() != client.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
@@ -211,10 +218,11 @@
// updates.add_changed(Rect(0, client.height(), client.width(),
// server->pb->height()));
- damagedCursorRegion.assign_intersect(server->pb->getRect());
+ damagedCursorRegion.assign_intersect(server->getPixelBuffer()->getRect());
- client.setDimensions(server->pb->width(), server->pb->height(),
- server->screenLayout);
+ client.setDimensions(server->getPixelBuffer()->width(),
+ server->getPixelBuffer()->height(),
+ server->getScreenLayout());
if (state() == RFBSTATE_NORMAL) {
if (!client.supportsDesktopSize()) {
close("Client does not support desktop resize");
@@ -224,12 +232,12 @@
}
// 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());
@@ -267,7 +275,7 @@
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);
@@ -310,36 +318,6 @@
}
-int VNCSConnectionST::checkIdleTimeout()
-{
- int idleTimeout = rfb::Server::idleTimeout;
- if (idleTimeout == 0) return 0;
- if (state() != RFBSTATE_NORMAL && idleTimeout < 15)
- idleTimeout = 15; // minimum of 15 seconds while authenticating
- time_t now = time(0);
- if (now < lastEventTime) {
- // Someone must have set the time backwards. Set lastEventTime so that the
- // idleTimeout will count from now.
- vlog.info("Time has gone backwards - resetting idle timeout");
- lastEventTime = now;
- }
- int timeLeft = lastEventTime + idleTimeout - now;
- if (timeLeft < -60) {
- // Our callback is over a minute late - someone must have set the time
- // forwards. Set lastEventTime so that the idleTimeout will count from
- // now.
- vlog.info("Time has gone forwards - resetting idle timeout");
- lastEventTime = now;
- return secsToMillis(idleTimeout);
- }
- if (timeLeft <= 0) {
- close("Idle timeout");
- return 0;
- }
- return secsToMillis(timeLeft);
-}
-
-
bool VNCSConnectionST::getComparerState()
{
// We interpret a low compression level as an indication that the client
@@ -385,7 +363,7 @@
if (!client.supportsLocalCursor())
return true;
- if (!server->cursorPos.equals(pointerEventPos) &&
+ if (!server->getCursorPos().equals(pointerEventPos) &&
(time(0) - pointerEventTime) > 0)
return true;
@@ -409,83 +387,40 @@
void VNCSConnectionST::authSuccess()
{
- lastEventTime = time(0);
-
- server->startDesktop();
+ if (rfb::Server::idleTimeout)
+ idleTimer.start(secsToMillis(rfb::Server::idleTimeout));
// - Set the connection parameters appropriately
- client.setDimensions(server->pb->width(), server->pb->height(),
- server->screenLayout);
+ client.setDimensions(server->getPixelBuffer()->width(),
+ server->getPixelBuffer()->height(),
+ server->getScreenLayout());
client.setName(server->getName());
- client.setLEDState(server->ledState);
+ client.setLEDState(server->getLEDState());
// - Set the default pixel format
- client.setPF(server->pb->getPF());
+ client.setPF(server->getPixelBuffer()->getPF());
char buffer[256];
client.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::idleTimeout)
+ idleTimer.start(secsToMillis(rfb::Server::idleTimeout));
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)
@@ -499,37 +434,32 @@
void VNCSConnectionST::pointerEvent(const Point& pos, int buttonMask)
{
- pointerEventTime = lastEventTime = time(0);
- server->lastUserInputTime = lastEventTime;
- if (!(accessRights & AccessPtrEvents)) return;
+ if (rfb::Server::idleTimeout)
+ idleTimer.start(secsToMillis(rfb::Server::idleTimeout));
+ pointerEventTime = time(0);
+ 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;
};
@@ -538,9 +468,9 @@
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 (rfb::Server::idleTimeout)
+ idleTimer.start(secsToMillis(rfb::Server::idleTimeout));
+ if (!accessCheck(AccessKeyEvents)) return;
if (!rfb::Server::acceptKeyEvents) return;
if (down)
@@ -548,18 +478,8 @@
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))) {
@@ -577,7 +497,7 @@
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)
@@ -587,12 +507,12 @@
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);
}
}
@@ -607,7 +527,7 @@
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
@@ -621,15 +541,15 @@
//
} 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();
@@ -655,21 +575,21 @@
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);
@@ -710,28 +630,11 @@
{
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()->writeDesktopSize(reasonClient, resultInvalid);
- 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()->writeDesktopSize(reasonClient, result);
-
- // 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[])
@@ -846,6 +749,9 @@
close(e.str());
}
+ if (t == &idleTimer)
+ close("Idle timeout");
+
return false;
}
@@ -966,7 +872,7 @@
void VNCSConnectionST::writeDataUpdate()
{
- Region req, pending;
+ Region req;
UpdateInfo ui;
bool needNewUpdateInfo;
const RenderedCursor *cursor;
@@ -980,9 +886,6 @@
if (req.is_empty())
return;
- // Get any framebuffer changes we haven't yet been informed of
- pending = server->getPendingRegion();
-
// Get the lists of updates. Prior to exporting the data to the `ui' object,
// getUpdateInfo() will normalize the `updates' object such way that its
// `changed' and `copied' regions would not intersect.
@@ -998,7 +901,7 @@
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;
@@ -1031,13 +934,8 @@
// If there are queued updates then we cannot safely send an update
// without risking a partially updated screen
-
- if (!pending.is_empty()) {
- // However we might still be able to send a lossless refresh
- req.assign_subtract(pending);
- req.assign_subtract(ui.changed);
- req.assign_subtract(ui.copied);
-
+ if (!server->getPendingRegion().is_empty()) {
+ req.clear();
ui.changed.clear();
ui.copied.clear();
}
@@ -1063,48 +961,17 @@
damagedCursorRegion.assign_union(ui.changed.intersect(renderedCursorRect));
}
- // Return if there is nothing to send the client.
+ // If we don't have a normal update, then try a lossless refresh
if (ui.is_empty() && !writer()->needFakeUpdate()) {
- int eta;
-
- // Any lossless refresh that needs handling?
- if (!encodeManager.needsLosslessRefresh(req))
- return;
-
- // Now? Or later?
- eta = encodeManager.getNextLosslessRefresh(req);
- if (eta > 0) {
- losslessTimer.start(eta);
- return;
- }
+ writeLosslessRefresh();
+ return;
}
+ // We have something to send, so let's get to it
+
writeRTTPing();
- if (!ui.is_empty())
- encodeManager.writeUpdate(ui, server->getPixelBuffer(), cursor);
- else {
- int nextUpdate;
-
- // FIXME: If continuous updates aren't used then the client might
- // be slower than frameRate in its requests and we could
- // afford a larger update size
- nextUpdate = server->msToNextUpdate();
- if (nextUpdate > 0) {
- size_t bandwidth, maxUpdateSize;
-
- // FIXME: Bandwidth estimation without congestion control
- bandwidth = congestion.getBandwidth();
-
- // FIXME: Hard coded value for maximum CPU throughput
- if (bandwidth > 5000000)
- bandwidth = 5000000;
-
- maxUpdateSize = bandwidth * nextUpdate / 1000;
- encodeManager.writeLosslessRefresh(req, server->getPixelBuffer(),
- cursor, maxUpdateSize);
- }
- }
+ encodeManager.writeUpdate(ui, server->getPixelBuffer(), cursor);
writeRTTPing();
@@ -1115,6 +982,80 @@
requested.clear();
}
+void VNCSConnectionST::writeLosslessRefresh()
+{
+ Region req, pending;
+ const RenderedCursor *cursor;
+
+ int nextRefresh, nextUpdate;
+ size_t bandwidth, maxUpdateSize;
+
+ if (continuousUpdates)
+ req = cuRegion.union_(requested);
+ else
+ req = requested;
+
+ // If there are queued updates then we could not safely send an
+ // update without risking a partially updated screen, however we
+ // might still be able to send a lossless refresh
+ pending = server->getPendingRegion();
+ if (!pending.is_empty()) {
+ UpdateInfo ui;
+
+ // Don't touch the updates pending in the server core
+ req.assign_subtract(pending);
+
+ // Or any updates pending just for this connection
+ updates.getUpdateInfo(&ui, req);
+ req.assign_subtract(ui.changed);
+ req.assign_subtract(ui.copied);
+ }
+
+ // Any lossy area we can refresh?
+ if (!encodeManager.needsLosslessRefresh(req))
+ return;
+
+ // Right away? Or later?
+ nextRefresh = encodeManager.getNextLosslessRefresh(req);
+ if (nextRefresh > 0) {
+ losslessTimer.start(nextRefresh);
+ return;
+ }
+
+ // Prepare the cursor in case it overlaps with a region getting
+ // refreshed
+ cursor = NULL;
+ if (needRenderedCursor())
+ cursor = server->getRenderedCursor();
+
+ // FIXME: If continuous updates aren't used then the client might
+ // be slower than frameRate in its requests and we could
+ // afford a larger update size
+ nextUpdate = server->msToNextUpdate();
+
+ // Don't bother if we're about to send a real update
+ if (nextUpdate == 0)
+ return;
+
+ // FIXME: Bandwidth estimation without congestion control
+ bandwidth = congestion.getBandwidth();
+
+ // FIXME: Hard coded value for maximum CPU throughput
+ if (bandwidth > 5000000)
+ bandwidth = 5000000;
+
+ maxUpdateSize = bandwidth * nextUpdate / 1000;
+
+ writeRTTPing();
+
+ encodeManager.writeLosslessRefresh(req, server->getPixelBuffer(),
+ cursor, maxUpdateSize);
+
+ writeRTTPing();
+
+ requested.clear();
+}
+
void VNCSConnectionST::screenLayoutChange(rdr::U16 reason)
{
@@ -1122,7 +1063,7 @@
return;
client.setDimensions(client.width(), client.height(),
- server->screenLayout);
+ server->getScreenLayout());
if (state() != RFBSTATE_NORMAL)
return;
@@ -1145,7 +1086,7 @@
client.setCursor(emptyCursor);
clientHasCursor = false;
} else {
- client.setCursor(*server->cursor);
+ client.setCursor(*server->getCursor());
clientHasCursor = true;
}
@@ -1178,43 +1119,8 @@
void VNCSConnectionST::setSocketTimeouts()
{
int timeoutms = rfb::Server::clientWaitTimeMillis;
- soonestTimeout(&timeoutms, secsToMillis(rfb::Server::idleTimeout));
if (timeoutms == 0)
timeoutms = -1;
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;
-}
-
diff --git a/common/rfb/VNCSConnectionST.h b/common/rfb/VNCSConnectionST.h
index dfc8bcb..662d9f3 100644
--- a/common/rfb/VNCSConnectionST.h
+++ b/common/rfb/VNCSConnectionST.h
@@ -43,21 +43,18 @@
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,9 @@
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 +95,18 @@
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 +126,6 @@
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);
@@ -171,6 +143,7 @@
void writeFramebufferUpdate();
void writeNoDataUpdate();
void writeDataUpdate();
+ void writeLosslessRefresh();
void screenLayoutChange(rdr::U16 reason);
void setCursor();
@@ -178,6 +151,7 @@
void setLEDState(unsigned int state);
void setSocketTimeouts();
+ private:
network::Socket* sock;
CharArray peerEndpoint;
bool reverseConnection;
@@ -204,15 +178,13 @@
std::map<rdr::U32, rdr::U32> pressedKeys;
- time_t lastEventTime;
+ Timer idleTimer;
+
time_t pointerEventTime;
Point pointerEventPos;
bool clientHasCursor;
- AccessRights accessRights;
-
CharArray closeReason;
- time_t startTime;
};
}
#endif
diff --git a/common/rfb/VNCServer.h b/common/rfb/VNCServer.h
index c5335ad..298326f 100644
--- a/common/rfb/VNCServer.h
+++ b/common/rfb/VNCServer.h
@@ -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 @@
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 @@
// 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.
diff --git a/common/rfb/VNCServerST.cxx b/common/rfb/VNCServerST.cxx
index a9ae62e..c95c14f 100644
--- a/common/rfb/VNCServerST.cxx
+++ b/common/rfb/VNCServerST.cxx
@@ -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,12 +80,17 @@
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),
+ keyRemapper(&KeyRemapper::defInstance),
+ idleTimer(this), disconnectTimer(this), connectTimer(this),
frameTimer(this)
{
- lastUserInputTime = lastDisconnectTime = time(0);
slog.debug("creating single-threaded server %s", name.buf);
+
+ // FIXME: Do we really want to kick off these right away?
+ if (rfb::Server::maxIdleTime)
+ idleTimer.start(secsToMillis(rfb::Server::maxIdleTime));
+ if (rfb::Server::maxDisconnectionTime)
+ disconnectTimer.start(secsToMillis(rfb::Server::maxDisconnectionTime));
}
VNCServerST::~VNCServerST()
@@ -99,9 +104,11 @@
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 +132,13 @@
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 +146,17 @@
return;
}
- if (clients.empty()) {
- lastConnectionTime = time(0);
- }
+ CharArray name;
+ name.buf = sock->getPeerEndpoint();
+ connectionsLog.status("accepted: %s", name.buf);
+
+ // Adjust the exit timers
+ if (rfb::Server::maxConnectionTime && clients.empty())
+ connectTimer.start(secsToMillis(rfb::Server::maxConnectionTime));
+ disconnectTimer.stop();
VNCSConnectionST* client = new VNCSConnectionST(this, sock, outgoing);
+ clients.push_front(client);
client->init();
}
@@ -147,9 +165,24 @@
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;
+
+ // Adjust the exit timers
+ connectTimer.stop();
+ if (rfb::Server::maxDisconnectionTime && clients.empty())
+ disconnectTimer.start(secsToMillis(rfb::Server::maxDisconnectionTime));
+
// - 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();
@@ -191,89 +224,6 @@
throw rdr::Exception("invalid Socket in VNCServerST");
}
-int VNCServerST::checkTimeouts()
-{
- int timeout = 0;
- std::list<VNCSConnectionST*>::iterator ci, ci_next;
-
- soonestTimeout(&timeout, Timer::checkTimeouts());
-
- for (ci=clients.begin();ci!=clients.end();ci=ci_next) {
- ci_next = ci; ci_next++;
- soonestTimeout(&timeout, (*ci)->checkIdleTimeout());
- }
-
- int timeLeft;
- time_t now = time(0);
-
- // Check MaxDisconnectionTime
- if (rfb::Server::maxDisconnectionTime && clients.empty()) {
- if (now < lastDisconnectTime) {
- // Someone must have set the time backwards.
- slog.info("Time has gone backwards - resetting lastDisconnectTime");
- lastDisconnectTime = now;
- }
- timeLeft = lastDisconnectTime + rfb::Server::maxDisconnectionTime - now;
- if (timeLeft < -60) {
- // Someone must have set the time forwards.
- slog.info("Time has gone forwards - resetting lastDisconnectTime");
- lastDisconnectTime = now;
- timeLeft = rfb::Server::maxDisconnectionTime;
- }
- if (timeLeft <= 0) {
- slog.info("MaxDisconnectionTime reached, exiting");
- exit(0);
- }
- soonestTimeout(&timeout, timeLeft * 1000);
- }
-
- // Check MaxConnectionTime
- if (rfb::Server::maxConnectionTime && lastConnectionTime && !clients.empty()) {
- if (now < lastConnectionTime) {
- // Someone must have set the time backwards.
- slog.info("Time has gone backwards - resetting lastConnectionTime");
- lastConnectionTime = now;
- }
- timeLeft = lastConnectionTime + rfb::Server::maxConnectionTime - now;
- if (timeLeft < -60) {
- // Someone must have set the time forwards.
- slog.info("Time has gone forwards - resetting lastConnectionTime");
- lastConnectionTime = now;
- timeLeft = rfb::Server::maxConnectionTime;
- }
- if (timeLeft <= 0) {
- slog.info("MaxConnectionTime reached, exiting");
- exit(0);
- }
- soonestTimeout(&timeout, timeLeft * 1000);
- }
-
-
- // Check MaxIdleTime
- if (rfb::Server::maxIdleTime) {
- if (now < lastUserInputTime) {
- // Someone must have set the time backwards.
- slog.info("Time has gone backwards - resetting lastUserInputTime");
- lastUserInputTime = now;
- }
- timeLeft = lastUserInputTime + rfb::Server::maxIdleTime - now;
- if (timeLeft < -60) {
- // Someone must have set the time forwards.
- slog.info("Time has gone forwards - resetting lastUserInputTime");
- lastUserInputTime = now;
- timeLeft = rfb::Server::maxIdleTime;
- }
- if (timeLeft <= 0) {
- slog.info("MaxIdleTime reached, exiting");
- exit(0);
- }
- soonestTimeout(&timeout, timeLeft * 1000);
- }
-
- return timeout;
-}
-
-
// VNCServer methods
void VNCServerST::blockUpdates()
@@ -470,6 +420,83 @@
}
}
+// Event handlers
+
+void VNCServerST::keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down)
+{
+ if (rfb::Server::maxIdleTime)
+ idleTimer.start(secsToMillis(rfb::Server::maxIdleTime));
+
+ // 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)
+{
+ if (rfb::Server::maxIdleTime)
+ idleTimer.start(secsToMillis(rfb::Server::maxIdleTime));
+
+ // 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,
@@ -507,7 +534,7 @@
}
}
-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)
@@ -532,11 +559,77 @@
}
return true;
+ } else if (t == &idleTimer) {
+ slog.info("MaxIdleTime reached, exiting");
+ desktop->terminate();
+ } else if (t == &disconnectTimer) {
+ slog.info("MaxDisconnectionTime reached, exiting");
+ desktop->terminate();
+ } else if (t == &connectTimer) {
+ slog.info("MaxConnectionTime reached, exiting");
+ desktop->terminate();
}
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()
@@ -692,50 +785,6 @@
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)
diff --git a/common/rfb/VNCServerST.h b/common/rfb/VNCServerST.h
index b7845dd..43a3bb9 100644
--- a/common/rfb/VNCServerST.h
+++ b/common/rfb/VNCServerST.h
@@ -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 @@
class KeyRemapper;
class VNCServerST : public VNCServer,
- public Timer::Callback,
- public network::SocketServer {
+ public Timer::Callback {
public:
// -=- Constructors
@@ -79,12 +76,6 @@
// Flush pending data from the Socket on to the network.
virtual void processSocketWriteEvent(network::Socket* sock);
- // checkTimeouts
- // Returns the number of milliseconds left until the next idle timeout
- // expires. If any have already expired, the corresponding connections
- // are closed. Zero is returned if there is no idle timeout.
- virtual int checkTimeouts();
-
// Methods overridden from VNCServer
@@ -93,102 +84,70 @@
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 ®ion);
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 +156,17 @@
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,29 +190,11 @@
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 idleTimer;
+ Timer disconnectTimer;
+ Timer connectTimer;
Timer frameTimer;
};
diff --git a/contrib/packages/deb/ubuntu-trusty/debian/rules b/contrib/packages/deb/ubuntu-trusty/debian/rules
index 81f4f89..ea9f143 100755
--- a/contrib/packages/deb/ubuntu-trusty/debian/rules
+++ b/contrib/packages/deb/ubuntu-trusty/debian/rules
@@ -151,7 +151,7 @@
# anything for this package.
#/usr/bin/docbook-to-man debian/vnc.sgml > vnc.1
(cd media;make)
- (cd java;cmake -G"Unix Makefiles";make)
+ #(cd java;cmake -G"Unix Makefiles";make)
touch build-indep-stamp
@@ -213,8 +213,8 @@
mv $(CURDIR)/debian/xtigervncviewer/usr/share/man/man1/vncviewer.1 \
$(CURDIR)/debian/xtigervncviewer/usr/share/man/man1/xtigervncviewer.1
# tigervnc-java
- mkdir -p $(CURDIR)/debian/tigervnc-java/usr/share
- (cd java; make install DESTDIR=$(CURDIR)/debian/tigervnc-java/usr/share)
+ #mkdir -p $(CURDIR)/debian/tigervnc-java/usr/share
+ #(cd java; make install DESTDIR=$(CURDIR)/debian/tigervnc-java/usr/share)
#dh_movefiles
# Build architecture-independent files here.
diff --git a/contrib/packages/deb/ubuntu-xenial/debian/rules b/contrib/packages/deb/ubuntu-xenial/debian/rules
index 531a1c4..7509e7b 100644
--- a/contrib/packages/deb/ubuntu-xenial/debian/rules
+++ b/contrib/packages/deb/ubuntu-xenial/debian/rules
@@ -138,7 +138,7 @@
# anything for this package.
#/usr/bin/docbook-to-man debian/vnc.sgml > vnc.1
(cd media;make)
- (cd java;cmake -G"Unix Makefiles";make)
+ #(cd java;cmake -G"Unix Makefiles";make)
touch build-indep-stamp
@@ -204,15 +204,15 @@
mv $(CURDIR)/debian/tigervncserver/usr/share/icons \
$(CURDIR)/debian/xtigervncviewer/usr/share/
# tigervnc-java
- mkdir -p $(CURDIR)/debian/tigervnc-java/usr/share
- (cd java; make install DESTDIR=$(CURDIR)/debian/tigervnc-java/usr/share)
+ #mkdir -p $(CURDIR)/debian/tigervnc-java/usr/share
+ #(cd java; make install DESTDIR=$(CURDIR)/debian/tigervnc-java/usr/share)
# install additional license files
mkdir -p $(CURDIR)/debian/xtigervncviewer/usr/share/doc/xtigervncviewer
cp $(CURDIR)/debian/tigervncserver/usr/share/doc/tigervnc-*/* \
$(CURDIR)/debian/xtigervncviewer/usr/share/doc/xtigervncviewer/
- mkdir -p $(CURDIR)/debian/tigervnc-java/usr/share/doc/tigervnc-java
- cp $(CURDIR)/debian/tigervncserver/usr/share/doc/tigervnc-*/* \
- $(CURDIR)/debian/tigervnc-java/usr/share/doc/tigervnc-java/
+ #mkdir -p $(CURDIR)/debian/tigervnc-java/usr/share/doc/tigervnc-java
+ #cp $(CURDIR)/debian/tigervncserver/usr/share/doc/tigervnc-*/* \
+ #$(CURDIR)/debian/tigervnc-java/usr/share/doc/tigervnc-java/
mkdir -p $(CURDIR)/debian/tigervncserver/usr/share/doc/tigervncserver
mv $(CURDIR)/debian/tigervncserver/usr/share/doc/tigervnc-*/* \
$(CURDIR)/debian/tigervncserver/usr/share/doc/tigervncserver/
diff --git a/contrib/packages/rpm/el7/SPECS/tigervnc.spec b/contrib/packages/rpm/el7/SPECS/tigervnc.spec
index 1b8630a..77db826 100644
--- a/contrib/packages/rpm/el7/SPECS/tigervnc.spec
+++ b/contrib/packages/rpm/el7/SPECS/tigervnc.spec
@@ -9,8 +9,8 @@
%endif
Name: tigervnc
-Version: 1.6.80
-Release: 1%{?snap:.%{snap}}%{?dist}
+Version: 1.9.80
+Release: 2%{?snap:.%{snap}}%{?dist}
Summary: A TigerVNC remote display system
Group: User Interface/Desktops
@@ -151,7 +151,7 @@
for all in `find . -type f -perm -001`; do
chmod -x "$all"
done
-patch -p1 -b --suffix .vnc < ../xserver119.patch
+patch -p1 -b --suffix .vnc < ../xserver120.patch
popd
# Don't use shebang in vncserver script.
@@ -219,7 +219,7 @@
--with-fontdir=%{_datadir}/X11/fonts \
--with-xkb-output=%{_localstatedir}/lib/xkb \
--enable-install-libxf86config \
- --enable-glx --disable-dri --enable-dri2 \
+ --enable-glx --disable-dri --enable-dri2 --disable-dri3 \
--disable-wayland \
--disable-present \
--disable-config-dbus \
@@ -354,6 +354,9 @@
%endif
%changelog
+* Sun Nov 26 2018 Brian P. Hinz <bphinz@users.sourceforge.net> 1.9.80-2
+- Bumped Xorg version to 1.2.0
+
* Sun Jul 22 2018 Brian P. Hinz <bphinz@users.sourceforge.net> 1.9.80-1
- Updated fltk to latest version
diff --git a/java/CMakeLists.txt b/java/CMakeLists.txt
index 23137f7..da24dcf 100644
--- a/java/CMakeLists.txt
+++ b/java/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.11)
project(tigervnc-java Java)
if(NOT VERSION)
@@ -25,13 +25,10 @@
set(JAVA_TSA_URL NOTFOUND CACHE STRING "URL of Time Stamping Authority (TSA)")
if(NOT BUILD)
- execute_process(COMMAND "date" "+%Y%m%d" OUTPUT_VARIABLE BUILD)
+ STRING(TIMESTAMP BUILD "%Y%m%d" UTC)
endif()
-execute_process(COMMAND "date" "+%b %d %Y" OUTPUT_VARIABLE JAVA_DATE)
-execute_process(COMMAND "date" "+%H:%M:%S" OUTPUT_VARIABLE JAVA_TIME)
-string(REGEX REPLACE "\n" "" JAVA_DATE ${JAVA_DATE})
-string(REGEX REPLACE "\n" "" JAVA_TIME ${JAVA_TIME})
-string(REGEX REPLACE "\n" "" BUILD ${BUILD})
+STRING(TIMESTAMP JAVA_DATE "%Y-%m-%d" UTC)
+STRING(TIMESTAMP JAVA_TIME "%H:%M:%S" UTC)
set(JAVA_SOURCES "")
set(JAVA_CLASSES "")
diff --git a/tests/encperf.cxx b/tests/encperf.cxx
index 6f9283b..6523eb7 100644
--- a/tests/encperf.cxx
+++ b/tests/encperf.cxx
@@ -421,8 +421,9 @@
}
int runCount = count;
- struct stats runs[runCount];
- double values[runCount], dev[runCount];
+ struct stats *runs = new struct stats[runCount];
+ double *values = new double[runCount];
+ double *dev = new double[runCount];
double median, meddev;
if (fn == NULL) {
diff --git a/unix/tx/TXWindow.cxx b/unix/tx/TXWindow.cxx
index a681917..6129840 100644
--- a/unix/tx/TXWindow.cxx
+++ b/unix/tx/TXWindow.cxx
@@ -24,6 +24,7 @@
#include <list>
#include <stdio.h>
#include <stdlib.h>
+#include <vector>
#include <rfb/util.h>
std::list<TXWindow*> windows;
@@ -132,20 +133,20 @@
void TXWindow::getColours(Display* dpy, XColor* cols, int nCols)
{
- bool* got = new bool[nCols];
+ std::vector<bool> got;
+
bool failed = false;
int i;
for (i = 0; i < nCols; i++) {
if (XAllocColor(dpy, cmap, &cols[i])) {
- got[i] = true;
+ got.push_back(true);
} else {
- got[i] = false;
+ got.push_back(false);
failed = true;
}
}
if (!failed) {
- delete [] got;
return;
}
@@ -168,12 +169,13 @@
int cmapSize = DisplayCells(dpy,DefaultScreen(dpy));
XColor* cm = new XColor[cmapSize];
- bool* shared = new bool[cmapSize];
- bool* usedAsNearest = new bool[cmapSize];
+ std::vector<bool> shared;
+ std::vector<bool> usedAsNearest;
for (i = 0; i < cmapSize; i++) {
cm[i].pixel = i;
- shared[i] = usedAsNearest[i] = false;
+ shared.push_back(false);
+ usedAsNearest.push_back(false);
}
XQueryColors(dpy, cmap, cm, cmapSize);
diff --git a/unix/vncpasswd/vncpasswd.cxx b/unix/vncpasswd/vncpasswd.cxx
index 8bd4e48..3055223 100644
--- a/unix/vncpasswd/vncpasswd.cxx
+++ b/unix/vncpasswd/vncpasswd.cxx
@@ -134,7 +134,7 @@
} else if (argv[i][0] == '-') {
usage();
} else if (!fname) {
- fname = argv[i];
+ fname = strDup(argv[i]);
} else {
usage();
}
@@ -165,24 +165,37 @@
FILE* fp = fopen(fname,"w");
if (!fp) {
fprintf(stderr,"Couldn't open %s for writing\n",fname);
+ delete [] fname;
+ delete obfuscated;
+ delete obfuscatedReadOnly;
exit(1);
}
chmod(fname, S_IRUSR|S_IWUSR);
if (fwrite(obfuscated->buf, obfuscated->length, 1, fp) != 1) {
fprintf(stderr,"Writing to %s failed\n",fname);
+ delete [] fname;
+ delete obfuscated;
+ delete obfuscatedReadOnly;
exit(1);
}
+ delete obfuscated;
+
if (obfuscatedReadOnly) {
if (fwrite(obfuscatedReadOnly->buf, obfuscatedReadOnly->length, 1, fp) != 1) {
fprintf(stderr,"Writing to %s failed\n",fname);
+ delete [] fname;
+ delete obfuscatedReadOnly;
exit(1);
}
}
fclose(fp);
+ delete [] fname;
+ delete obfuscatedReadOnly;
+
return 0;
}
}
diff --git a/unix/x0vncserver/XDesktop.cxx b/unix/x0vncserver/XDesktop.cxx
index e77e765..564b2d5 100644
--- a/unix/x0vncserver/XDesktop.cxx
+++ b/unix/x0vncserver/XDesktop.cxx
@@ -18,6 +18,12 @@
* USA.
*/
+#include <assert.h>
+#include <signal.h>
+#include <unistd.h>
+
+#include <rfb/LogWriter.h>
+
#include <x0vncserver/XDesktop.h>
#include <X11/XKBlib.h>
@@ -53,6 +59,10 @@
"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 +73,7 @@
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 +238,7 @@
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 +265,9 @@
XDamageDestroy(dpy, damage);
#endif
+ delete queryConnectDialog;
+ queryConnectDialog = 0;
+
server->setPixelBuffer(0);
server = 0;
@@ -261,10 +275,38 @@
pb = 0;
}
+void XDesktop::terminate() {
+ kill(getpid(), SIGTERM);
+}
+
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;
@@ -630,6 +672,8 @@
dev = (XDamageNotifyEvent*)ev;
rect.setXYWH(dev->area.x, dev->area.y, dev->area.width, dev->area.height);
+ rect = rect.translate(Point(-geometry->offsetLeft(),
+ -geometry->offsetTop()));
server->add_changed(rect);
return true;
@@ -703,6 +747,21 @@
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;
diff --git a/unix/x0vncserver/XDesktop.h b/unix/x0vncserver/XDesktop.h
index ff52c01..3e85aac 100644
--- a/unix/x0vncserver/XDesktop.h
+++ b/unix/x0vncserver/XDesktop.h
@@ -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);
@@ -45,7 +49,10 @@
// -=- SDesktop interface
virtual void start(rfb::VNCServer* vs);
virtual void stop();
+ virtual void terminate();
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 +63,17 @@
// -=- 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;
diff --git a/unix/x0vncserver/x0vncserver.cxx b/unix/x0vncserver/x0vncserver.cxx
index d0d4be8..eac9edf 100644
--- a/unix/x0vncserver/x0vncserver.cxx
+++ b/unix/x0vncserver/x0vncserver.cxx
@@ -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 @@
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 @@
}
-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
{
@@ -256,9 +206,6 @@
Configuration::enableServerParams();
- // Disable configuration parameters which we do not support
- Configuration::removeParam("AcceptSetDesktopSize");
-
for (int i = 1; i < argc; i++) {
if (Configuration::setParam(argv[i]))
continue;
@@ -307,8 +254,6 @@
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));
@@ -374,7 +319,7 @@
}
}
- soonestTimeout(&wait_ms, server.checkTimeouts());
+ soonestTimeout(&wait_ms, Timer::checkTimeouts());
tv.tv_sec = wait_ms / 1000;
tv.tv_usec = (wait_ms % 1000) * 1000;
@@ -409,7 +354,7 @@
}
}
- server.checkTimeouts();
+ Timer::checkTimeouts();
// Client list could have been changed.
server.getSockets(&sockets);
diff --git a/unix/x0vncserver/x0vncserver.man b/unix/x0vncserver/x0vncserver.man
index 5f1508c..5aaf694 100644
--- a/unix/x0vncserver/x0vncserver.man
+++ b/unix/x0vncserver/x0vncserver.man
@@ -187,6 +187,10 @@
Accept pointer press and release events from clients. Default is on.
.
.TP
+.B \-AcceptSetDesktopSize
+Accept requests to resize the size of the desktop. Default is on.
+.
+.TP
.B \-RemapKeys \fImapping
Sets up a keyboard mapping.
.I mapping
diff --git a/unix/xserver/hw/vnc/InputXKB.c b/unix/xserver/hw/vnc/InputXKB.c
index 50a2130..f84a6e4 100644
--- a/unix/xserver/hw/vnc/InputXKB.c
+++ b/unix/xserver/hw/vnc/InputXKB.c
@@ -1,6 +1,6 @@
/* Copyright (C) 2009 TightVNC Team
* Copyright (C) 2009 Red Hat, Inc.
- * Copyright 2013-2015 Pierre Ossman for Cendio AB
+ * Copyright 2013-2018 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -52,6 +52,14 @@
extern DeviceIntPtr vncKeyboardDev;
+static const KeyCode fakeKeys[] = {
+#ifdef __linux__
+ 92, 203, 204, 205, 206, 207
+#else
+ 8, 124, 125, 156, 127, 128
+#endif
+ };
+
static void vncXkbProcessDeviceEvent(int screenNum,
InternalEvent *event,
DeviceIntPtr dev);
@@ -430,17 +438,20 @@
KeyCode vncKeysymToKeycode(KeySym keysym, unsigned state, unsigned *new_state)
{
XkbDescPtr xkb;
- unsigned int key;
+ unsigned int key; // KeyCode has insufficient range for the loop
+ KeyCode fallback;
KeySym ks;
unsigned level_three_mask;
if (new_state != NULL)
*new_state = state;
+ fallback = 0;
xkb = GetMaster(vncKeyboardDev, KEYBOARD_OR_FLOAT)->key->xkbInfo->desc;
for (key = xkb->min_key_code; key <= xkb->max_key_code; key++) {
unsigned int state_out;
KeySym dummy;
+ size_t fakeIdx;
XkbTranslateKeyCode(xkb, key, state, &state_out, &ks);
if (ks == NoSymbol)
@@ -456,10 +467,35 @@
if (state_out & LockMask)
XkbConvertCase(ks, &dummy, &ks);
- if (ks == keysym)
- return key;
+ if (ks != keysym)
+ continue;
+
+ /*
+ * Some keys are never sent by a real keyboard and are
+ * used in the default layouts as a fallback for
+ * modifiers. Make sure we use them last as some
+ * applications can be confused by these normally
+ * unused keys.
+ */
+ for (fakeIdx = 0;
+ fakeIdx < sizeof(fakeKeys)/sizeof(fakeKeys[0]);
+ fakeIdx++) {
+ if (key == fakeKeys[fakeIdx]) {
+ if (fallback == 0)
+ fallback = key;
+ break;
+ }
+ }
+ if (fakeIdx < sizeof(fakeKeys)/sizeof(fakeKeys[0]))
+ continue;
+
+ return key;
}
+ /* Use the fallback key, if one was found */
+ if (fallback != 0)
+ return fallback;
+
if (new_state == NULL)
return 0;
diff --git a/unix/xserver/hw/vnc/XserverDesktop.cc b/unix/xserver/hw/vnc/XserverDesktop.cc
index 04107dc..d8b3a4d 100644
--- a/unix/xserver/hw/vnc/XserverDesktop.cc
+++ b/unix/xserver/hw/vnc/XserverDesktop.cc
@@ -22,6 +22,7 @@
//
#include <assert.h>
+#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
@@ -81,7 +82,6 @@
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 +145,31 @@
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 +180,6 @@
queryConnectSocket = sock;
queryConnectTimer.start(queryConnectTimeout * 1000);
-
- return rfb::VNCServerST::PENDING;
}
void XserverDesktop::bell()
@@ -361,7 +368,7 @@
}
// Trigger timers and check when the next will expire
- int nextTimeout = server->checkTimeouts();
+ int nextTimeout = Timer::checkTimeouts();
if (nextTimeout > 0 && (*timeout == -1 || nextTimeout < *timeout))
*timeout = nextTimeout;
} catch (rdr::Exception& e) {
@@ -417,6 +424,11 @@
// SDesktop callbacks
+void XserverDesktop::terminate()
+{
+ kill(getpid(), SIGTERM);
+}
+
void XserverDesktop::pointerEvent(const Point& pos, int buttonMask)
{
vncPointerMove(pos.x + vncGetScreenX(screenIndex),
diff --git a/unix/xserver/hw/vnc/XserverDesktop.h b/unix/xserver/hw/vnc/XserverDesktop.h
index 014fcb5..1253935 100644
--- a/unix/xserver/hw/vnc/XserverDesktop.h
+++ b/unix/xserver/hw/vnc/XserverDesktop.h
@@ -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 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,11 @@
const char* rejectMsg=0);
// rfb::SDesktop callbacks
+ virtual void start(rfb::VNCServer* vs);
+ virtual void stop();
+ virtual void terminate();
+ 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 +99,6 @@
// 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 +112,7 @@
private:
int screenIndex;
- rfb::VNCServerST* server;
+ rfb::VNCServer* server;
std::list<network::SocketListener*> listeners;
bool directFbptr;
diff --git a/unix/xserver/hw/vnc/vncExtInit.cc b/unix/xserver/hw/vnc/vncExtInit.cc
index 286a04f..20072f4 100644
--- a/unix/xserver/hw/vnc/vncExtInit.cc
+++ b/unix/xserver/hw/vnc/vncExtInit.cc
@@ -179,7 +179,7 @@
listeners.push_back(new network::TcpListener(vncInetdSock));
vlog.info("inetd wait");
}
- } else if (rfbunixpath.getValueStr()[0] != '\0') {
+ } else if (((const char*)rfbunixpath)[0] != '\0') {
char path[PATH_MAX];
int mode = (int)rfbunixmode;
@@ -187,7 +187,7 @@
strncpy(path, rfbunixpath, sizeof(path));
else
snprintf(path, sizeof(path), "%s.%d",
- rfbunixpath.getValueStr(), scr);
+ (const char*)rfbunixpath, scr);
path[sizeof(path)-1] = '\0';
listeners.push_back(new network::UnixListener(path, mode));
diff --git a/unix/xserver/hw/vnc/vncSelection.c b/unix/xserver/hw/vnc/vncSelection.c
index 51dfd9c..4f3538d 100644
--- a/unix/xserver/hw/vnc/vncSelection.c
+++ b/unix/xserver/hw/vnc/vncSelection.c
@@ -105,7 +105,7 @@
LOG_ERROR("Could not set PRIMARY selection");
}
- vncOwnSelection(xaCLIPBOARD);
+ rc = vncOwnSelection(xaCLIPBOARD);
if (rc != Success)
LOG_ERROR("Could not set CLIPBOARD selection");
}
diff --git a/unix/xserver/hw/vnc/xvnc.c b/unix/xserver/hw/vnc/xvnc.c
index 79b0e3d..98c4a15 100644
--- a/unix/xserver/hw/vnc/xvnc.c
+++ b/unix/xserver/hw/vnc/xvnc.c
@@ -766,10 +766,13 @@
curpmap = (ColormapPtr) LookupIDByType(pmap->pScreen->defColormap,
RT_COLORMAP);
#else
- dixLookupResourceByType((void * *) &curpmap, pmap->pScreen->defColormap,
- RT_COLORMAP, serverClient, DixUnknownAccess);
+ int rc = dixLookupResourceByType((void * *) &curpmap, pmap->pScreen->defColormap,
+ RT_COLORMAP, serverClient, DixUnknownAccess);
+ if (rc != Success)
+ ErrorF("Failed to uninstall color map\n");
+ else
#endif
- (*pmap->pScreen->InstallColormap)(curpmap);
+ (*pmap->pScreen->InstallColormap)(curpmap);
}
}
}
diff --git a/vncviewer/DesktopWindow.cxx b/vncviewer/DesktopWindow.cxx
index 2890989..150c39b 100644
--- a/vncviewer/DesktopWindow.cxx
+++ b/vncviewer/DesktopWindow.cxx
@@ -103,12 +103,12 @@
int geom_x = 0, geom_y = 0;
if (strcmp(geometry, "") != 0) {
int matched;
- matched = sscanf(geometry.getValueStr(), "+%d+%d", &geom_x, &geom_y);
+ matched = sscanf((const char*)geometry, "+%d+%d", &geom_x, &geom_y);
if (matched == 2) {
force_position(1);
} else {
int geom_w, geom_h;
- matched = sscanf(geometry.getValueStr(), "%dx%d+%d+%d", &geom_w, &geom_h, &geom_x, &geom_y);
+ matched = sscanf((const char*)geometry, "%dx%d+%d+%d", &geom_w, &geom_h, &geom_x, &geom_y);
switch (matched) {
case 4:
force_position(1);
diff --git a/vncviewer/OptionsDialog.cxx b/vncviewer/OptionsDialog.cxx
index b018c95..62b5d9c 100644
--- a/vncviewer/OptionsDialog.cxx
+++ b/vncviewer/OptionsDialog.cxx
@@ -282,7 +282,7 @@
/* Screen */
int width, height;
- if (sscanf(desktopSize.getValueStr(), "%dx%d", &width, &height) != 2) {
+ if (sscanf((const char*)desktopSize, "%dx%d", &width, &height) != 2) {
desktopSizeCheckbox->value(false);
desktopWidthInput->value("1024");
desktopHeightInput->value("768");
diff --git a/vncviewer/PlatformPixelBuffer.cxx b/vncviewer/PlatformPixelBuffer.cxx
index e6a054a..1e9803e 100644
--- a/vncviewer/PlatformPixelBuffer.cxx
+++ b/vncviewer/PlatformPixelBuffer.cxx
@@ -58,6 +58,9 @@
data = (rdr::U8*)xim->data;
stride = xim->bytes_per_line / (getPF().bpp/8);
+
+ // On X11, the Pixmap backing this Surface is uninitialized.
+ clear(0, 0, 0);
#else
FullFramePixelBuffer::data = (rdr::U8*)Surface::data;
stride = width;
@@ -101,6 +104,9 @@
mutex.unlock();
#if !defined(WIN32) && !defined(__APPLE__)
+ if (r.width() == 0 || r.height() == 0)
+ return r;
+
GC gc;
gc = XCreateGC(fl_display, pixmap, 0, NULL);
diff --git a/vncviewer/ServerDialog.cxx b/vncviewer/ServerDialog.cxx
index de67f87..fec1789 100644
--- a/vncviewer/ServerDialog.cxx
+++ b/vncviewer/ServerDialog.cxx
@@ -150,7 +150,7 @@
return;
}
- const char* filename = strdup(file_chooser->value());
+ const char* filename = file_chooser->value();
try {
dialog->serverName->value(loadViewerParameters(filename));
@@ -165,8 +165,8 @@
void ServerDialog::handleSaveAs(Fl_Widget *widget, void *data)
{
ServerDialog *dialog = (ServerDialog*)data;
- const char* servername = strdup(dialog->serverName->value());
- char* filename;
+ const char* servername = dialog->serverName->value();
+ const char* filename;
Fl_File_Chooser* file_chooser = new Fl_File_Chooser("", _("TigerVNC configuration (*.tigervnc)"),
2, _("Save the TigerVNC configuration to file"));
@@ -187,7 +187,7 @@
return;
}
- filename = strdup(file_chooser->value());
+ filename = file_chooser->value();
FILE* f = fopen(filename, "r");
if (f) {
@@ -235,7 +235,7 @@
void ServerDialog::handleConnect(Fl_Widget *widget, void *data)
{
ServerDialog *dialog = (ServerDialog*)data;
- const char* servername = strdup(dialog->serverName->value());
+ const char* servername = dialog->serverName->value();
dialog->hide();
diff --git a/vncviewer/Viewport.cxx b/vncviewer/Viewport.cxx
index ec78314..425cb9f 100644
--- a/vncviewer/Viewport.cxx
+++ b/vncviewer/Viewport.cxx
@@ -936,6 +936,13 @@
keyCode = ((msg->lParam >> 16) & 0xff);
+ // Windows' touch keyboard doesn't set a scan code for the Alt
+ // portion of the AltGr sequence, so we need to help it out
+ if (!isExtended && (keyCode == 0x00) && (vKey == VK_MENU)) {
+ isExtended = true;
+ keyCode = 0x38;
+ }
+
// Windows doesn't have a proper AltGr, but handles it using fake
// Ctrl+Alt. However the remote end might not be Windows, so we need
// to merge those in to a single AltGr event. We detect this case
@@ -1040,6 +1047,12 @@
keyCode = ((msg->lParam >> 16) & 0xff);
+ // Touch keyboard AltGr (see above)
+ if (!isExtended && (keyCode == 0x00) && (vKey == VK_MENU)) {
+ isExtended = true;
+ keyCode = 0x38;
+ }
+
// We can't get a release in the middle of an AltGr sequence, so
// abort that detection
if (self->altGrArmed) {
diff --git a/vncviewer/gettext.h b/vncviewer/gettext.h
index ac4d7d5..768a699 100644
--- a/vncviewer/gettext.h
+++ b/vncviewer/gettext.h
@@ -1,24 +1,26 @@
/* Convenience header for conditional use of GNU <libintl.h>.
- Copyright (C) 1995-1998, 2000-2002, 2004-2006, 2009-2011 Free Software Foundation, Inc.
+ Copyright (C) 1995-1998, 2000-2002, 2004-2006, 2009-2018 Free Software
+ Foundation, Inc.
- This program is free software: you can redistribute it and/or modify
+ This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, see <https://www.gnu.org/licenses/>. */
#ifndef _LIBGETTEXT_H
#define _LIBGETTEXT_H 1
-/* NLS can be disabled through the configure --disable-nls option. */
-#if ENABLE_NLS
+/* NLS can be disabled through the configure --disable-nls option
+ or through "#define ENABLE NLS 0" before including this file. */
+#if defined ENABLE_NLS && ENABLE_NLS
/* Get declarations of GNU message catalog functions. */
# include <libintl.h>
@@ -182,8 +184,9 @@
#include <string.h>
-#if (((__GNUC__ >= 3 || __GNUG__ >= 2) && !defined __STRICT_ANSI__) \
- /* || __STDC_VERSION__ >= 199901L */ )
+#if (((__GNUC__ >= 3 || __GNUG__ >= 2) && !defined __STRICT_ANSI__ && !defined __cplusplus) \
+ /* || __STDC_VERSION__ == 199901L
+ || (__STDC_VERSION__ >= 201112L && !defined __STDC_NO_VLA__) */ )
# define _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS 1
#else
# define _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS 0
@@ -224,15 +227,17 @@
if (msg_ctxt_id != NULL)
#endif
{
+ int found_translation;
memcpy (msg_ctxt_id, msgctxt, msgctxt_len - 1);
msg_ctxt_id[msgctxt_len - 1] = '\004';
memcpy (msg_ctxt_id + msgctxt_len, msgid, msgid_len);
translation = dcgettext (domain, msg_ctxt_id, category);
+ found_translation = (translation != msg_ctxt_id);
#if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
if (msg_ctxt_id != buf)
free (msg_ctxt_id);
#endif
- if (translation != msg_ctxt_id)
+ if (found_translation)
return translation;
}
return msgid;
@@ -270,15 +275,17 @@
if (msg_ctxt_id != NULL)
#endif
{
+ int found_translation;
memcpy (msg_ctxt_id, msgctxt, msgctxt_len - 1);
msg_ctxt_id[msgctxt_len - 1] = '\004';
memcpy (msg_ctxt_id + msgctxt_len, msgid, msgid_len);
translation = dcngettext (domain, msg_ctxt_id, msgid_plural, n, category);
+ found_translation = !(translation == msg_ctxt_id || translation == msgid_plural);
#if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
if (msg_ctxt_id != buf)
free (msg_ctxt_id);
#endif
- if (!(translation == msg_ctxt_id || translation == msgid_plural))
+ if (found_translation)
return translation;
}
return (n == 1 ? msgid : msgid_plural);
diff --git a/vncviewer/parameters.cxx b/vncviewer/parameters.cxx
index 51cce3d..8427818 100644
--- a/vncviewer/parameters.cxx
+++ b/vncviewer/parameters.cxx
@@ -325,9 +325,10 @@
static bool getKeyString(const char* _name, char* dest, size_t destSize, HKEY* hKey) {
- DWORD buffersize = 256;
- WCHAR value[destSize];
+ const DWORD buffersize = 256;
wchar_t name[buffersize];
+ WCHAR* value;
+ DWORD valuesize;
unsigned size = fl_utf8towc(_name, strlen(_name)+1, name, buffersize);
if (size >= buffersize) {
@@ -335,8 +336,11 @@
return false;
}
- LONG res = RegQueryValueExW(*hKey, name, 0, NULL, (LPBYTE)value, &buffersize);
+ value = new WCHAR[destSize];
+ valuesize = destSize;
+ LONG res = RegQueryValueExW(*hKey, name, 0, NULL, (LPBYTE)value, &valuesize);
if (res != ERROR_SUCCESS){
+ delete [] value;
if (res == ERROR_FILE_NOT_FOUND) {
// The value does not exist, defaults will be used.
} else {
@@ -346,18 +350,19 @@
return false;
}
- char utf8val[destSize];
- size = fl_utf8fromwc(utf8val, sizeof(utf8val), value, wcslen(value)+1);
- if (size >= sizeof(utf8val)) {
+ char* utf8val = new char[destSize];
+ size = fl_utf8fromwc(utf8val, destSize, value, wcslen(value)+1);
+ delete [] value;
+ if (size >= destSize) {
+ delete [] utf8val;
vlog.error(_("The parameter %s was too large to read from the registry"), _name);
return false;
}
- const char *ret = utf8val;
- if(decodeValue(ret, dest, destSize))
- return true;
- else
- return false;
+ bool ret = decodeValue(utf8val, dest, destSize);
+ delete [] utf8val;
+
+ return ret;
}
@@ -499,6 +504,7 @@
}
snprintf(filepath, sizeof(filepath), "%sdefault.tigervnc", homeDir);
+ free(homeDir);
} else {
snprintf(filepath, sizeof(filepath), "%s", filename);
}
@@ -555,6 +561,7 @@
"can't obtain home directory path."));
snprintf(filepath, sizeof(filepath), "%sdefault.tigervnc", homeDir);
+ free(homeDir);
} else {
snprintf(filepath, sizeof(filepath), "%s", filename);
}
diff --git a/vncviewer/vncviewer.cxx b/vncviewer/vncviewer.cxx
index ac4afca..1c6f524 100644
--- a/vncviewer/vncviewer.cxx
+++ b/vncviewer/vncviewer.cxx
@@ -479,9 +479,9 @@
int localPort = findFreeTcpPort();
int remotePort;
- gatewayHost = strDup(via.getValueStr());
if (interpretViaParam(remoteHost, &remotePort, localPort) != 0)
return 1;
+ gatewayHost = (const char*)via;
createTunnel(gatewayHost, remoteHost, remotePort, localPort);
return 0;
diff --git a/win/rfb_win32/SDisplay.cxx b/win/rfb_win32/SDisplay.cxx
index 9b2cbb0..2cedc4a 100644
--- a/win/rfb_win32/SDisplay.cxx
+++ b/win/rfb_win32/SDisplay.cxx
@@ -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,9 +68,10 @@
: 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);
+ terminateEvent.h = CreateEvent(0, TRUE, FALSE, 0);
}
SDisplay::~SDisplay()
@@ -138,6 +141,25 @@
if (statusLocation) *statusLocation = false;
}
+void SDisplay::terminate()
+{
+ SetEvent(terminateEvent);
+}
+
+
+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() {
diff --git a/win/rfb_win32/SDisplay.h b/win/rfb_win32/SDisplay.h
index c1d5c1e..6dbfabb 100644
--- a/win/rfb_win32/SDisplay.h
+++ b/win/rfb_win32/SDisplay.h
@@ -52,6 +52,13 @@
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,9 @@
virtual void start(VNCServer* vs);
virtual void stop();
+ virtual void terminate();
+ 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);
@@ -80,12 +90,19 @@
// -=- EventHandler interface
HANDLE getUpdateEvent() {return updateEvent;}
+ HANDLE getTerminateEvent() {return terminateEvent;}
virtual void processEvent(HANDLE event);
// -=- Notification of whether or not SDisplay is started
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;
@@ -146,10 +163,15 @@
// -=- Event signalled to trigger an update to be flushed
Handle updateEvent;
+ // -=- Event signalled to terminate the server
+ Handle terminateEvent;
// -=- Where to write the active/inactive indicator to
bool* statusLocation;
+ // -=- Whom to query incoming connections
+ QueryConnectionHandler* queryConnectionHandler;
+
unsigned ledState;
};
diff --git a/win/rfb_win32/SocketManager.cxx b/win/rfb_win32/SocketManager.cxx
index 5b211a0..0092d94 100644
--- a/win/rfb_win32/SocketManager.cxx
+++ b/win/rfb_win32/SocketManager.cxx
@@ -21,6 +21,7 @@
#include <winsock2.h>
#include <list>
#include <rfb/LogWriter.h>
+#include <rfb/Timer.h>
#include <rfb_win32/SocketManager.h>
using namespace rfb;
@@ -78,6 +79,7 @@
li.sock = sock_;
li.server = srvr;
li.notifier = acn;
+ li.disable = false;
listeners[event] = li;
}
@@ -128,13 +130,39 @@
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();
std::map<HANDLE,ListenInfo>::iterator i;
for (i=listeners.begin(); i!=listeners.end(); i++)
- soonestTimeout(&timeout, i->second.server->checkTimeouts());
+ soonestTimeout(&timeout, Timer::checkTimeouts());
std::list<network::Socket*> shutdownSocks;
std::map<HANDLE,ConnInfo>::iterator j, j_next;
@@ -164,7 +192,7 @@
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;
}
diff --git a/win/rfb_win32/SocketManager.h b/win/rfb_win32/SocketManager.h
index c3c8faf..e5ca02e 100644
--- a/win/rfb_win32/SocketManager.h
+++ b/win/rfb_win32/SocketManager.h
@@ -65,6 +65,9 @@
// 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 @@
network::SocketListener* sock;
network::SocketServer* server;
AddressChangeNotifier* notifier;
+ bool disable;
};
std::map<HANDLE, ListenInfo> listeners;
std::map<HANDLE, ConnInfo> connections;
diff --git a/win/winvnc/ControlPanel.cxx b/win/winvnc/ControlPanel.cxx
index ba6cab2..72831e5 100644
--- a/win/winvnc/ControlPanel.cxx
+++ b/win/winvnc/ControlPanel.cxx
@@ -19,10 +19,9 @@
{
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 @@
}
-void ControlPanel::UpdateListView(rfb::ListConnInfo* LCInfo)
+void ControlPanel::UpdateListView(ListConnInfo* LCInfo)
{
getSelConnInfo();
DeleteAllLVItem(IDC_LIST_CONNECTIONS, handle);
@@ -85,12 +84,12 @@
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 @@
{
COPYDATASTRUCT copyData;
copyData.dwData = command;
+ copyData.cbData = 0;
+ copyData.lpData = 0;
getSelConnInfo();
if (data != -1) {
ListConnStatus.Copy(&ListSelConn);
@@ -149,8 +150,6 @@
} else {
ListConnStatus.Clear();
}
- copyData.cbData = 0;
- copyData.lpData = &ListConnStatus;
SendMessage(m_hSTIcon, WM_COPYDATA, 0, (LPARAM)©Data);
}
diff --git a/win/winvnc/ControlPanel.h b/win/winvnc/ControlPanel.h
index 73b859f..f64a608 100644
--- a/win/winvnc/ControlPanel.h
+++ b/win/winvnc/ControlPanel.h
@@ -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 @@
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
\ No newline at end of file
+#endif
diff --git a/common/rfb/ListConnInfo.h b/win/winvnc/ListConnInfo.h
similarity index 80%
rename from common/rfb/ListConnInfo.h
rename to win/winvnc/ListConnInfo.h
index c49947d..6ca5b7c 100644
--- a/common/rfb/ListConnInfo.h
+++ b/win/winvnc/ListConnInfo.h
@@ -24,7 +24,7 @@
#include <rfb/util.h>
-namespace rfb {
+namespace winvnc {
struct ListConnInfo {
ListConnInfo() : disableClients(false) {}
@@ -32,7 +32,6 @@
void Clear() {
conn.clear();
IP_address.clear();
- time_conn.clear();
status.clear();
}
@@ -41,7 +40,6 @@
void iBegin() {
ci = conn.begin();
Ii = IP_address.begin();
- ti = time_conn.begin();
si = status.begin();
}
@@ -50,32 +48,29 @@
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 @@
}
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 @@
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;
};
diff --git a/win/winvnc/STrayIcon.cxx b/win/winvnc/STrayIcon.cxx
index 05a38d6..a90819d 100644
--- a/win/winvnc/STrayIcon.cxx
+++ b/win/winvnc/STrayIcon.cxx
@@ -184,7 +184,7 @@
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 @@
LaunchProcess vncConnect;
STrayIconThread& thread;
ControlPanel * CPanel;
- rfb::ListConnInfo LCInfo;
+ ListConnInfo LCInfo;
};
diff --git a/win/winvnc/VNCServerService.cxx b/win/winvnc/VNCServerService.cxx
index 5656de0..f5a4dba 100644
--- a/win/winvnc/VNCServerService.cxx
+++ b/win/winvnc/VNCServerService.cxx
@@ -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>
diff --git a/win/winvnc/VNCServerWin32.cxx b/win/winvnc/VNCServerWin32.cxx
index 9f6a954..e001449 100644
--- a/win/winvnc/VNCServerWin32.cxx
+++ b/win/winvnc/VNCServerWin32.cxx
@@ -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,12 +72,11 @@
// 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);
+ sockMgr.addEvent(desktop.getTerminateEvent(), this);
// Register the queued command event to be handled
sockMgr.addEvent(commandEvent, this);
@@ -241,27 +241,27 @@
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 +309,10 @@
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:
@@ -336,8 +336,88 @@
command = NoCommand;
commandSig->signal();
}
- } else if (event_ == sessionEvent.h) {
+ } else if ((event_ == sessionEvent.h) ||
+ (event_ == desktop.getTerminateEvent())) {
stop();
}
}
+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);
+ }
+ }
+}
diff --git a/win/winvnc/VNCServerWin32.h b/win/winvnc/VNCServerWin32.h
index 271cb76..1a73782 100644
--- a/win/winvnc/VNCServerWin32.h
+++ b/win/winvnc/VNCServerWin32.h
@@ -37,9 +37,10 @@
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 @@
// 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 @@
// 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;