Encapsulate client handling in VNCServerST

Removed the last parts of VNCSConnectionST's back door in to
VNCServerST and let the parent class fully handle coordination of
clients, and access to the desktop.
diff --git a/common/rfb/VNCSConnectionST.cxx b/common/rfb/VNCSConnectionST.cxx
index d9e276a..50e6d88 100644
--- a/common/rfb/VNCSConnectionST.cxx
+++ b/common/rfb/VNCSConnectionST.cxx
@@ -56,22 +56,18 @@
 {
   setStreams(&sock->inStream(), &sock->outStream());
   peerEndpoint.buf = sock->getPeerEndpoint();
-  VNCServerST::connectionsLog.write(1,"accepted: %s", peerEndpoint.buf);
 
   // Configure the socket
   setSocketTimeouts();
   lastEventTime = time(0);
-
-  server->clients.push_front(this);
 }
 
 
 VNCSConnectionST::~VNCSConnectionST()
 {
   // If we reach here then VNCServerST is deleting us!
-  VNCServerST::connectionsLog.write(1,"closed: %s (%s)",
-                                    peerEndpoint.buf,
-                                    (closeReason.buf) ? closeReason.buf : "");
+  if (closeReason.buf)
+    vlog.info("closing %s: %s", peerEndpoint.buf, closeReason.buf);
 
   // Release any keys the client still had pressed
   while (!pressedKeys.empty()) {
@@ -86,9 +82,6 @@
     server->keyEvent(keysym, keycode, false);
   }
 
-  // Remove this client from the server
-  server->clients.remove(this);
-
   delete [] fenceData;
 }
 
@@ -113,10 +106,6 @@
   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.
@@ -445,30 +434,7 @@
 
 void VNCSConnectionST::queryConnection(const char* userName)
 {
-  // - Authentication succeeded - clear from blacklist
-  CharArray name; name.buf = sock->getPeerAddress();
-  server->blHosts->clearBlackmark(name.buf);
-
-  // - Prepare the desktop that we might be making calls
-  server->startDesktop();
-
-  // - 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 (!(rfb::Server::queryConnect || sock->requiresQuery()) ||
-      accessCheck(AccessNoQuery))
-  {
-    approveConnection(true);
-    return;
-  }
-
-  // - Get the server to display an Accept/Reject dialog, if required
-  server->queryConnection(sock, userName);
+  server->queryConnection(this, userName);
 }
 
 void VNCSConnectionST::clientInit(bool shared)
@@ -477,21 +443,8 @@
   if (rfb::Server::alwaysShared || reverseConnection) shared = true;
   if (!accessCheck(AccessNonShared)) shared = true;
   if (rfb::Server::neverShared) shared = false;
-  if (!shared) {
-    if (rfb::Server::disconnectClients && accessCheck(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)
diff --git a/common/rfb/VNCServerST.cxx b/common/rfb/VNCServerST.cxx
index 5e16611..e09e085 100644
--- a/common/rfb/VNCServerST.cxx
+++ b/common/rfb/VNCServerST.cxx
@@ -54,6 +54,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 +67,7 @@
 using namespace rfb;
 
 static LogWriter slog("VNCServerST");
-LogWriter VNCServerST::connectionsLog("Connections");
+static LogWriter connectionsLog("Connections");
 
 //
 // -=- VNCServerST Implementation
@@ -99,9 +100,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!
@@ -134,11 +137,16 @@
     return;
   }
 
+  CharArray name;
+  name.buf = sock->getPeerEndpoint();
+  connectionsLog.status("accepted: %s", name.buf);
+
   if (clients.empty()) {
     lastConnectionTime = time(0);
   }
 
   VNCSConnectionST* client = new VNCSConnectionST(this, sock, outgoing);
+  clients.push_front(client);
   client->init();
 }
 
@@ -147,13 +155,22 @@
   std::list<VNCSConnectionST*>::iterator ci;
   for (ci = clients.begin(); ci != clients.end(); ci++) {
     if ((*ci)->getSock() == sock) {
+      clients.remove(*ci);
+
       // - Release the cursor if this client owns it
       if (pointerClient == *ci)
         pointerClient = NULL;
 
+      if ((*ci)->authenticated())
+        lastDisconnectTime = time(0);
+
       // - Delete the per-Socket resources
       delete *ci;
 
+      CharArray name;
+      name.buf = sock->getPeerEndpoint();
+      connectionsLog.status("closed: %s", name.buf);
+
       // - Check that the desktop object is still required
       if (authClientCount() == 0)
         stopDesktop();
@@ -613,10 +630,61 @@
   return false;
 }
 
-void VNCServerST::queryConnection(network::Socket* sock,
+void VNCServerST::queryConnection(VNCSConnectionST* client,
                                   const char* userName)
 {
-  desktop->queryConnection(sock, 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
diff --git a/common/rfb/VNCServerST.h b/common/rfb/VNCServerST.h
index 0fa2c87..52b2289 100644
--- a/common/rfb/VNCServerST.h
+++ b/common/rfb/VNCServerST.h
@@ -28,7 +28,6 @@
 
 #include <rfb/SDesktop.h>
 #include <rfb/VNCServer.h>
-#include <rfb/LogWriter.h>
 #include <rfb/Blacklist.h>
 #include <rfb/Cursor.h>
 #include <rfb/Timer.h>
@@ -134,13 +133,9 @@
     // any), and logs the specified reason for closure.
     void closeClients(const char* reason, network::Socket* sock);
 
-    // 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.
-    // approveConnection() must be called some time later to accept or reject
-    // the connection.
-    virtual void queryConnection(network::Socket* sock,
-                                 const char* userName);
+    // queryConnection() does some basic checks and then passes on the
+    // request to the desktop.
+    void queryConnection(VNCSConnectionST* client, const char* userName);
 
     // setBlacklist() is called to replace the VNCServerST's internal
     // Blacklist instance with another instance.  This allows a single
@@ -157,9 +152,22 @@
     bool getDisable() { return disableclients;};
     void setDisable(bool disable) { disableclients = disable;};
 
-  protected:
+    // 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);
 
-    friend class VNCSConnectionST;
+    // Estimated time until the next time new updates will be pushed
+    // to clients
+    int msToNextUpdate();
+
+    // Part of the framebuffer that has been modified but is not yet
+    // ready to be sent to clients
+    Region getPendingRegion();
+
+    const RenderedCursor* getRenderedCursor();
+
+  protected:
 
     // Timer callbacks
     virtual bool handleTimeout(Timer* t);
@@ -169,7 +177,6 @@
     void startDesktop();
     void stopDesktop();
 
-    static LogWriter connectionsLog;
     Blacklist blacklist;
     Blacklist* blHosts;
 
@@ -199,10 +206,7 @@
     bool needRenderedCursor();
     void startFrameClock();
     void stopFrameClock();
-    int msToNextUpdate();
     void writeUpdate();
-    Region getPendingRegion();
-    const RenderedCursor* getRenderedCursor();
 
     bool getComparerState();
 
diff --git a/unix/x0vncserver/XDesktop.cxx b/unix/x0vncserver/XDesktop.cxx
index c7f8ef8..62a18a0 100644
--- a/unix/x0vncserver/XDesktop.cxx
+++ b/unix/x0vncserver/XDesktop.cxx
@@ -20,6 +20,8 @@
 
 #include <assert.h>
 
+#include <rfb/LogWriter.h>
+
 #include <x0vncserver/XDesktop.h>
 
 #include <X11/XKBlib.h>
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>