aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--common/network/Socket.h7
-rw-r--r--common/rfb/SDesktop.h6
-rw-r--r--common/rfb/VNCSConnectionST.cxx61
-rw-r--r--common/rfb/VNCSConnectionST.h8
-rw-r--r--common/rfb/VNCServerST.cxx121
-rw-r--r--common/rfb/VNCServerST.h12
-rw-r--r--unix/x0vncserver/XDesktop.cxx6
-rw-r--r--unix/x0vncserver/XDesktop.h1
-rw-r--r--unix/x0vncserver/x0vncserver.cxx4
-rw-r--r--unix/xserver/hw/vnc/XserverDesktop.cc8
-rw-r--r--unix/xserver/hw/vnc/XserverDesktop.h1
-rw-r--r--win/rfb_win32/SDisplay.cxx6
-rw-r--r--win/rfb_win32/SDisplay.h4
-rw-r--r--win/rfb_win32/SocketManager.cxx3
-rw-r--r--win/winvnc/VNCServerWin32.cxx4
15 files changed, 95 insertions, 157 deletions
diff --git a/common/network/Socket.h b/common/network/Socket.h
index c7d06c3e..d38feba4 100644
--- a/common/network/Socket.h
+++ b/common/network/Socket.h
@@ -144,13 +144,6 @@ namespace network {
// 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;
};
}
diff --git a/common/rfb/SDesktop.h b/common/rfb/SDesktop.h
index 61182469..0060aa23 100644
--- a/common/rfb/SDesktop.h
+++ b/common/rfb/SDesktop.h
@@ -75,6 +75,12 @@ namespace rfb {
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.
virtual unsigned int setScreenLayout(int __unused_attr fb_width,
diff --git a/common/rfb/VNCSConnectionST.cxx b/common/rfb/VNCSConnectionST.cxx
index 7b261e74..8758362c 100644
--- a/common/rfb/VNCSConnectionST.cxx
+++ b/common/rfb/VNCSConnectionST.cxx
@@ -51,15 +51,23 @@ VNCSConnectionST::VNCSConnectionST(VNCServerST* server_, network::Socket *s,
fenceDataLen(0), fenceData(NULL), congestionTimer(this),
losslessTimer(this), server(server_), updates(false),
updateRenderedCursor(false), removeRenderedCursor(false),
- continuousUpdates(false), encodeManager(this), pointerEventTime(0),
- clientHasCursor(false)
+ continuousUpdates(false), encodeManager(this), idleTimer(this),
+ pointerEventTime(0), clientHasCursor(false)
{
setStreams(&sock->inStream(), &sock->outStream());
peerEndpoint.buf = sock->getPeerEndpoint();
// Configure the socket
setSocketTimeouts();
- lastEventTime = time(0);
+
+ // 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));
+ }
}
@@ -312,36 +320,6 @@ void VNCSConnectionST::setLEDStateOrClose(unsigned int state)
}
-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
@@ -412,7 +390,8 @@ void VNCSConnectionST::approveConnectionOrClose(bool accept,
void VNCSConnectionST::authSuccess()
{
- lastEventTime = time(0);
+ if (rfb::Server::idleTimeout)
+ idleTimer.start(secsToMillis(rfb::Server::idleTimeout));
// - Set the connection parameters appropriately
cp.width = server->getPixelBuffer()->width();
@@ -438,7 +417,8 @@ void VNCSConnectionST::queryConnection(const char* 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 (!accessCheck(AccessNonShared)) shared = true;
if (rfb::Server::neverShared) shared = false;
@@ -457,7 +437,9 @@ void VNCSConnectionST::setPixelFormat(const PixelFormat& pf)
void VNCSConnectionST::pointerEvent(const Point& pos, int buttonMask)
{
- pointerEventTime = lastEventTime = time(0);
+ if (rfb::Server::idleTimeout)
+ idleTimer.start(secsToMillis(rfb::Server::idleTimeout));
+ pointerEventTime = time(0);
if (!accessCheck(AccessPtrEvents)) return;
if (!rfb::Server::acceptPointerEvents) return;
pointerEventPos = pos;
@@ -489,7 +471,8 @@ public:
void VNCSConnectionST::keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down) {
rdr::U32 lookup;
- lastEventTime = time(0);
+ if (rfb::Server::idleTimeout)
+ idleTimer.start(secsToMillis(rfb::Server::idleTimeout));
if (!accessCheck(AccessKeyEvents)) return;
if (!rfb::Server::acceptKeyEvents) return;
@@ -765,6 +748,9 @@ bool VNCSConnectionST::handleTimeout(Timer* t)
close(e.str());
}
+ if (t == &idleTimer)
+ close("Idle timeout");
+
return false;
}
@@ -1106,7 +1092,6 @@ void VNCSConnectionST::setLEDState(unsigned int ledstate)
void VNCSConnectionST::setSocketTimeouts()
{
int timeoutms = rfb::Server::clientWaitTimeMillis;
- soonestTimeout(&timeoutms, secsToMillis(rfb::Server::idleTimeout));
if (timeoutms == 0)
timeoutms = -1;
sock->inStream().setTimeout(timeoutms);
diff --git a/common/rfb/VNCSConnectionST.h b/common/rfb/VNCSConnectionST.h
index 1b7d59ac..c992d145 100644
--- a/common/rfb/VNCSConnectionST.h
+++ b/common/rfb/VNCSConnectionST.h
@@ -77,11 +77,6 @@ namespace rfb {
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
// getComparerState() returns if this client would like the framebuffer
@@ -182,7 +177,8 @@ namespace rfb {
std::map<rdr::U32, rdr::U32> pressedKeys;
- time_t lastEventTime;
+ Timer idleTimer;
+
time_t pointerEventTime;
Point pointerEventPos;
bool clientHasCursor;
diff --git a/common/rfb/VNCServerST.cxx b/common/rfb/VNCServerST.cxx
index 038da3dc..40580b16 100644
--- a/common/rfb/VNCServerST.cxx
+++ b/common/rfb/VNCServerST.cxx
@@ -81,10 +81,16 @@ VNCServerST::VNCServerST(const char* name_, SDesktop* desktop_)
cursor(new Cursor(0, 0, Point(), NULL)),
renderedCursorInvalid(false),
keyRemapper(&KeyRemapper::defInstance),
- lastConnectionTime(0), frameTimer(this)
+ 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()
@@ -144,9 +150,10 @@ void VNCServerST::addSocket(network::Socket* sock, bool outgoing)
name.buf = sock->getPeerEndpoint();
connectionsLog.status("accepted: %s", name.buf);
- if (clients.empty()) {
- lastConnectionTime = time(0);
- }
+ // 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);
@@ -164,8 +171,10 @@ void VNCServerST::removeSocket(network::Socket* sock) {
if (pointerClient == *ci)
pointerClient = NULL;
- if ((*ci)->authenticated())
- lastDisconnectTime = time(0);
+ // 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;
@@ -215,89 +224,6 @@ void VNCServerST::processSocketWriteEvent(network::Socket* sock)
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()
@@ -495,7 +421,8 @@ void VNCServerST::setLEDState(unsigned int state)
void VNCServerST::keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down)
{
- lastUserInputTime = time(0);
+ if (rfb::Server::maxIdleTime)
+ idleTimer.start(secsToMillis(rfb::Server::maxIdleTime));
// Remap the key if required
if (keyRemapper) {
@@ -513,7 +440,8 @@ void VNCServerST::keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down)
void VNCServerST::pointerEvent(VNCSConnectionST* client,
const Point& pos, int buttonMask)
{
- lastUserInputTime = time(0);
+ 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
@@ -628,6 +556,15 @@ bool VNCServerST::handleTimeout(Timer* t)
}
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;
diff --git a/common/rfb/VNCServerST.h b/common/rfb/VNCServerST.h
index 545b9a49..43a3bb95 100644
--- a/common/rfb/VNCServerST.h
+++ b/common/rfb/VNCServerST.h
@@ -76,12 +76,6 @@ namespace rfb {
// 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
@@ -198,9 +192,9 @@ namespace rfb {
KeyRemapper* keyRemapper;
- time_t lastUserInputTime;
- time_t lastDisconnectTime;
- time_t lastConnectionTime;
+ Timer idleTimer;
+ Timer disconnectTimer;
+ Timer connectTimer;
Timer frameTimer;
};
diff --git a/unix/x0vncserver/XDesktop.cxx b/unix/x0vncserver/XDesktop.cxx
index 5f71ccb2..1fdc9e2c 100644
--- a/unix/x0vncserver/XDesktop.cxx
+++ b/unix/x0vncserver/XDesktop.cxx
@@ -19,6 +19,8 @@
*/
#include <assert.h>
+#include <signal.h>
+#include <unistd.h>
#include <rfb/LogWriter.h>
@@ -273,6 +275,10 @@ void XDesktop::stop() {
pb = 0;
}
+void XDesktop::terminate() {
+ kill(getpid(), SIGTERM);
+}
+
bool XDesktop::isRunning() {
return running;
}
diff --git a/unix/x0vncserver/XDesktop.h b/unix/x0vncserver/XDesktop.h
index 7d060613..3e85aac3 100644
--- a/unix/x0vncserver/XDesktop.h
+++ b/unix/x0vncserver/XDesktop.h
@@ -49,6 +49,7 @@ public:
// -=- 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);
diff --git a/unix/x0vncserver/x0vncserver.cxx b/unix/x0vncserver/x0vncserver.cxx
index c77870de..cf2c35a2 100644
--- a/unix/x0vncserver/x0vncserver.cxx
+++ b/unix/x0vncserver/x0vncserver.cxx
@@ -322,7 +322,7 @@ int main(int argc, char** argv)
}
}
- soonestTimeout(&wait_ms, server.checkTimeouts());
+ soonestTimeout(&wait_ms, Timer::checkTimeouts());
tv.tv_sec = wait_ms / 1000;
tv.tv_usec = (wait_ms % 1000) * 1000;
@@ -357,7 +357,7 @@ int main(int argc, char** argv)
}
}
- server.checkTimeouts();
+ Timer::checkTimeouts();
// Client list could have been changed.
server.getSockets(&sockets);
diff --git a/unix/xserver/hw/vnc/XserverDesktop.cc b/unix/xserver/hw/vnc/XserverDesktop.cc
index e61472b3..d8b3a4d4 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>
@@ -367,7 +368,7 @@ void XserverDesktop::blockHandler(int* timeout)
}
// 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) {
@@ -423,6 +424,11 @@ void XserverDesktop::approveConnection(uint32_t opaqueId, bool accept,
// 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 ff36b3b5..1253935f 100644
--- a/unix/xserver/hw/vnc/XserverDesktop.h
+++ b/unix/xserver/hw/vnc/XserverDesktop.h
@@ -87,6 +87,7 @@ public:
// 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);
diff --git a/win/rfb_win32/SDisplay.cxx b/win/rfb_win32/SDisplay.cxx
index afb72ad7..2cedc4a8 100644
--- a/win/rfb_win32/SDisplay.cxx
+++ b/win/rfb_win32/SDisplay.cxx
@@ -71,6 +71,7 @@ SDisplay::SDisplay()
statusLocation(0), queryConnectionHandler(0), ledState(0)
{
updateEvent.h = CreateEvent(0, TRUE, FALSE, 0);
+ terminateEvent.h = CreateEvent(0, TRUE, FALSE, 0);
}
SDisplay::~SDisplay()
@@ -140,6 +141,11 @@ void SDisplay::stop()
if (statusLocation) *statusLocation = false;
}
+void SDisplay::terminate()
+{
+ SetEvent(terminateEvent);
+}
+
void SDisplay::queryConnection(network::Socket* sock,
const char* userName)
diff --git a/win/rfb_win32/SDisplay.h b/win/rfb_win32/SDisplay.h
index 76ddf50b..6dbfabbc 100644
--- a/win/rfb_win32/SDisplay.h
+++ b/win/rfb_win32/SDisplay.h
@@ -72,6 +72,7 @@ namespace rfb {
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);
@@ -89,6 +90,7 @@ namespace rfb {
// -=- EventHandler interface
HANDLE getUpdateEvent() {return updateEvent;}
+ HANDLE getTerminateEvent() {return terminateEvent;}
virtual void processEvent(HANDLE event);
// -=- Notification of whether or not SDisplay is started
@@ -161,6 +163,8 @@ namespace rfb {
// -=- 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;
diff --git a/win/rfb_win32/SocketManager.cxx b/win/rfb_win32/SocketManager.cxx
index aa469e53..0092d94d 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;
@@ -161,7 +162,7 @@ int SocketManager::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;
diff --git a/win/winvnc/VNCServerWin32.cxx b/win/winvnc/VNCServerWin32.cxx
index 03b1bca7..e0014495 100644
--- a/win/winvnc/VNCServerWin32.cxx
+++ b/win/winvnc/VNCServerWin32.cxx
@@ -76,6 +76,7 @@ VNCServerWin32::VNCServerWin32()
// 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);
@@ -335,7 +336,8 @@ void VNCServerWin32::processEvent(HANDLE event_) {
command = NoCommand;
commandSig->signal();
}
- } else if (event_ == sessionEvent.h) {
+ } else if ((event_ == sessionEvent.h) ||
+ (event_ == desktop.getTerminateEvent())) {
stop();
}
}