Update browser plugins to support v2 wire protocol, and checkin some prebuilt
libraries for them.  The XPI files are *not* checked in here until all
platforms are rebuilt with the changes -- otherwise, users would no longer
be able to use platforms that were left out.  Log levels were changed in a
few places in the XPCOM plugin to reduce spaminess, especially in the event
the development mode server connection goes away while the page is still
running.

The Safari plugin changes have had only minimal changes, and the IE plugin
changes are completely untested.  They are checked in anyway since they were
never brought up to common code changes made last year, and therefore can't
be built from trunk anyway, so they are certainly no worse off this way.

When Bob is in town next week, we will test the Safari plugin more thoroughly
(including building an install image) and get the IE plugin built/tested.

Patch by: jat
Review by: bobv



git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@5998 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/plugins/common/AllowedConnections.cpp b/plugins/common/AllowedConnections.cpp
index 1f93f65..39b8a0e 100644
--- a/plugins/common/AllowedConnections.cpp
+++ b/plugins/common/AllowedConnections.cpp
@@ -1,12 +1,12 @@
 /*
  * Copyright 2008 Google Inc.
- * 
+ *
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  * use this file except in compliance with the License. You may obtain a copy of
  * the License at
- * 
+ *
  * http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
@@ -15,17 +15,20 @@
  */
 
 #include "Debug.h"
+#include <string>
+#include <cstring>
 
 #include "AllowedConnections.h"
 
 void AllowedConnections::init() {
 }
 
-bool AllowedConnections::isAllowed(const std::string& target) {
-  return true;
-}
-
 bool AllowedConnections::isAllowed(const char* host, int port) {
+  // always allow localhost
+  if (!strcmp(host, "localhost") || !strcmp(host, "127.0.0.1")) {
+    return true;
+  }
+  // TODO(jat): allow specified IP addresses that are actually on this machine
   return true;
 }
 
diff --git a/plugins/common/AllowedConnections.h b/plugins/common/AllowedConnections.h
index 0dbed2e..ff48693 100644
--- a/plugins/common/AllowedConnections.h
+++ b/plugins/common/AllowedConnections.h
@@ -2,13 +2,13 @@
 #define _H_AllowedConnections
 /*
  * Copyright 2008 Google Inc.
- * 
+ *
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  * use this file except in compliance with the License. You may obtain a copy of
  * the License at
- * 
+ *
  * http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
@@ -19,14 +19,17 @@
 #include <string>
 
 /**
- * Manages rules to control access to other sites.
+ * Manages rules to control access to other sites from the plugin.  This is
+ * important since arbitrary web pages could try and use the plugin to connect
+ * to hosts the browser's machine has access to, such as doing port scanning
+ * behind a firewall.
  */
 class AllowedConnections {
 public:
   AllowedConnections() {
     init();
   }
-  
+
   AllowedConnections(const std::string& rule) {
     init();
     parseRule(rule);
@@ -34,14 +37,7 @@
 
   /**
    * Returns true if a connection to the requested target is allowed.
-   * 
-   * @param target host or host:port to test
-   */
-  bool isAllowed(const std::string& target);
-
-  /**
-   * Returns true if a connection to the requested target is allowed.
-   * 
+   *
    * @param host name or address to connect to
    * @param port TCP port to connect to
    */
diff --git a/plugins/common/BrowserChannel.h b/plugins/common/BrowserChannel.h
index 0a65c62..ac91af5 100644
--- a/plugins/common/BrowserChannel.h
+++ b/plugins/common/BrowserChannel.h
@@ -5,7 +5,7 @@
  */
 
 /* from BrowserChannel.BROWSERCHANNEL_PROTOCOL_VERSION */
-#define BROWSERCHANNEL_PROTOCOL_VERSION 1
+#define BROWSERCHANNEL_PROTOCOL_VERSION 2
 
 /* from com.google.gwt.dev.shell.BrowserChannel.SpecialDispatchId */
 #define SPECIAL_HAS_METHOD 0
@@ -16,11 +16,17 @@
 /* from com.google.gwt.dev.shell.BrowserChannel.MessageType */
 #define MESSAGE_TYPE_INVOKE 0
 #define MESSAGE_TYPE_RETURN 1
-#define MESSAGE_TYPE_LOAD_MODULE 2
+#define MESSAGE_TYPE_OLD_LOAD_MODULE 2
 #define MESSAGE_TYPE_QUIT 3
 #define MESSAGE_TYPE_LOADJSNI 4
 #define MESSAGE_TYPE_INVOKESPECIAL 5
 #define MESSAGE_TYPE_FREEVALUE 6
+#define MESSAGE_TYPE_FATAL_ERROR 7
+#define MESSAGE_TYPE_CHECK_VERSIONS 8
+#define MESSAGE_TYPE_PROTOCOL_VERSION 9
+#define MESSAGE_TYPE_CHOOSE_TRANSPORT 10
+#define MESSAGE_TYPE_SWITCH_TRANSPORT 11
+#define MESSAGE_TYPE_LOAD_MODULE 12
 
 /* from com.google.gwt.dev.shell.BrowserChannel.Value.ValueType */
 #define VALUE_TYPE_NULL 0
diff --git a/plugins/common/CheckVersionsMessage.cpp b/plugins/common/CheckVersionsMessage.cpp
new file mode 100644
index 0000000..911cf38
--- /dev/null
+++ b/plugins/common/CheckVersionsMessage.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+#include "CheckVersionsMessage.h"
+#include "HostChannel.h"
+#include "scoped_ptr/scoped_ptr.h"
+
+CheckVersionsMessage::~CheckVersionsMessage() {
+}
+
+char CheckVersionsMessage::getType() const {
+  return TYPE;
+}
+
+/**
+ * Receive a CheckVersions message from the channel (note that the message
+ * type has already been read).  Caller is responsible for destroying
+ * returned message.  Returns null on error.
+ */
+CheckVersionsMessage* CheckVersionsMessage::receive(HostChannel& channel) {
+  int minVersion;
+  if (!channel.readInt(minVersion)) {
+    // TODO(jat): error handling
+    printf("Failed to read minimum version\n");
+    return 0;
+  }
+  int maxVersion;
+  if (!channel.readInt(maxVersion)) {
+    // TODO(jat): error handling
+    printf("Failed to read maximum version\n");
+    return 0;
+  }
+  std::string hostedHtmlVersion;
+  if (!channel.readString(hostedHtmlVersion)) {
+    // TODO(jat): error handling
+    printf("Failed to read hosted.html version\n");
+    return 0;
+  }
+  return new CheckVersionsMessage(minVersion, maxVersion, hostedHtmlVersion);
+}
+
+/**
+ * Send a fatal error message on the channel.
+ */
+bool CheckVersionsMessage::send(HostChannel& channel, int minVersion,
+    int maxVersion, const std::string& hostedHtmlVersion) {
+  if (!channel.sendByte(TYPE)) return false;
+  if (!channel.sendInt(minVersion)) return false;
+  if (!channel.sendInt(maxVersion)) return false;
+  if (!channel.sendString(hostedHtmlVersion)) return false;
+  return true;
+}
diff --git a/plugins/common/CheckVersionsMessage.h b/plugins/common/CheckVersionsMessage.h
new file mode 100644
index 0000000..10634ae
--- /dev/null
+++ b/plugins/common/CheckVersionsMessage.h
@@ -0,0 +1,56 @@
+#ifndef __CHECKVERSIONSMESSAGE_H
+#define __CHECKVERSIONSMESSAGE_H
+/*
+ * Copyright 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+#include <string>
+#include "Message.h"
+#include "BrowserChannel.h"
+#include "Value.h"
+
+class HostChannel;
+
+/**
+ * Class representing a CheckVersions message sent to the server.
+ *
+ * This message tells the server the range or protocol versions this plugin
+ * understands as well as the hosted.html version (so stale copies of it can
+ * be detected).
+ */
+class CheckVersionsMessage : public Message {
+public:
+  static const char TYPE = MESSAGE_TYPE_CHECK_VERSIONS;
+private:
+  int minVersion;
+  int maxVersion;
+  const std::string& hostedHtmlVersion;
+
+protected:
+  CheckVersionsMessage(int minVersion, int maxVersion,
+      const std::string& hostedHtmlVersion) : minVersion(minVersion),
+      maxVersion(maxVersion), hostedHtmlVersion(hostedHtmlVersion) {}
+
+public:
+  ~CheckVersionsMessage();
+  virtual char getType() const;
+
+  const std::string& getHostedHtmlVersion() const { return hostedHtmlVersion; }
+
+  static CheckVersionsMessage* receive(HostChannel& channel);
+  static bool send(HostChannel& channel, int minVersion, int maxVersion,
+      const std::string& hostedHtmlVersion);
+};
+#endif
diff --git a/plugins/common/ChooseTransportMessage.cpp b/plugins/common/ChooseTransportMessage.cpp
new file mode 100644
index 0000000..08c315f
--- /dev/null
+++ b/plugins/common/ChooseTransportMessage.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+#include <cstdarg>
+#include <vector>
+#include "ChooseTransportMessage.h"
+#include "HostChannel.h"
+#include "scoped_ptr/scoped_ptr.h"
+
+ChooseTransportMessage::~ChooseTransportMessage() {
+}
+
+char ChooseTransportMessage::getType() const {
+  return TYPE;
+}
+
+/**
+ * Receive an ChooseTransport message from the channel (note that the message
+ * type has already been read).  Caller is responsible for destroying
+ * returned message.  Returns null on error.
+ */
+ChooseTransportMessage* ChooseTransportMessage::receive(HostChannel& channel) {
+  int length;
+  if (!channel.readInt(length)) {
+    // TODO(jat): error handling
+    printf("Failed to read transport\n");
+    return 0;
+  }
+  std::vector<std::string> transports;
+  for (int i = 0; i < length; ++i) {
+    std::string transport;
+    if (!channel.readString(transport)) {
+      // TODO(jat): error handling
+      printf("Failed to read transport\n");
+      return 0;
+    }
+    transports.push_back(transport);
+  }
+  return new ChooseTransportMessage(transports);
+}
+
+/**
+ * Send this ChooseTransport message on the channel.
+ */
+bool ChooseTransportMessage::send(HostChannel& channel,
+    const std::vector<std::string>& transports) {
+  if (!channel.sendByte(TYPE)) return false;
+  int n = transports.size();
+  if (!channel.sendInt(n)) return false;
+  for (int i = 0; i < n; ++i) {
+    if (!channel.sendString(transports[i])) return false;
+  }
+  return true;
+}
diff --git a/plugins/common/ChooseTransportMessage.h b/plugins/common/ChooseTransportMessage.h
new file mode 100644
index 0000000..512185e
--- /dev/null
+++ b/plugins/common/ChooseTransportMessage.h
@@ -0,0 +1,55 @@
+#ifndef __CHOOSETRANSPORTMESSAGE_H
+#define __CHOOSETRANSPORTMESSAGE_H
+/*
+ * Copyright 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+#include <string>
+#include <vector>
+#include "Message.h"
+#include "BrowserChannel.h"
+#include "Value.h"
+
+class HostChannel;
+
+/**
+ * Class representing a ChooseTransport message to send to the server.
+ *
+ * This message type is a request for the server to choose an alternate
+ * transport from a provide list, such as a shared memory transport.  The
+ * set of transport names is open-ended and thus requires mutual agreement
+ * on the names between the client and server.
+ */
+class ChooseTransportMessage : public Message {
+public:
+  static const char TYPE = MESSAGE_TYPE_CHOOSE_TRANSPORT;
+private:
+  std::vector<std::string> transports;
+
+protected:
+  ChooseTransportMessage(const std::vector<std::string>& transports)
+      : transports(transports) {}
+
+public:
+  ~ChooseTransportMessage();
+  virtual char getType() const;
+
+  const std::vector<std::string>& getTransports() const { return transports; }
+
+  static ChooseTransportMessage* receive(HostChannel& channel);
+  static bool send(HostChannel& channel,
+      const std::vector<std::string>& transport);
+};
+#endif
diff --git a/plugins/common/DebugLevel.h b/plugins/common/DebugLevel.h
index d172e99..b6f6a27 100644
--- a/plugins/common/DebugLevel.h
+++ b/plugins/common/DebugLevel.h
@@ -19,7 +19,7 @@
 // Defines the default debug level if not defined -- see Debug.h
 // Can also define GWT_DEBUGDISABLE to remove all traces of the debug code.
 //#define GWT_DEBUGLEVEL Debugging
-#define GWT_DEBUGLEVEL Spam
+#define GWT_DEBUGLEVEL Info
 //#define GWT_DEBUGDISABLE
 
 #endif
diff --git a/plugins/common/FatalErrorMessage.cpp b/plugins/common/FatalErrorMessage.cpp
new file mode 100644
index 0000000..0b4b2d0
--- /dev/null
+++ b/plugins/common/FatalErrorMessage.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+#include "FatalErrorMessage.h"
+#include "HostChannel.h"
+#include "scoped_ptr/scoped_ptr.h"
+
+FatalErrorMessage::~FatalErrorMessage() {
+}
+
+char FatalErrorMessage::getType() const {
+  return TYPE;
+}
+
+/**
+ * Receive an FatalError message from the channel (note that the message
+ * type has already been read).  Caller is responsible for destroying
+ * returned message.  Returns null on error.
+ */
+FatalErrorMessage* FatalErrorMessage::receive(HostChannel& channel) {
+  std::string error;
+  if (!channel.readString(error)) {
+    // TODO(jat): error handling
+    printf("Failed to read error message\n");
+    return 0;
+  }
+  return new FatalErrorMessage(error);
+}
+
+/**
+ * Send a fatal error message on the channel.
+ */
+bool FatalErrorMessage::send(HostChannel& channel, const std::string& error) {
+  if (!channel.sendByte(TYPE)) return false;
+  if (!channel.sendString(error)) return false;
+  return true;
+}
diff --git a/plugins/common/FatalErrorMessage.h b/plugins/common/FatalErrorMessage.h
new file mode 100644
index 0000000..a80b9d1
--- /dev/null
+++ b/plugins/common/FatalErrorMessage.h
@@ -0,0 +1,54 @@
+#ifndef __FATALERRORMESSAGE_H
+#define __FATALERRORMESSAGE_H
+/*
+ * Copyright 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+#include <string>
+#include "Message.h"
+#include "BrowserChannel.h"
+#include "Value.h"
+
+class HostChannel;
+
+/**
+ * Class representing an FatalError message received from the server.
+ *
+ * This message indicates that a fatal error occurred during the processing
+ * of the previous message from the client and the connection should be
+ * aborted.
+ */
+class FatalErrorMessage : public Message {
+public:
+  static const char TYPE = MESSAGE_TYPE_FATAL_ERROR;
+private:
+  std::string error;
+
+protected:
+  /**
+   * @param error error message
+   */
+  FatalErrorMessage(const std::string& error) : error(error) {}
+
+public:
+  ~FatalErrorMessage();
+  virtual char getType() const;
+
+  const std::string& getError() const { return error; }
+
+  static FatalErrorMessage* receive(HostChannel& channel);
+  static bool send(HostChannel& channel, const std::string& error);
+};
+#endif
diff --git a/plugins/common/FreeValueMessage.h b/plugins/common/FreeValueMessage.h
index a8b7a64..3158f40 100644
--- a/plugins/common/FreeValueMessage.h
+++ b/plugins/common/FreeValueMessage.h
@@ -2,13 +2,13 @@
 #define __H_FreeValueMessage
 /*
  * Copyright 2008 Google Inc.
- * 
+ *
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  * use this file except in compliance with the License. You may obtain a copy of
  * the License at
- * 
+ *
  * http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
@@ -21,26 +21,35 @@
 #include "BrowserChannel.h"
 #include "HostChannel.h"
 
+/**
+ * Class representing an FreeValue message sent or received from the server.
+ *
+ * This message gives a list of object IDs which are no longer needed by the
+ * sending side.  Note that there is no reply to this message, and it can
+ * only be sent when the other side is expecting to receive a return value or
+ * another invoke.  Special care must be taken to ensure that any freed values
+ * referenced by the succeeding invoke/return are resurrected instead of freed.
+ */
 class FreeValueMessage : public Message {
-public:  
+public:
   static const char TYPE = MESSAGE_TYPE_FREEVALUE;
 private:
   int idCount;
   const int* ids;
-  
+
   FreeValueMessage(int idCount, const int* ids) : idCount(idCount), ids(ids) {}
-  
+
 public:
   ~FreeValueMessage();
 
   virtual char getType() const {
     return TYPE;
   }
-  
+
   int getIdCount() const {
     return idCount;
   }
-  
+
   const int* const getIds() const {
     return ids;
   }
diff --git a/plugins/common/HostChannel.cpp b/plugins/common/HostChannel.cpp
index 896667e..53272da 100644
--- a/plugins/common/HostChannel.cpp
+++ b/plugins/common/HostChannel.cpp
@@ -37,6 +37,11 @@
 #include "Platform.h"
 #include "ByteOrder.h"
 
+#include "CheckVersionsMessage.h"
+#include "ProtocolVersionMessage.h"
+#include "ChooseTransportMessage.h"
+#include "SwitchTransportMessage.h"
+#include "FatalErrorMessage.h"
 #include "FreeValueMessage.h"
 #include "HostChannel.h"
 #include "LoadJsniMessage.h"
@@ -65,6 +70,51 @@
   return sock.connect(host, port);
 }
 
+bool HostChannel::init(SessionHandler* handler, int minProtoVers,
+    int maxProtoVers, const std::string& hostedHtmlVers) {
+  Debug::log(Debug::Info) << "initializing connection: proto=" << minProtoVers
+      << "-" << maxProtoVers << ", hostedHtmlVersion=" << hostedHtmlVers
+      << Debug::flush;
+  // TODO(jat): support transport selection
+  CheckVersionsMessage::send(*this, minProtoVers, maxProtoVers, hostedHtmlVers);
+  flush();
+  char type;
+  if (!readByte(type)) {
+    handler->fatalError(*this, "Failed to receive message type");
+    Debug::log(Debug::Error) << "Failed to receive message type" << Debug::flush;
+    disconnectFromHost();
+    return false;
+  }
+  switch (type) {
+    case MESSAGE_TYPE_PROTOCOL_VERSION:
+    {
+      scoped_ptr<ProtocolVersionMessage> imsg(ProtocolVersionMessage
+          ::receive(*this));
+      if (!imsg.get()) {
+        Debug::log(Debug::Error) << "Failed to receive protocol version message"
+            << Debug::flush;
+        return false;
+      }
+      // TODO(jat): save selected protocol version when we support a range
+      break;
+    }
+    case MESSAGE_TYPE_FATAL_ERROR:
+    {
+      scoped_ptr<FatalErrorMessage> imsg(FatalErrorMessage::receive(*this));
+      if (!imsg.get()) {
+        Debug::log(Debug::Error) << "Failed to receive fatal error message"
+            << Debug::flush;
+        return false;
+      }
+      handler->fatalError(*this, imsg.get()->getError());
+      return false;
+    }
+    default:
+      return false;
+  }
+  return true;
+}
+
 bool HostChannel::disconnectFromHost() {
   Debug::log(Debug::Debugging) << "Disconnecting channel" << Debug::flush;
   if (!isConnected()) {
@@ -189,9 +239,13 @@
   char type;
   while (true) {
     flush();
-     Debug::log(Debug::Spam) << "Waiting for response, flushed output" << Debug::flush;
+    Debug::log(Debug::Spam) << "Waiting for response, flushed output"
+        << Debug::flush;
     if (!readByte(type)) {
-      Debug::log(Debug::Error) << "Failed to receive message type" << Debug::flush;
+      if (isConnected()) {
+        Debug::log(Debug::Error) << "Failed to receive message type"
+            << Debug::flush;
+      }
       return 0;
     }
     switch (type) {
diff --git a/plugins/common/HostChannel.h b/plugins/common/HostChannel.h
index 0097b6d..8facabe 100644
--- a/plugins/common/HostChannel.h
+++ b/plugins/common/HostChannel.h
@@ -44,9 +44,15 @@
     Debug::log(Debug::Debugging) << "HostChannel destroyed" << Debug::flush;
   }
 
+  // Connects to the OOPHM server (socket operations only).
   bool connectToHost(const char* host, unsigned port);
+
+  // Negotiates protocol version and transport selection.
+  bool init(SessionHandler* handler, int minVersion, int maxVersion,
+      const std::string& hostedHtmlVersion);
+
   bool disconnectFromHost();
-  
+
   bool isConnected() const {
     return sock.isConnected();
   }
diff --git a/plugins/common/InvokeSpecialMessage.h b/plugins/common/InvokeSpecialMessage.h
index 196baa5..5888cc1 100644
--- a/plugins/common/InvokeSpecialMessage.h
+++ b/plugins/common/InvokeSpecialMessage.h
@@ -25,8 +25,8 @@
 class HostChannel;
 
 /**
- * Class representing an InvokeSpecialMessage received from the server, and a way
- * to send an invoke message to the server.
+ * Class representing an InvokeSpecial message received from the server, and a
+ * way to send an invoke message to the server.
  */
 class InvokeSpecialMessage : public Message {
 public:
diff --git a/plugins/common/LoadModuleMessage.cpp b/plugins/common/LoadModuleMessage.cpp
index a436961..1ee4ab3 100644
--- a/plugins/common/LoadModuleMessage.cpp
+++ b/plugins/common/LoadModuleMessage.cpp
@@ -26,16 +26,22 @@
   return LoadModuleMessage::TYPE;
 }
 
-bool LoadModuleMessage::send(HostChannel& channel, uint32_t version, const char* moduleName,
-    const uint32_t moduleNameLen, const char* userAgent, SessionHandler* handler) {
-  Debug::log(Debug::Spam) << "LoadModule(module=\"" << moduleName << "\",vers="
-      << version << ")" << Debug::flush;
-  if (!channel.sendByte(TYPE) || !channel.sendInt(version)
-      || !channel.sendString(moduleName, moduleNameLen)
-      || !channel.sendString(userAgent, static_cast<uint32_t>(strlen(userAgent)))) {
+bool LoadModuleMessage::send(HostChannel& channel, const std::string& url,
+    const std::string& tabKey, const std::string& sessionKey,
+    const std::string& moduleName, const std::string& userAgent,
+    SessionHandler* handler) {
+  Debug::log(Debug::Spam) << "LoadModule(url=\"" << url << "\", tabKey=\""
+      << "\", sessionKey=\"" << sessionKey << "\", module=\"" << moduleName
+      << "\")" << Debug::flush;
+  if (!channel.sendByte(TYPE) || !channel.sendString(url)
+      || !channel.sendString(tabKey)
+      || !channel.sendString(sessionKey)
+      || !channel.sendString(moduleName)
+      || !channel.sendString(userAgent)) {
     return false;
   }
-  scoped_ptr<ReturnMessage> ret(channel.reactToMessagesWhileWaitingForReturn(handler));
+  scoped_ptr<ReturnMessage> ret(channel.reactToMessagesWhileWaitingForReturn(
+      handler));
   if (!ret.get()) {
     return false;
   }
diff --git a/plugins/common/LoadModuleMessage.h b/plugins/common/LoadModuleMessage.h
index 3091c46..4a331cb 100644
--- a/plugins/common/LoadModuleMessage.h
+++ b/plugins/common/LoadModuleMessage.h
@@ -2,13 +2,13 @@
 #define __LOADMODULEMESSAGE_H
 /*
  * Copyright 2008 Google Inc.
- * 
+ *
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  * use this file except in compliance with the License. You may obtain a copy of
  * the License at
- * 
+ *
  * http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
@@ -25,22 +25,37 @@
 
 class HostChannel;
 
+/**
+ * Class representing a LoadModule message sent to the server.
+ *
+ * This message requests that the server load the requested module.  A return
+ * message is not sent until the module is unloaded or fails to load.
+ */
+
 class LoadModuleMessage : public Message {
   static const char TYPE = MESSAGE_TYPE_LOAD_MODULE;
 
-public:  
-  LoadModuleMessage(int version, std::string& moduleName, std::string& userAgent) :
-    version(version), moduleName(moduleName), userAgent(userAgent) { }
+public:
+  LoadModuleMessage(const std::string& url, const std::string& tabKey,
+      const std::string& sessionKey, const std::string& moduleName,
+      const std::string& userAgent) : url(url), tabKey(tabKey),
+      sessionKey(sessionKey), moduleName(moduleName), userAgent(userAgent) { }
 
-  int getVersion() const { return version; }
+  const std::string& getUrl() const { return url; }
+  const std::string& getTabKey() const { return tabKey; }
+  const std::string& getSessionKey() const { return sessionKey; }
   const std::string& getModuleName() const { return moduleName; }
   const std::string& getUserAgent() const { return userAgent; }
   virtual char getType() const;
-  
-  static bool send(HostChannel& channel, uint32_t version, const char* moduleName,
-      uint32_t moduleNameLen, const char* userAgent, SessionHandler* handler);
+
+  static bool send(HostChannel& channel, const std::string& url,
+      const std::string& tabKey, const std::string& sessionKey,
+      const std::string& moduleName, const std::string& userAgent,
+      SessionHandler* handler);
 private:
-  int version;
+  std::string url;
+  std::string tabKey;
+  std::string sessionKey;
   std::string moduleName;
   std::string userAgent;
 };
diff --git a/plugins/common/Makefile b/plugins/common/Makefile
index b22fd27..abfd933 100644
--- a/plugins/common/Makefile
+++ b/plugins/common/Makefile
@@ -18,12 +18,16 @@
       ReturnMessage.h Value.h BrowserChannel.h Debug.h DebugLevel.h \
       SessionHandler.h ServerMethods.h Socket.h AllowedConnections.h \
       LoadJsniMessage.h InvokeSpecialMessage.h FreeValueMessage.h \
-      ByteOrder.h
+      ByteOrder.h FatalErrorMessage.h CheckVersionsMessage.h \
+      ChooseTransportMessage.h SwitchTransportMessage.h \
+      ProtocolVersionMessage.h
 
 SRCS=	HostChannel.cpp LoadModuleMessage.cpp InvokeMessage.cpp \
 	ReturnMessage.cpp ServerMethods.cpp Debug.cpp Socket.cpp \
 	AllowedConnections.cpp LoadJsniMessage.cpp InvokeSpecialMessage.cpp \
-	FreeValueMessage.cpp
+	FreeValueMessage.cpp FatalErrorMessage.cpp CheckVersionsMessage.cpp \
+      ChooseTransportMessage.cpp SwitchTransportMessage.cpp \
+      ProtocolVersionMessage.cpp
 
 LIBCOMMON= libcommon$(FLAG32BIT).a
 OBJDIR= obj$(FLAG32BIT)
@@ -55,9 +59,11 @@
 
 # DO NOT DELETE
 HostChannel.o: HostChannel.cpp Debug.h Platform.h DebugLevel.h \
-  ByteOrder.h FreeValueMessage.h Message.h BrowserChannel.h HostChannel.h \
-  Socket.h AllowedConnections.h ReturnMessage.h Value.h SessionHandler.h \
-  LoadJsniMessage.h InvokeMessage.h InvokeSpecialMessage.h QuitMessage.h \
+  ByteOrder.h CheckVersionsMessage.h Message.h BrowserChannel.h Value.h \
+  ProtocolVersionMessage.h ChooseTransportMessage.h \
+  SwitchTransportMessage.h FreeValueMessage.h HostChannel.h Socket.h \
+  AllowedConnections.h ReturnMessage.h SessionHandler.h LoadJsniMessage.h \
+  InvokeMessage.h InvokeSpecialMessage.h QuitMessage.h \
   scoped_ptr/scoped_ptr.h
 LoadModuleMessage.o: LoadModuleMessage.cpp Debug.h Platform.h \
   DebugLevel.h LoadModuleMessage.h Message.h BrowserChannel.h \
@@ -91,3 +97,26 @@
   BrowserChannel.h HostChannel.h Debug.h Platform.h DebugLevel.h \
   ByteOrder.h Socket.h AllowedConnections.h ReturnMessage.h Value.h \
   SessionHandler.h scoped_ptr/scoped_ptr.h
+FatalErrorMessage.o: FatalErrorMessage.cpp FatalErrorMessage.h Message.h \
+  BrowserChannel.h Value.h Debug.h Platform.h DebugLevel.h HostChannel.h \
+  ByteOrder.h Socket.h AllowedConnections.h ReturnMessage.h \
+  SessionHandler.h scoped_ptr/scoped_ptr.h
+CheckVersionsMessage.o: CheckVersionsMessage.cpp CheckVersionsMessage.h \
+  Message.h BrowserChannel.h Value.h Debug.h Platform.h DebugLevel.h \
+  HostChannel.h ByteOrder.h Socket.h AllowedConnections.h ReturnMessage.h \
+  SessionHandler.h scoped_ptr/scoped_ptr.h
+ChooseTransportMessage.o: ChooseTransportMessage.cpp \
+  ChooseTransportMessage.h Message.h BrowserChannel.h Value.h Debug.h \
+  Platform.h DebugLevel.h HostChannel.h ByteOrder.h Socket.h \
+  AllowedConnections.h ReturnMessage.h SessionHandler.h \
+  scoped_ptr/scoped_ptr.h
+SwitchTransportMessage.o: SwitchTransportMessage.cpp \
+  SwitchTransportMessage.h Message.h BrowserChannel.h Value.h Debug.h \
+  Platform.h DebugLevel.h HostChannel.h ByteOrder.h Socket.h \
+  AllowedConnections.h ReturnMessage.h SessionHandler.h \
+  scoped_ptr/scoped_ptr.h
+ProtocolVersionMessage.o: ProtocolVersionMessage.cpp \
+  ProtocolVersionMessage.h Message.h BrowserChannel.h Value.h Debug.h \
+  Platform.h DebugLevel.h HostChannel.h ByteOrder.h Socket.h \
+  AllowedConnections.h ReturnMessage.h SessionHandler.h \
+  scoped_ptr/scoped_ptr.h
diff --git a/plugins/common/ProtocolVersionMessage.cpp b/plugins/common/ProtocolVersionMessage.cpp
new file mode 100644
index 0000000..e2db3f9
--- /dev/null
+++ b/plugins/common/ProtocolVersionMessage.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+#include "ProtocolVersionMessage.h"
+#include "HostChannel.h"
+#include "scoped_ptr/scoped_ptr.h"
+
+ProtocolVersionMessage::~ProtocolVersionMessage() {
+}
+
+char ProtocolVersionMessage::getType() const {
+  return TYPE;
+}
+
+/**
+ * Receive a ProtocolVersion message from the server.
+ */
+ProtocolVersionMessage* ProtocolVersionMessage::receive(HostChannel& channel) {
+  int version;
+  if (!channel.readInt(version)) {
+    // TODO(jat): error handling
+    printf("Failed to read version\n");
+    return 0;
+  }
+  return new ProtocolVersionMessage(version);
+}
+
+/**
+ * Send a ProtocolVersion message on the channel.
+ */
+bool ProtocolVersionMessage::send(HostChannel& channel, int version) {
+  if (!channel.sendByte(TYPE)) return false;
+  if (!channel.sendInt(version)) return false;
+  return true;
+}
diff --git a/plugins/common/ProtocolVersionMessage.h b/plugins/common/ProtocolVersionMessage.h
new file mode 100644
index 0000000..db6f770
--- /dev/null
+++ b/plugins/common/ProtocolVersionMessage.h
@@ -0,0 +1,54 @@
+#ifndef __PROTOCOLVERSIONMESSAGE_H
+#define __PROTOCOLVERSIONMESSAGE_H
+/*
+ * Copyright 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+#include <string>
+#include "Message.h"
+#include "BrowserChannel.h"
+#include "Value.h"
+
+class HostChannel;
+
+/**
+ * Class representing a ProtocolVersion message received from the server, and a
+ * way to send one.
+ *
+ * This message indicates which version of the protocol the server has chosen
+ * for the remainder of the communication.
+ */
+class ProtocolVersionMessage : public Message {
+public:
+  static const char TYPE = MESSAGE_TYPE_PROTOCOL_VERSION;
+private:
+  int version;
+
+protected:
+  /**
+   * @param version selected protocol version
+   */
+  ProtocolVersionMessage(int version) : version(version) {}
+
+public:
+  ~ProtocolVersionMessage();
+  virtual char getType() const;
+
+  int getVersion() const { return version; }
+
+  static ProtocolVersionMessage* receive(HostChannel& channel);
+  static bool send(HostChannel& channel, int version);
+};
+#endif
diff --git a/plugins/common/QuitMessage.h b/plugins/common/QuitMessage.h
index 344612f..f8f9b80 100644
--- a/plugins/common/QuitMessage.h
+++ b/plugins/common/QuitMessage.h
@@ -2,13 +2,13 @@
 #define __H_QuitMessage
 /*
  * Copyright 2008 Google Inc.
- * 
+ *
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  * use this file except in compliance with the License. You may obtain a copy of
  * the License at
- * 
+ *
  * http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
@@ -20,17 +20,21 @@
 #include "Message.h"
 #include "BrowserChannel.h"
 
+/**
+ * This class represents a Quit message sent to the server, indicating the
+ * channel should be closed down.
+ */
 class QuitMessage : public Message {
-public:  
+public:
   static const char TYPE = MESSAGE_TYPE_QUIT;
 private:
   QuitMessage() {}
-  
-public:  
+
+public:
   virtual char getType() const {
     return TYPE;
   }
-  
+
   static bool send(HostChannel& channel) {
     return channel.sendByte(TYPE);
   }
diff --git a/plugins/common/ReturnMessage.h b/plugins/common/ReturnMessage.h
index fddf9ec..374b9fe 100644
--- a/plugins/common/ReturnMessage.h
+++ b/plugins/common/ReturnMessage.h
@@ -2,13 +2,13 @@
 #define __RETURNMESSAGE_H
 /*
  * Copyright 2008 Google Inc.
- * 
+ *
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  * use this file except in compliance with the License. You may obtain a copy of
  * the License at
- * 
+ *
  * http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
@@ -23,20 +23,27 @@
 
 class HostChannel;
 
+/**
+ * Class representing a Return message received from the server, and a way
+ * to send one.
+ *
+ * This message gives the return value of a previous Invoke or LoadModule
+ * message (for the latter, only the exception state is important).
+ */
 class ReturnMessage : public Message {
   static const char TYPE = MESSAGE_TYPE_RETURN;
 private:
   bool bisException;
   Value retval;
-  
-public:  
+
+public:
   ReturnMessage(bool isException, const Value& retValue) : bisException(isException),
       retval(retValue) {}
 
   bool isException() const { return bisException; }
   const Value& getReturnValue() const { return retval; }
   virtual char getType() const;
-  
+
   static ReturnMessage* receive(HostChannel& channel);
   static bool send(HostChannel& channel, bool isException, const Value& retValue);
 };
diff --git a/plugins/common/ServerMethods.cpp b/plugins/common/ServerMethods.cpp
index 5a18bcb..0be51b0 100644
--- a/plugins/common/ServerMethods.cpp
+++ b/plugins/common/ServerMethods.cpp
@@ -1,12 +1,12 @@
 /*
  * Copyright 2008 Google Inc.
- * 
+ *
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  * use this file except in compliance with the License. You may obtain a copy of
  * the License at
- * 
+ *
  * http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
@@ -29,6 +29,11 @@
 
 Value ServerMethods::getProperty(HostChannel& channel, SessionHandler* handler, int objectRef,
     int dispatchId) {
+  if (!channel.isConnected()) {
+    Debug::log(Debug::Debugging) << "Ignoring getProperty after disconnect"
+        << Debug::flush;
+    return Value();
+  }
   Value args[2];
   args[0].setInt(objectRef);
   args[1].setInt(dispatchId);
@@ -52,6 +57,11 @@
     // only JSNI-style names and toString are valid
     return -1;
   }
+  if (!channel.isConnected()) {
+    Debug::log(Debug::Debugging) << "Ignoring hasMethod after disconnect"
+        << Debug::flush;
+    return -2;
+  }
   Value arg;
   arg.setString(name);
   if (!InvokeSpecialMessage::send(channel, SPECIAL_HAS_METHOD, 1, &arg)) {
@@ -74,6 +84,11 @@
     // only JSNI-style names and toString are valid
     return -1;
   }
+  if (!channel.isConnected()) {
+    Debug::log(Debug::Debugging) << "Ignoring hasProperty after disconnect"
+        << Debug::flush;
+    return -2;
+  }
   Value arg;
   arg.setString(name);
   if (!InvokeSpecialMessage::send(channel, SPECIAL_HAS_PROPERTY, 1, &arg)) {
@@ -92,6 +107,11 @@
 
 bool ServerMethods::setProperty(HostChannel& channel, SessionHandler* handler, int objectRef,
     int dispatchId, const Value& value) {
+  if (!channel.isConnected()) {
+    Debug::log(Debug::Debugging) << "Ignoring setProperty after disconnect"
+        << Debug::flush;
+    return false;
+  }
   // TODO(jat): error handling?
   Value args[3];
   args[0].setInt(objectRef);
diff --git a/plugins/common/SessionHandler.h b/plugins/common/SessionHandler.h
index 217dce4..2cb011f 100644
--- a/plugins/common/SessionHandler.h
+++ b/plugins/common/SessionHandler.h
@@ -2,13 +2,13 @@
 #define _H_SessionHandler
 /*
  * Copyright 2008 Google Inc.
- * 
+ *
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  * use this file except in compliance with the License. You may obtain a copy of
  * the License at
- * 
+ *
  * http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
@@ -23,18 +23,18 @@
 
 /**
  * Interface for session-handling needs.
- * 
+ *
  * Note that if this is being "added" onto a class which extends a C structure, the inheritance
  * chain leading to the plain C object must be first in the inheritance list.
- * 
+ *
  * For example:
- * 
+ *
  * extern "C" {
  *   typedef struct PlainCstruct {
  *      ... data only members here
  *   } PlainCstruct;
  * };
- * 
+ *
  * class MyWrapper: public PlainCstruct, SessionHandler {
  *    ... virtual functions ok here
  * };
@@ -49,6 +49,13 @@
     SetProperty = SPECIAL_SET_PROPERTY
   };
 protected:
+
+  /**
+   * Report a fatal error -- the channel will be closed after this method
+   * returns.
+   */
+  virtual void fatalError(HostChannel& channel, const std::string& message) = 0;
+
   virtual void freeValue(HostChannel& channel, int idCount, const int* ids) = 0;
 
   virtual void loadJsni(HostChannel& channel, const std::string& js) = 0;
@@ -56,16 +63,16 @@
   /**
    * Does not own any of its args -- must copy them if it wants them and should not free the
    * ones passed in.
-   * 
+   *
    * Returns true if an exception occurred.
    */
   virtual bool invoke(HostChannel& channel, const Value& thisObj, const std::string& methodName,
       int numArgs, const Value* const args, Value* returnValue)=0;
-  
+
   /**
    * Invoke a plugin-provided method with the given args.  As above, this method does not own
    * any of its args.
-   * 
+   *
    * Returns true if an exception occurred.
    */
   virtual bool invokeSpecial(HostChannel& channel, SpecialMethodId method, int numArgs,
diff --git a/plugins/common/SwitchTransportMessage.cpp b/plugins/common/SwitchTransportMessage.cpp
new file mode 100644
index 0000000..ccb5520
--- /dev/null
+++ b/plugins/common/SwitchTransportMessage.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+#include "SwitchTransportMessage.h"
+#include "HostChannel.h"
+#include "scoped_ptr/scoped_ptr.h"
+
+SwitchTransportMessage::~SwitchTransportMessage() {
+}
+
+char SwitchTransportMessage::getType() const {
+  return TYPE;
+}
+
+/**
+ * Receive a SwitchTransport message from the server.
+ */
+SwitchTransportMessage* SwitchTransportMessage::receive(HostChannel& channel) {
+  std::string transport;
+  if (!channel.readString(transport)) {
+    // TODO(jat): error handling
+    printf("Failed to read transport\n");
+    return 0;
+  }
+  return new SwitchTransportMessage(transport);
+}
+
+/**
+ * Send a fatal error message on the channel.
+ */
+bool SwitchTransportMessage::send(HostChannel& channel,
+    const std::string& transport) {
+  if (!channel.sendByte(TYPE)) return false;
+  if (!channel.sendString(transport)) return false;
+  return true;
+}
diff --git a/plugins/common/SwitchTransportMessage.h b/plugins/common/SwitchTransportMessage.h
new file mode 100644
index 0000000..0dad82a
--- /dev/null
+++ b/plugins/common/SwitchTransportMessage.h
@@ -0,0 +1,53 @@
+#ifndef __SWITCHTRANSPORTMESSAGE_H
+#define __SWITCHTRANSPORTMESSAGE_H
+/*
+ * Copyright 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+#include <string>
+#include "Message.h"
+#include "BrowserChannel.h"
+#include "Value.h"
+
+class HostChannel;
+
+/**
+ * Class representing an SwitchTransport message received from the server, and a
+ * way to send one.
+ *
+ * The SwitchTransport message is sent by the server in response to a
+ * ChooseTransport message, and will select one of the available transports
+ * advertised by the client.  The empty string represents the in-band channel,
+ * and is always an acceptable response.
+ */
+class SwitchTransportMessage : public Message {
+public:
+  static const char TYPE = MESSAGE_TYPE_SWITCH_TRANSPORT;
+private:
+  std::string transport;
+
+protected:
+  SwitchTransportMessage(const std::string& transport) : transport(transport) {}
+
+public:
+  ~SwitchTransportMessage();
+  virtual char getType() const;
+
+  const std::string& getTransport() const { return transport; }
+
+  static SwitchTransportMessage* receive(HostChannel& channel);
+  static bool send(HostChannel& channel, const std::string& transport);
+};
+#endif