IE, Chrome, Firefox plugins: gracefully disconnect when server connection drops.

1) Plugins fails gracefully in the face of a disconnect, returning undefined instead of making lots of noise.

2) Plugins invokes hosted.html's __gwt_disconnected() method the first time the session is detected as dropped.  This glasspanels the app.

Review by: jat

git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@7129 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/plugins/common/HostChannel.cpp b/plugins/common/HostChannel.cpp
index 90552a4..bff1b21 100644
--- a/plugins/common/HostChannel.cpp
+++ b/plugins/common/HostChannel.cpp
@@ -68,6 +68,7 @@
 
 bool HostChannel::init(SessionHandler* handler, int minProtoVers,
     int maxProtoVers, const std::string& hostedHtmlVers) {
+  this->handler = handler;
   Debug::log(Debug::Debugging)
       << "  negotiating versions - we support protocol " << minProtoVers
       << " through " << maxProtoVers << ", hostedHtmlVersion=" << hostedHtmlVers
diff --git a/plugins/common/HostChannel.h b/plugins/common/HostChannel.h
index f104d63..3c5c5e3 100644
--- a/plugins/common/HostChannel.h
+++ b/plugins/common/HostChannel.h
@@ -33,6 +33,7 @@
 class HostChannel {
   Socket sock;
   static ByteOrder byteOrder;
+  SessionHandler* handler;
 
 public:
   ~HostChannel() {
@@ -95,10 +96,12 @@
 
   bool readByte(char& data) {
     if (!isConnected()) {
+      handler->disconnectDetected();
       return false;
     }
     int c = sock.readByte();
     if (c < 0) {
+      handler->disconnectDetected();
       return false;
     }
     data = static_cast<char>(c);
@@ -107,9 +110,14 @@
 
   bool sendByte(const char data) {
     if (!isConnected()) {
+      handler->disconnectDetected();
       return false;
     }
-    return sock.writeByte(data);
+    if (!sock.writeByte(data)) {
+      handler->disconnectDetected();
+      return false;
+    }
+    return true;
   }
 
   bool readStringLength(uint32_t& data);
@@ -133,7 +141,15 @@
   }
 
   bool flush() {
-    return sock.flush();
+    if (!sock.isConnected()) {
+      handler->disconnectDetected();
+      return false;
+    }
+    if (!sock.flush()) {
+      handler->disconnectDetected();
+      return false;
+    }
+    return true;
   }
 
   ReturnMessage* reactToMessagesWhileWaitingForReturn(SessionHandler* handler) {
diff --git a/plugins/common/SessionHandler.h b/plugins/common/SessionHandler.h
index 2cb011f..aebd00d 100644
--- a/plugins/common/SessionHandler.h
+++ b/plugins/common/SessionHandler.h
@@ -49,6 +49,24 @@
     SetProperty = SPECIAL_SET_PROPERTY
   };
 protected:
+  SessionHandler(): alreadyDisconnected(false) {
+  }
+
+  /**
+   * Called by the server socket when it cannot read, write, or flush.
+   */
+  void disconnectDetected() {
+    if (!alreadyDisconnected) {
+      alreadyDisconnected = true;
+      disconnectDetectedImpl();
+    }
+  }
+
+  /**
+   * Implementors should invoke __gwt_disconnected() in the hosted.html window
+   * to "glass" the screen with a disconnect message.
+   */
+  virtual void disconnectDetectedImpl() = 0;
 
   /**
    * Report a fatal error -- the channel will be closed after this method
@@ -84,6 +102,9 @@
   virtual void sendFreeValues(HostChannel& channel) = 0;
 
   virtual ~SessionHandler() {}
+
+private:
+  bool alreadyDisconnected;
 };
 
 #endif