Properly terminate server on timeouts

Do a proper cleanup when one of the termination timeouts trigger
rather than just exiting on the spot. This makes sure we don't leave
stray stuff around, e.g. unix socket files.
diff --git a/common/rfb/SDesktop.h b/common/rfb/SDesktop.h
index 6118246..0060aa2 100644
--- a/common/rfb/SDesktop.h
+++ b/common/rfb/SDesktop.h
@@ -75,6 +75,12 @@
     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/VNCServerST.cxx b/common/rfb/VNCServerST.cxx
index 352b80f..601e636 100644
--- a/common/rfb/VNCServerST.cxx
+++ b/common/rfb/VNCServerST.cxx
@@ -574,13 +574,13 @@
     return true;
   } else if (t == &idleTimer) {
     slog.info("MaxIdleTime reached, exiting");
-    exit(0);
+    desktop->terminate();
   } else if (t == &disconnectTimer) {
     slog.info("MaxDisconnectionTime reached, exiting");
-    exit(0);
+    desktop->terminate();
   } else if (t == &connectTimer) {
     slog.info("MaxConnectionTime reached, exiting");
-    exit(0);
+    desktop->terminate();
   }
 
   return false;