diff options
-rw-r--r-- | common/network/Socket.h | 7 | ||||
-rw-r--r-- | common/rfb/SDesktop.h | 6 | ||||
-rw-r--r-- | common/rfb/VNCSConnectionST.cxx | 61 | ||||
-rw-r--r-- | common/rfb/VNCSConnectionST.h | 8 | ||||
-rw-r--r-- | common/rfb/VNCServerST.cxx | 121 | ||||
-rw-r--r-- | common/rfb/VNCServerST.h | 12 | ||||
-rw-r--r-- | unix/x0vncserver/XDesktop.cxx | 6 | ||||
-rw-r--r-- | unix/x0vncserver/XDesktop.h | 1 | ||||
-rw-r--r-- | unix/x0vncserver/x0vncserver.cxx | 4 | ||||
-rw-r--r-- | unix/xserver/hw/vnc/XserverDesktop.cc | 8 | ||||
-rw-r--r-- | unix/xserver/hw/vnc/XserverDesktop.h | 1 | ||||
-rw-r--r-- | win/rfb_win32/SDisplay.cxx | 6 | ||||
-rw-r--r-- | win/rfb_win32/SDisplay.h | 4 | ||||
-rw-r--r-- | win/rfb_win32/SocketManager.cxx | 3 | ||||
-rw-r--r-- | win/winvnc/VNCServerWin32.cxx | 4 |
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(); } } |