Improved congestion control handling

Refine the previous method by interpolating the values we need.
This reduces the effect of the problem that we cannot send enough
ping packets.
diff --git a/common/rfb/VNCSConnectionST.cxx b/common/rfb/VNCSConnectionST.cxx
index 43eb825..b2ceb7d 100644
--- a/common/rfb/VNCSConnectionST.cxx
+++ b/common/rfb/VNCSConnectionST.cxx
@@ -43,7 +43,7 @@
   : sock(s), reverseConnection(reverse),
     queryConnectTimer(this), inProcessMessages(false),
     pendingSyncFence(false), syncFence(false), fenceFlags(0),
-    fenceDataLen(0), fenceData(NULL),
+    fenceDataLen(0), fenceData(NULL), congestionTimer(this),
     server(server_), updates(false),
     updateRenderedCursor(false), removeRenderedCursor(false),
     continuousUpdates(false), encodeManager(this), pointerEventTime(0),
@@ -726,6 +726,8 @@
     if (t == &queryConnectTimer) {
       if (state() == RFBSTATE_QUERYING)
         approveConnection(false, "The attempt to prompt the user to accept the connection failed");
+    } else if (t == &congestionTimer) {
+      writeFramebufferUpdate();
     }
   } catch (rdr::Exception& e) {
     close(e.str());
@@ -742,6 +744,8 @@
   if (!cp.supportsFence)
     return;
 
+  congestion.updatePosition(sock->outStream().length());
+
   // We need to make sure any old update are already processed by the
   // time we get the response back. This allows us to reliably throttle
   // back on client overload, as well as network overload.
@@ -749,11 +753,15 @@
   writer()->writeFence(fenceFlagRequest | fenceFlagBlockBefore,
                        sizeof(type), &type);
 
-  congestion.sentPing(sock->outStream().length());
+  congestion.sentPing();
 }
 
 bool VNCSConnectionST::isCongested()
 {
+  unsigned eta;
+
+  congestionTimer.stop();
+
   // Stuff still waiting in the send buffer?
   sock->outStream().flush();
   if (sock->outStream().bufferUsage() > 0)
@@ -762,13 +770,22 @@
   if (!cp.supportsFence)
     return false;
 
-  return congestion.isCongested(sock->outStream().length(),
-                                sock->outStream().getIdleTime());
+  congestion.updatePosition(sock->outStream().length());
+  if (!congestion.isCongested())
+    return false;
+
+  eta = congestion.getUncongestedETA();
+  if (eta >= 0)
+    congestionTimer.start(eta);
+
+  return true;
 }
 
 
 void VNCSConnectionST::writeFramebufferUpdate()
 {
+  congestion.updatePosition(sock->outStream().length());
+
   // We're in the middle of processing a command that's supposed to be
   // synchronised. Allowing an update to slip out right now might violate
   // that synchronisation.
@@ -805,6 +822,8 @@
   writeDataUpdate();
 
   network::TcpSocket::cork(sock->getFd(), false);
+
+  congestion.updatePosition(sock->outStream().length());
 }
 
 void VNCSConnectionST::writeNoDataUpdate()