From 5ddb06e6b07880a34ca07cbb3c0b220c1b6b6bd1 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 28 Feb 2024 13:54:23 +0100 Subject: [PATCH] Maintain a constant VNCServer/SDesktop connection The desktop isn't completely paused just because there are no clients, so it might still need some support from the server object. This is primarily an issue for headless servers, where they need to continue emulating things even without clients. A scraping server can generally go completely passive if there are no clients. --- common/rfb/SDesktop.h | 17 ++++++++++------- common/rfb/VNCServerST.cxx | 4 +++- unix/x0vncserver/XDesktop.cxx | 10 ++++++---- unix/x0vncserver/XDesktop.h | 3 ++- unix/xserver/hw/vnc/XserverDesktop.cc | 7 +++++-- unix/xserver/hw/vnc/XserverDesktop.h | 3 ++- win/rfb_win32/SDisplay.cxx | 12 +++++++----- win/rfb_win32/SDisplay.h | 3 ++- 8 files changed, 37 insertions(+), 22 deletions(-) diff --git a/common/rfb/SDesktop.h b/common/rfb/SDesktop.h index 9db08116..e3871616 100644 --- a/common/rfb/SDesktop.h +++ b/common/rfb/SDesktop.h @@ -1,5 +1,5 @@ /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * Copyright 2009-2019 Pierre Ossman for Cendio AB + * Copyright 2009-2024 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 @@ -49,18 +49,21 @@ namespace rfb { class SDesktop : public InputHandler { public: + // init() is called immediately when the VNCServer gets a reference + // to the SDesktop, so that a reverse reference can be set up. + virtual void init(rfb::VNCServer* vs) = 0; + // start() is called by the server when the first client authenticates // successfully, and can be used to begin any expensive tasks which are not // needed when there are no clients. A valid PixelBuffer must have been // set via the VNCServer's setPixelBuffer() method by the time this call // returns. - virtual void start(VNCServer* vs) = 0; + virtual void start() = 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. + // expensive tasks. virtual void stop() = 0; @@ -136,13 +139,13 @@ namespace rfb { if (buffer) delete buffer; } - virtual void start(VNCServer* vs) { + virtual void init(VNCServer* vs) { server = vs; server->setPixelBuffer(buffer); } + virtual void start() { + } virtual void stop() { - server->setPixelBuffer(0); - server = 0; } virtual void queryConnection(network::Socket* sock, const char* /*userName*/) { diff --git a/common/rfb/VNCServerST.cxx b/common/rfb/VNCServerST.cxx index 68379f24..8d8dbfd7 100644 --- a/common/rfb/VNCServerST.cxx +++ b/common/rfb/VNCServerST.cxx @@ -92,6 +92,8 @@ VNCServerST::VNCServerST(const char* name_, SDesktop* desktop_) { slog.debug("creating single-threaded server %s", name.c_str()); + desktop_->init(this); + // FIXME: Do we really want to kick off these right away? if (rfb::Server::maxIdleTime) idleTimer.start(secsToMillis(rfb::Server::maxIdleTime)); @@ -707,7 +709,7 @@ void VNCServerST::startDesktop() { if (!desktopStarted) { slog.debug("starting desktop"); - desktop->start(this); + desktop->start(); if (!pb) throw Exception("SDesktop::start() did not set a valid PixelBuffer"); desktopStarted = true; diff --git a/unix/x0vncserver/XDesktop.cxx b/unix/x0vncserver/XDesktop.cxx index b3d5e54c..1f1f7481 100644 --- a/unix/x0vncserver/XDesktop.cxx +++ b/unix/x0vncserver/XDesktop.cxx @@ -230,9 +230,13 @@ void XDesktop::poll() { } } +void XDesktop::init(VNCServer* vs) +{ + server = vs; +} -void XDesktop::start(VNCServer* vs) { - +void XDesktop::start() +{ // Determine actual number of buttons of the X pointer device. unsigned char btnMap[8]; int numButtons = XGetPointerMapping(dpy, btnMap, 8); @@ -247,7 +251,6 @@ void XDesktop::start(VNCServer* vs) { pb = new XPixelBuffer(dpy, factory, geometry->getRect()); vlog.info("Allocated %s", pb->getImage()->classDesc()); - server = vs; server->setPixelBuffer(pb, computeScreenLayout()); #ifdef HAVE_XDAMAGE @@ -290,7 +293,6 @@ void XDesktop::stop() { queryConnectDialog = 0; server->setPixelBuffer(0); - server = 0; delete pb; pb = 0; diff --git a/unix/x0vncserver/XDesktop.h b/unix/x0vncserver/XDesktop.h index 1cb73f43..fc230e5b 100644 --- a/unix/x0vncserver/XDesktop.h +++ b/unix/x0vncserver/XDesktop.h @@ -47,7 +47,8 @@ public: virtual ~XDesktop(); void poll(); // -=- SDesktop interface - virtual void start(rfb::VNCServer* vs); + virtual void init(rfb::VNCServer* vs); + virtual void start(); virtual void stop(); virtual void terminate(); bool isRunning(); diff --git a/unix/xserver/hw/vnc/XserverDesktop.cc b/unix/xserver/hw/vnc/XserverDesktop.cc index ab7f29d2..7de6143b 100644 --- a/unix/xserver/hw/vnc/XserverDesktop.cc +++ b/unix/xserver/hw/vnc/XserverDesktop.cc @@ -145,11 +145,14 @@ void XserverDesktop::refreshScreenLayout() server->setScreenLayout(::computeScreenLayout(&outputIdMap)); } -void XserverDesktop::start(rfb::VNCServer* vs) +void XserverDesktop::init(rfb::VNCServer* vs) { // We already own the server object, and we always keep it in a // ready state - assert(vs == server); +} + +void XserverDesktop::start() +{ } void XserverDesktop::stop() diff --git a/unix/xserver/hw/vnc/XserverDesktop.h b/unix/xserver/hw/vnc/XserverDesktop.h index 8aa97d97..6c4f0b68 100644 --- a/unix/xserver/hw/vnc/XserverDesktop.h +++ b/unix/xserver/hw/vnc/XserverDesktop.h @@ -88,7 +88,8 @@ public: const char* rejectMsg=0); // rfb::SDesktop callbacks - virtual void start(rfb::VNCServer* vs); + virtual void init(rfb::VNCServer* vs); + virtual void start(); virtual void stop(); virtual void terminate(); virtual void queryConnection(network::Socket* sock, diff --git a/win/rfb_win32/SDisplay.cxx b/win/rfb_win32/SDisplay.cxx index 612f883b..dd1ac7da 100644 --- a/win/rfb_win32/SDisplay.cxx +++ b/win/rfb_win32/SDisplay.cxx @@ -96,7 +96,12 @@ SDisplay::~SDisplay() // -=- SDesktop interface -void SDisplay::start(VNCServer* vs) +void SDisplay::init(VNCServer* vs) +{ + server = vs; +} + +void SDisplay::start() { vlog.debug("starting"); @@ -105,7 +110,6 @@ void SDisplay::start(VNCServer* vs) setConsoleSession(); // Start the SDisplay core - server = vs; startCore(); vlog.debug("started"); @@ -135,10 +139,8 @@ void SDisplay::stop() } // Stop the SDisplayCore - if (server) - server->setPixelBuffer(0); + server->setPixelBuffer(0); stopCore(); - server = 0; vlog.debug("stopped"); diff --git a/win/rfb_win32/SDisplay.h b/win/rfb_win32/SDisplay.h index febc720e..5b55cd66 100644 --- a/win/rfb_win32/SDisplay.h +++ b/win/rfb_win32/SDisplay.h @@ -71,7 +71,8 @@ namespace rfb { // -=- SDesktop interface - virtual void start(VNCServer* vs); + virtual void init(VNCServer* vs); + virtual void start(); virtual void stop(); virtual void terminate(); virtual void queryConnection(network::Socket* sock, -- 2.39.5