Initial checkin of OOPHM plugins into trunk.  Testing of non-XPCOM plugins
is still required, and more platforms need to be built.


git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@5868 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/plugins/common/AllowedConnections.cpp b/plugins/common/AllowedConnections.cpp
new file mode 100644
index 0000000..1f93f65
--- /dev/null
+++ b/plugins/common/AllowedConnections.cpp
@@ -0,0 +1,33 @@
+/*
+ * 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 "Debug.h"
+
+#include "AllowedConnections.h"
+
+void AllowedConnections::init() {
+}
+
+bool AllowedConnections::isAllowed(const std::string& target) {
+  return true;
+}
+
+bool AllowedConnections::isAllowed(const char* host, int port) {
+  return true;
+}
+
+void AllowedConnections::parseRule(const std::string& rule) {
+};
diff --git a/plugins/common/AllowedConnections.h b/plugins/common/AllowedConnections.h
new file mode 100644
index 0000000..0dbed2e
--- /dev/null
+++ b/plugins/common/AllowedConnections.h
@@ -0,0 +1,55 @@
+#ifndef _H_AllowedConnections
+#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
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+#include <string>
+
+/**
+ * Manages rules to control access to other sites.
+ */
+class AllowedConnections {
+public:
+  AllowedConnections() {
+    init();
+  }
+  
+  AllowedConnections(const std::string& rule) {
+    init();
+    parseRule(rule);
+  }
+
+  /**
+   * 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
+   */
+  bool isAllowed(const char* host, int port);
+
+private:
+  void init();
+  void parseRule(const std::string& rule);
+};
+
+#endif
diff --git a/plugins/common/BrowserChannel.h b/plugins/common/BrowserChannel.h
new file mode 100644
index 0000000..0a65c62
--- /dev/null
+++ b/plugins/common/BrowserChannel.h
@@ -0,0 +1,38 @@
+/*
+ * DO NOT EDIT
+ * Generated by com.google.gwt.util.tools.OophmHeaderFileGenerator
+ * TODO(jat): update generator to handle modifications
+ */
+
+/* from BrowserChannel.BROWSERCHANNEL_PROTOCOL_VERSION */
+#define BROWSERCHANNEL_PROTOCOL_VERSION 1
+
+/* from com.google.gwt.dev.shell.BrowserChannel.SpecialDispatchId */
+#define SPECIAL_HAS_METHOD 0
+#define SPECIAL_HAS_PROPERTY 1
+#define SPECIAL_GET_PROPERTY 2
+#define SPECIAL_SET_PROPERTY 3
+
+/* 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_QUIT 3
+#define MESSAGE_TYPE_LOADJSNI 4
+#define MESSAGE_TYPE_INVOKESPECIAL 5
+#define MESSAGE_TYPE_FREEVALUE 6
+
+/* from com.google.gwt.dev.shell.BrowserChannel.Value.ValueType */
+#define VALUE_TYPE_NULL 0
+#define VALUE_TYPE_BOOLEAN 1
+#define VALUE_TYPE_BYTE 2
+#define VALUE_TYPE_CHAR 3
+#define VALUE_TYPE_SHORT 4
+#define VALUE_TYPE_INT 5
+#define VALUE_TYPE_LONG 6
+#define VALUE_TYPE_FLOAT 7
+#define VALUE_TYPE_DOUBLE 8
+#define VALUE_TYPE_STRING 9
+#define VALUE_TYPE_JAVA_OBJECT 10
+#define VALUE_TYPE_JS_OBJECT 11
+#define VALUE_TYPE_UNDEFINED 12
diff --git a/plugins/common/ByteOrder.h b/plugins/common/ByteOrder.h
new file mode 100644
index 0000000..7e6bd86
--- /dev/null
+++ b/plugins/common/ByteOrder.h
@@ -0,0 +1,141 @@
+#ifndef __H_ByteOrder
+#define __H_ByteOrder
+/*
+ * 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 "Platform.h"
+#include <cstring>
+
+class ByteOrder {
+private:
+  enum FloatByteOrder {
+    FLOAT_BIG_ENDIAN,
+    FLOAT_LITTLE_ENDIAN,
+    // TODO(jat): do we need to consider anything other than straight
+    // big-endian or little-endian?  PDP-11 (irrelevant), ARM (probably
+    // relevant for mobile devices), MIPS (probably not relevant, but maybe)
+    // and others have some intermediate endianess.  Also, FP-endianess is not
+    // necessarily the same as that for integers.
+  };
+#ifdef PLATFORM_FLOAT_ENDIANESS
+  static const FloatByteOrder floatByteOrder = PLATFORM_FLOAT_ENDIANESS;
+#else
+  FloatByteOrder floatByteOrder;
+#endif
+
+  typedef union {
+    float v;
+    char b[sizeof(float)];
+  } FloatUnion;
+
+  typedef union {
+    double v;
+    char b[sizeof(double)];
+  } DoubleUnion;
+
+  /**
+   * Copy src to dest, reversing the order of the bytes.
+   * Assumes src and dest do not overlap.
+   */
+  void memcpyrev(char* dest, const char* src, size_t n) {
+    src += n;
+    while (n-- > 0) {
+      *dest++ = *--src;
+    }
+  }
+public:
+  ByteOrder() {
+#ifndef PLATFORM_FLOAT_ENDIANESS
+    DoubleUnion u;
+    memset(u.b, 0, sizeof(u.b));
+    u.b[0] = (char) 0x80;
+    u.b[7] = (char) 0x02;
+    // TODO(jat): add more tests here if we support other endianess
+    floatByteOrder = u.v > 0 ? FLOAT_LITTLE_ENDIAN : FLOAT_BIG_ENDIAN;
+    if (Debug::level(Debug::Debugging)) {
+      std::string str = "Unknown";
+      switch (floatByteOrder) {
+         case FLOAT_LITTLE_ENDIAN:
+           str = "little-endian";
+           break;
+         case FLOAT_BIG_ENDIAN:
+           str = "big-endian";
+           break;
+      }
+      Debug::log(Debug::Debugging) << "Dynamically detected float byte order: "
+          << str << Debug::flush;
+    }
+#endif
+  }
+
+  void bytesFromDouble(double v, char* bytes) {
+    DoubleUnion u;
+    u.v = v;
+    switch (floatByteOrder) {
+      case FLOAT_LITTLE_ENDIAN:
+        memcpyrev(bytes, u.b, sizeof(u.b));
+        break;
+      case FLOAT_BIG_ENDIAN:
+        memcpy(bytes, u.b, sizeof(u.b));
+        break;
+    }
+  }
+
+  void bytesFromFloat(float v, char* bytes) {
+    FloatUnion u;
+    u.v = v;
+    switch (floatByteOrder) {
+      case FLOAT_LITTLE_ENDIAN:
+        memcpyrev(bytes, u.b, sizeof(u.b));
+        break;
+      case FLOAT_BIG_ENDIAN:
+        memcpy(bytes, u.b, sizeof(u.b));
+        break;
+    }
+  }
+
+  double doubleFromBytes(const char* bytes) {
+    DoubleUnion u;
+    switch (floatByteOrder) {
+      case FLOAT_LITTLE_ENDIAN:
+        memcpyrev(u.b, bytes, sizeof(u.b));
+        break;
+      case FLOAT_BIG_ENDIAN:
+        // TODO(jat): find a way to avoid the extra copy while keeping the
+        // compiler happy.
+        memcpy(u.b, bytes, sizeof(u.b));
+        break;
+    }
+    return u.v;
+  }
+
+  float floatFromBytes(const char* bytes) {
+    FloatUnion u;
+    switch (floatByteOrder) {
+      case FLOAT_LITTLE_ENDIAN:
+        memcpyrev(u.b, bytes, sizeof(u.b));
+        break;
+      case FLOAT_BIG_ENDIAN:
+        // TODO(jat): find a way to avoid the extra copy while keeping the
+        // compiler happy.
+        memcpy(u.b, bytes, sizeof(u.b));
+        break;
+    }
+    return u.v;
+  }
+};
+
+#endif
diff --git a/plugins/common/Debug.cpp b/plugins/common/Debug.cpp
new file mode 100644
index 0000000..66382bd
--- /dev/null
+++ b/plugins/common/Debug.cpp
@@ -0,0 +1,84 @@
+/*
+ * 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 <cstdio>
+
+#ifdef _WINDOWS
+#include <windows.h>
+#endif
+
+#include "Debug.h"
+
+#ifdef GWT_DEBUGDISABLE
+// Dummy implementations for when debugging has been disabled
+Debug::DebugStream& Debug::flush(Debug::DebugStream& dbg) {
+  return dbg;
+}
+
+void Debug::logFinish() {}
+
+void Debug::logString(const char* str) {}
+
+#else
+// Warning: this function is inlined in the manipulator output operator in DebugStream.
+// It only remains here because some compiler/linker combinations such as MSVC will
+// give unresolved symbol errors if it isn't -- GCC, for example, will completely remove
+// all traces of this method.
+Debug::DebugStream& Debug::flush(Debug::DebugStream& dbg) {
+  Debug::logFinish();
+  return dbg;
+}
+
+// These methods are implemented in an Objective-C++ file on OSX
+#if !defined(__APPLE_CC__) || defined(__mac)
+
+#ifdef _WINDOWS
+#define DEBUG_BUF_SIZE 2048
+
+static char buf[DEBUG_BUF_SIZE + 3]; // room for CR NL Null
+static char *bufPtr = buf;
+#endif
+
+void Debug::logFinish() {
+#ifdef _WINDOWS
+  logString("\r\n");
+  ::OutputDebugStringA(buf);
+  bufPtr = buf;
+#else
+  putchar('\n');
+#endif
+}
+
+// logStart may be called multiple times per logFinish
+void Debug::logStart(LogLevel level) {
+}
+
+void Debug::logString(const char* str) {
+#ifdef _WINDOWS
+  size_t len = strlen(str);
+  size_t buflen = DEBUG_BUF_SIZE - (bufPtr - buf);
+  if (len >= buflen) {
+    len = buflen - 1;
+  }
+  strncpy_s(bufPtr, buflen, str, len);
+  bufPtr += len;
+#else
+  printf("%s", str);
+#endif
+}
+#endif
+#endif
+
diff --git a/plugins/common/Debug.h b/plugins/common/Debug.h
new file mode 100644
index 0000000..c44e824
--- /dev/null
+++ b/plugins/common/Debug.h
@@ -0,0 +1,214 @@
+#ifndef _H_Debug
+#define _H_Debug
+/*
+ * 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.
+ */
+#ifndef _WINDOWS
+// TODO(jat): remove, for snprintf prototypes which should go away
+#include <stdio.h>
+#endif
+
+#include <ostream>
+#include <string>
+
+#include "Platform.h"
+
+// Get a default debug config if none supplied.
+#ifndef GWT_DEBUGLEVEL
+#include "DebugLevel.h"
+#endif
+
+/**
+ * Debugging class to get debugging output to a platform-specific location, with multiple
+ * levels supported.
+ * 
+ * To use:
+ *   #define GWT_DEBUGLEVEL level  // where level is in LogLevel
+ *   #include "Debug.h"
+ *   Debug::log(Debug::Warning) << ...
+ * 
+ * Zero overhead if GWT_DEBUGDISABLE is defined, other than the effort spent on side
+ * effects for stream object construction.  If that is expensive, use something like
+ * Debug::level(Debug::Warning) to conditionalize expensive logging computations.
+ */
+class Debug {
+public:
+  enum LogLevel {
+    None,
+    Error,
+    Warning,
+    Info,
+    Debugging,
+    Spam
+  };
+
+private:
+  static const LogLevel minLogLevel = GWT_DEBUGLEVEL;
+
+public:
+  /**
+   * Return true if the requested level would be logged.  Use to protect
+   * expensive computations for logging.
+   */
+  static bool level(LogLevel testLevel) {
+#ifdef GWT_DEBUGDISABLE
+    return false;
+#else
+    return testLevel <= minLogLevel;
+#endif
+  }
+
+private:
+  // complete the current log message
+  static void logFinish();
+  
+  // begin a new log message
+  static void logStart(LogLevel level);
+  
+  // add a string to the current log message
+  static void logString(const char* str);
+  static void logString(const std::string& str) {
+    logString(str.c_str());
+  }
+  
+public:
+  // Note that flush is special-cased in the manipulator output operator,
+  // and its implementation is inlined there.  If its implementation is
+  // modified, the implementation of the manipulator output operator will
+  // need to be modified as well.
+  class DebugStream;
+  static DebugStream& flush(DebugStream& dbg);
+
+  class DebugStream {
+
+    const bool shouldLog;
+
+    // TODO(jat): better implementations of output operators
+  public:
+    DebugStream(LogLevel level) : shouldLog(Debug::level(level)) {
+      if (shouldLog) {
+        Debug::logStart(level);
+      }
+    }
+
+    bool isActive() const {
+      return shouldLog;
+    }
+
+    DebugStream& operator<<(long v) {
+      if (shouldLog) {
+        char buf[20];
+        snprintf(buf, sizeof(buf), "%ld", v);
+        Debug::logString(buf);
+      }
+      return *this;
+    }
+
+    DebugStream& operator<<(unsigned long v) {
+      if (shouldLog) {
+        char buf[20];
+        snprintf(buf, sizeof(buf), "%lu", v);
+        Debug::logString(buf);
+      }
+      return *this;
+    }
+
+    DebugStream& operator<<(long long v) {
+      if (shouldLog) {
+        char buf[40];
+        snprintf(buf, sizeof(buf), "%lld", v);
+        Debug::logString(buf);
+      }
+      return *this;
+    }
+
+    DebugStream& operator<<(unsigned long long v) {
+      if (shouldLog) {
+        char buf[40];
+        snprintf(buf, sizeof(buf), "%llu", v);
+        Debug::logString(buf);
+      }
+      return *this;
+    }
+
+    DebugStream& operator<<(int v) {
+      if (shouldLog) {
+        char buf[20];
+        snprintf(buf, sizeof(buf), "%d", v);
+        Debug::logString(buf);
+      }
+      return *this;
+    }
+
+    DebugStream& operator<<(unsigned int v) {
+      if (shouldLog) {
+        char buf[20];
+        snprintf(buf, sizeof(buf), "%u", v);
+        Debug::logString(buf);
+      }
+      return *this;
+    }
+
+    DebugStream& operator<<(double v) {
+      if (shouldLog) {
+        char buf[20];
+        snprintf(buf, sizeof(buf), "%g", v);
+        Debug::logString(buf);
+      }
+      return *this;
+    }
+
+    DebugStream& operator<<(const std::string& str) {
+      if (shouldLog) {
+        Debug::logString(str);
+      }
+      return *this;
+    }
+
+    DebugStream& operator<<(const char* str) {
+      if (shouldLog) {
+        Debug::logString(str);
+      }
+      return *this;
+    }
+
+    DebugStream& operator<<(const void* v) {
+      if (shouldLog) {
+        char buf[20];
+        snprintf(buf, sizeof(buf), "%p", v);
+        Debug::logString(buf);
+      }
+      return *this;
+    }
+
+    DebugStream& operator<<(DebugStream& (*manip)(DebugStream&)) {
+      if (shouldLog) {
+        // Special-case flush for efficiency.
+        if (manip == Debug::flush) {
+          Debug::logFinish();
+        } else {
+          return manip(*this);
+        }
+      }
+      return *this;
+    }
+  };
+
+  static DebugStream log(LogLevel testLevel) {
+    return DebugStream(testLevel);
+  }
+};
+
+#endif
diff --git a/plugins/common/DebugLevel.h b/plugins/common/DebugLevel.h
new file mode 100644
index 0000000..d172e99
--- /dev/null
+++ b/plugins/common/DebugLevel.h
@@ -0,0 +1,25 @@
+#ifndef _H_DebugLevel
+#define _H_DebugLevel
+/*
+ * 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.
+ */
+
+// 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_DEBUGDISABLE
+
+#endif
diff --git a/plugins/common/FreeValueMessage.cpp b/plugins/common/FreeValueMessage.cpp
new file mode 100644
index 0000000..b7f0bab
--- /dev/null
+++ b/plugins/common/FreeValueMessage.cpp
@@ -0,0 +1,47 @@
+/*
+ * 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 "FreeValueMessage.h"
+#include "HostChannel.h"
+#include "scoped_ptr/scoped_ptr.h"
+
+FreeValueMessage::~FreeValueMessage() {
+  delete[] ids;
+}
+
+FreeValueMessage* FreeValueMessage::receive(HostChannel& channel) {
+  int idCount;
+  if (!channel.readInt(idCount)) {
+    // TODO(jat): error handling
+    return 0;
+  }
+  // TODO: validate idCount
+  scoped_array<int> ids(new int[idCount]);
+
+  for (int i = 0; i < idCount; ++i) {
+    if (!channel.readInt(ids[i])) return 0;
+  }
+  return new FreeValueMessage(idCount, ids.release());
+}
+
+bool FreeValueMessage::send(HostChannel& channel, int idCount, const int* ids) {
+  if (!channel.sendByte(TYPE)) return false;
+  if (!channel.sendInt(idCount)) return false;
+  for (int i = 0; i < idCount; ++i) {
+    if (!channel.sendInt(ids[i])) return false;
+  }
+  return true;
+}
diff --git a/plugins/common/FreeValueMessage.h b/plugins/common/FreeValueMessage.h
new file mode 100644
index 0000000..a8b7a64
--- /dev/null
+++ b/plugins/common/FreeValueMessage.h
@@ -0,0 +1,51 @@
+#ifndef __H_FreeValueMessage
+#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
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+#include <string>
+#include "Message.h"
+#include "BrowserChannel.h"
+#include "HostChannel.h"
+
+class FreeValueMessage : public Message {
+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;
+  }
+
+  static FreeValueMessage* receive(HostChannel& channel);
+  static bool send(HostChannel& channel, int idCount, const int* ids);
+};
+#endif
diff --git a/plugins/common/HashMap.h b/plugins/common/HashMap.h
new file mode 100644
index 0000000..c76b220
--- /dev/null
+++ b/plugins/common/HashMap.h
@@ -0,0 +1,58 @@
+#ifndef _H_HashMap
+#define _H_HashMap
+/*
+ * 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.
+ */
+
+// Portability wrapper for hash maps, since they aren't part of the standard C++ library
+
+#ifdef __GNUC__
+#if 0
+// future support
+#include <unordered_map>
+#define hash_map unordered_map
+
+namespace HashFunctions = std;
+#else
+#include <ext/hash_map>
+using __gnu_cxx::hash_map;
+
+// TODO(jat): surely this exists somewhere already?
+// TODO(jat): portability issues
+namespace __gnu_cxx {
+  using std::size_t;
+
+  template<> struct hash<std::string> {
+    size_t operator()(const std::string& str) const {
+      return hash<const char*>()(str.c_str());
+    }
+  };
+};
+namespace HashFunctions = __gnu_cxx;
+#endif
+#elif sun
+// TODO(jat): find a hash_map implementation for Solaris
+#include <map>
+namespace HashFunctions = std;
+#define hash_map map
+using std::map;
+#else
+// Try something reasonably standard, which works in Windows
+#include <hash_map>
+using stdext::hash_map;
+namespace HashFunctions = stdext;
+#endif
+
+#endif
diff --git a/plugins/common/HostChannel.cpp b/plugins/common/HostChannel.cpp
new file mode 100644
index 0000000..896667e
--- /dev/null
+++ b/plugins/common/HostChannel.cpp
@@ -0,0 +1,393 @@
+/*
+ * 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 <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <cerrno>
+
+#include "Debug.h"
+
+#ifdef _WINDOWS
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#else
+#include <netdb.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include <sys/time.h>
+#endif
+#include <time.h>
+
+#include "Platform.h"
+#include "ByteOrder.h"
+
+#include "FreeValueMessage.h"
+#include "HostChannel.h"
+#include "LoadJsniMessage.h"
+#include "InvokeMessage.h"
+#include "InvokeSpecialMessage.h"
+#include "QuitMessage.h"
+#include "ReturnMessage.h"
+#include "Value.h"
+#include "scoped_ptr/scoped_ptr.h"
+
+using namespace std;
+
+ByteOrder HostChannel::byteOrder;
+
+bool HostChannel::connectToHost(const char* host, unsigned port) {
+  Debug::log(Debug::Info) << "Initiating GWT hosted mode connection to host "
+      << host << ", port " << port << Debug::flush;
+  if (!port) {
+    port = 9997;
+  }
+  if (!whitelist.isAllowed(host, port)) {
+    Debug::log(Debug::Error) << "Permission to connect to " << host << ":" << port
+        << " denied" << Debug::flush;
+    return false;
+  }
+  return sock.connect(host, port);
+}
+
+bool HostChannel::disconnectFromHost() {
+  Debug::log(Debug::Debugging) << "Disconnecting channel" << Debug::flush;
+  if (!isConnected()) {
+    Debug::log(Debug::Error) << "Disconnecting already disconnected channel" << Debug::flush;
+    return false;
+  }
+  QuitMessage::send(*this);
+  flush();
+  sock.disconnect();
+  return true;
+}
+
+bool HostChannel::readInt(int32_t& data) {
+  int32_t d;
+  if (!readBytes(&d, sizeof(d))) return false;
+  data = ntohl(d);
+  return true;
+}
+
+bool HostChannel::sendInt(int32_t data) {
+  uint32_t d = htonl(data);
+  return sendBytes(&d, sizeof(d));
+}
+
+bool HostChannel::readShort(short& data) {
+  int16_t d;
+  if (!readBytes(&d, sizeof(d))) return false;
+  data = ntohs(d);
+  return true;
+}
+
+bool HostChannel::sendShort(const short data) {
+  uint16_t d = htons(data);
+  return sendBytes(&d, sizeof(d));
+}
+
+bool HostChannel::readLong(int64_t& data) {
+  // network is big-endian
+  int32_t d[2];
+  if (!readInt(d[0])) return false;
+  if (!readInt(d[1])) return false;
+  data = (static_cast<int64_t>(d[0]) << 32) | ntohl(d[1]);
+  return true;
+}
+
+bool HostChannel::sendLong(const int64_t data) {
+  if (!sendInt(static_cast<int32_t>(data >> 32))) {
+    return false;
+  }
+  return sendInt(static_cast<int32_t>(data));
+}
+
+bool HostChannel::readFloat(float& data) {
+  char bytes[sizeof(data)];
+  if (!readBytes(bytes, sizeof(bytes))) {
+    return false;
+  }
+  data = byteOrder.floatFromBytes(bytes);
+  return true;
+}
+
+bool HostChannel::sendFloat(const float data) {
+  char bytes[sizeof(data)];
+  byteOrder.bytesFromFloat(data, bytes);
+  return sendBytes(bytes, sizeof(bytes));
+}
+
+bool HostChannel::readDouble(double& data) {
+  char bytes[sizeof(data)];
+  if (!readBytes(bytes, sizeof(bytes))) {
+    return false;
+  }
+  data = byteOrder.doubleFromBytes(bytes);
+  return true;
+}
+
+bool HostChannel::sendDouble(const double data) {
+  char bytes[sizeof(data)];
+  byteOrder.bytesFromDouble(data, bytes);
+  return sendBytes(bytes, sizeof(bytes));
+}
+
+bool HostChannel::readStringLength(uint32_t& data) {
+  int32_t val;
+  if (!readInt(val)) return false;
+  // TODO: assert positive?
+  data = val;
+  return true;
+}
+
+bool HostChannel::readStringBytes(char* data, const uint32_t len) {
+  return readBytes(data, len);
+}
+
+bool HostChannel::readString(std::string& strRef) {
+  uint32_t len;
+  if (!readStringLength(len)) {
+    Debug::log(Debug::Error) << "readString: failed to read length"
+        << Debug::flush;
+    return false;
+  }
+  // Allocating variable-length arrays on the stack is a GCC feature,
+  // and is vulnerable to stack overflow attacks, so we allocate on the heap.
+  scoped_array<char> buf(new char[len]);
+  if (!readStringBytes(buf.get(), len)) {
+    Debug::log(Debug::Error) << "readString: failed to read " << len
+        << " bytes" << Debug::flush;
+    return false;
+  }
+  strRef.assign(buf.get(), len);
+  return true;
+}
+
+static inline double operator-(const struct timeval& end,
+    const struct timeval& begin) {
+  double us = end.tv_sec * 1000000.0 + end.tv_usec - begin.tv_sec * 1000000.0
+      - begin.tv_usec;
+  return us;
+}
+
+ReturnMessage* HostChannel::reactToMessages(SessionHandler* handler, bool expectReturn) {
+  char type;
+  while (true) {
+    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;
+      return 0;
+    }
+    switch (type) {
+      case MESSAGE_TYPE_INVOKE:
+        {
+          scoped_ptr<InvokeMessage> imsg(InvokeMessage::receive(*this));
+          if (!imsg.get()) {
+            Debug::log(Debug::Error) << "Failed to receive invoke message" << Debug::flush;
+            return 0;
+          }
+          Value returnValue;
+          bool exception = handler->invoke(*this, imsg->getThis(), imsg->getMethodName(),
+              imsg->getNumArgs(), imsg->getArgs(), &returnValue);
+          handler->sendFreeValues(*this);
+          ReturnMessage::send(*this, exception, returnValue);
+        }
+        break;
+      case MESSAGE_TYPE_INVOKESPECIAL:
+        {
+          // scottb: I think this is never used; I think server never sends invokeSpecial
+          scoped_ptr<InvokeSpecialMessage> imsg(InvokeSpecialMessage::receive(*this));
+          if (!imsg.get()) {
+            Debug::log(Debug::Error) << "Failed to receive invoke special message" << Debug::flush;
+            return 0;
+          }
+          Value returnValue;
+          bool exception = handler->invokeSpecial(*this, imsg->getDispatchId(),
+              imsg->getNumArgs(), imsg->getArgs(), &returnValue);
+          handler->sendFreeValues(*this);
+          ReturnMessage::send(*this, exception, returnValue);
+        }
+        break;
+      case MESSAGE_TYPE_FREEVALUE:
+        {
+          scoped_ptr<FreeValueMessage> freeMsg(FreeValueMessage::receive(*this));
+          if (!freeMsg.get()) {
+            Debug::log(Debug::Error) << "Failed to receive free value message" << Debug::flush;
+            return 0;
+          }
+          handler->freeValue(*this, freeMsg->getIdCount(), freeMsg->getIds());
+        }
+        // do not send a response
+        break;
+      case MESSAGE_TYPE_LOADJSNI:
+        {
+          scoped_ptr<LoadJsniMessage> loadMsg(LoadJsniMessage::receive(*this));
+          if (!loadMsg.get()) {
+            Debug::log(Debug::Error) << "Failed to receive load JSNI message" << Debug::flush;
+            return 0;
+          }
+          handler->loadJsni(*this, loadMsg->getJs());
+        }
+        // do not send a response
+        break;
+      case MESSAGE_TYPE_RETURN:
+        if (!expectReturn) {
+          Debug::log(Debug::Error) << "Received unexpected RETURN" << Debug::flush;
+        }
+        return ReturnMessage::receive(*this);
+      case MESSAGE_TYPE_QUIT:
+        if (expectReturn) {
+          Debug::log(Debug::Error) << "Received QUIT while waiting for return" << Debug::flush;
+        }
+    	  disconnectFromHost();
+        return 0;
+      default:
+        // TODO(jat): error handling
+        Debug::log(Debug::Error) << "Unexpected message type " << type
+            << ", expectReturn=" << expectReturn << Debug::flush;
+        disconnectFromHost();
+        return 0;
+    }
+  }
+}
+
+bool HostChannel::readValue(Value& valueRef) {
+  char typeBuf;
+  if (!readByte(typeBuf)) return false;
+  Value::ValueType type = Value::ValueType(typeBuf);
+  switch (type) {
+    case Value::NULL_TYPE:
+      valueRef.setNull();
+      return true;
+    case Value::UNDEFINED:
+      valueRef.setUndefined();
+      return true;
+    case Value::BOOLEAN:
+      {
+        char val;
+        if (!readByte(val)) return false;
+        valueRef.setBoolean(val != 0);
+      }
+      return true;
+    case Value::BYTE:
+      {
+        char val;
+        if (!readByte(val)) return false;
+        valueRef.setByte(val);
+      }
+      return true;
+    case Value::CHAR:
+      {
+        short val;
+        if (!readShort(val)) return false;
+        valueRef.setChar(val);
+      }
+      return true;
+    case Value::SHORT:
+      {
+        short val;
+        if (!readShort(val)) return false;
+        valueRef.setShort(val);
+      }
+      return true;
+    case Value::STRING:
+      {
+        std::string val;
+        if (!readString(val)) return false;
+        valueRef.setString(val);
+      }
+      return true;
+    case Value::INT:
+      {
+        int val;
+        if (!readInt(val)) return false;
+        valueRef.setInt(val);
+      }
+      return true;
+    case Value::LONG:
+      {
+        int64_t val;
+        if (!readLong(val)) return false;
+        valueRef.setLong(val);
+      }
+      return true;
+    case Value::DOUBLE:
+      {
+        double val;
+        if (!readDouble(val)) return false;
+        valueRef.setDouble(val);
+      }
+      return true;
+    case Value::JAVA_OBJECT:
+      {
+        int objId;
+        if (!readInt(objId)) return false;
+        valueRef.setJavaObject(objId);
+      }
+      return true;
+    case Value::JS_OBJECT:
+      {
+        int val;
+        if (!readInt(val)) return false;
+        valueRef.setJsObjectId(val);
+      }
+      return true;
+    default:
+      Debug::log(Debug::Error) << "Unhandled value type sent from server: " << type << Debug::flush;
+      break;
+  }
+  return false;
+}
+
+bool HostChannel::sendValue(const Value& value) {
+  Value::ValueType type = value.getType();
+  if (!sendByte(type)) return false;
+  switch (type) {
+    case Value::NULL_TYPE:
+    case Value::UNDEFINED:
+      // Null and Undefined only have the tag byte, no data
+      return true;
+    case Value::BOOLEAN:
+      return sendByte(value.getBoolean() ? 1 : 0);
+    case Value::BYTE:
+      return sendByte(value.getByte());
+    case Value::CHAR:
+      return sendShort(short(value.getChar()));
+    case Value::SHORT:
+      return sendShort(value.getShort());
+    case Value::INT:
+      return sendInt(value.getInt());
+    case Value::LONG:
+      return sendLong(value.getLong());
+    case Value::STRING:
+      return sendString(value.getString());
+    case Value::DOUBLE:
+      return sendDouble(value.getDouble());
+    case Value::FLOAT:
+      return sendFloat(value.getFloat());
+    case Value::JS_OBJECT:
+      return sendInt(value.getJsObjectId());
+    case Value::JAVA_OBJECT:
+      return sendInt(value.getJavaObjectId());
+    default:
+      Debug::log(Debug::Error) << "Unhandled value type sent to server: " << type << Debug::flush;
+      break;
+  }
+  return false;
+}
diff --git a/plugins/common/HostChannel.h b/plugins/common/HostChannel.h
new file mode 100644
index 0000000..0097b6d
--- /dev/null
+++ b/plugins/common/HostChannel.h
@@ -0,0 +1,139 @@
+#ifndef __H_HostChannel
+#define __H_HostChannel
+/*
+ * 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 "Debug.h"
+
+// Sun's cstdio doesn't define a bunch of stuff
+#include <stdio.h>
+#include <string>
+
+#include "ByteOrder.h"
+#include "Socket.h"
+#include "AllowedConnections.h"
+#include "Platform.h"
+#include "Message.h"
+#include "ReturnMessage.h"
+#include "Value.h"
+#include "SessionHandler.h"
+
+class HostChannel {
+  Socket sock;
+  AllowedConnections whitelist;
+  static ByteOrder byteOrder;
+
+public:
+  ~HostChannel() {
+    if (isConnected()) {
+      disconnectFromHost();
+    }
+    Debug::log(Debug::Debugging) << "HostChannel destroyed" << Debug::flush;
+  }
+
+  bool connectToHost(const char* host, unsigned port);
+  bool disconnectFromHost();
+  
+  bool isConnected() const {
+    return sock.isConnected();
+  }
+
+  bool readBytes(void* data, size_t dataLen) {
+    char* ptr = static_cast<char*>(data);
+    while(dataLen > 0) {
+      if (!readByte(*ptr++)) {
+        return false;
+      }
+      --dataLen;
+    }
+    return true;
+  }
+
+  bool sendBytes(const void* data, size_t dataLen) {
+    const char* ptr = static_cast<const char*>(data);
+    while(dataLen > 0) {
+      if (!sendByte(*ptr++)) {
+        return false;
+      }
+      --dataLen;
+    }
+    return true;
+  }
+
+  // TODO: don't pass out-params by reference as it makes the call site misleading
+  bool readInt(int32_t& data);
+  bool sendInt(const int32_t data);
+
+  bool readShort(short& data);
+  bool sendShort(const short data);
+
+  bool readLong(int64_t& data);
+  bool sendLong(const int64_t data);
+
+  bool readFloat(float& data);
+  bool sendFloat(const float data);
+
+  bool readDouble(double& doubleRef);
+  bool sendDouble(const double data);
+
+  bool readByte(char& data) {
+    if (!isConnected()) {
+      return false;
+    }
+    int c = sock.readByte();
+    if (c < 0) {
+      return false;
+    }
+    data = static_cast<char>(c);
+    return true;
+  }
+
+  bool sendByte(const char data) {
+    if (!isConnected()) {
+      return false;
+    }
+    return sock.writeByte(data);
+  }
+
+  bool readStringLength(uint32_t& data);
+  bool readStringBytes(char* data, const uint32_t len);
+  bool readString(std::string& strRef);
+  bool sendString(const char* data, const uint32_t len) {
+    return sendInt(len) && sendBytes(data, len);
+  }
+
+  bool sendString(const std::string& str) {
+    return sendString(str.c_str(), static_cast<uint32_t>(str.length()));
+  }
+
+  bool readValue(Value& valueRef);
+  bool sendValue(const Value& value);
+
+  ReturnMessage* reactToMessages(SessionHandler* handler, bool expectReturn);
+
+  bool reactToMessages(SessionHandler* handler) {
+    return !reactToMessages(handler, false);
+  }
+
+  bool flush() {
+    return sock.flush();
+  }
+
+  ReturnMessage* reactToMessagesWhileWaitingForReturn(SessionHandler* handler) {
+    return reactToMessages(handler, true);
+  }
+};
+#endif
diff --git a/plugins/common/InvokeMessage.cpp b/plugins/common/InvokeMessage.cpp
new file mode 100644
index 0000000..90fc790
--- /dev/null
+++ b/plugins/common/InvokeMessage.cpp
@@ -0,0 +1,79 @@
+/*
+ * 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 "InvokeMessage.h"
+#include "HostChannel.h"
+#include "scoped_ptr/scoped_ptr.h"
+
+InvokeMessage::~InvokeMessage() {
+  delete[] args;
+}
+
+char InvokeMessage::getType() const {
+  return TYPE;
+}
+
+/**
+ * Receive an Invoke message from the channel (note that the message
+ * type has already been read).  Caller is responsible for destroying
+ * returned message.  Returns null on error.
+ */
+InvokeMessage* InvokeMessage::receive(HostChannel& channel) {
+  std::string methodName;
+  if (!channel.readString(methodName)) {
+    // TODO(jat): error handling
+    printf("Failed to read method name\n");
+    return 0;
+  }
+  Value thisRef;
+  if (!channel.readValue(thisRef)) {
+    // TODO(jat): error handling
+    printf("Failed to read thisRef\n");
+    return 0;
+  }
+  int numArgs;
+  if (!channel.readInt(numArgs)) {
+    // TODO(jat): error handling
+    printf("Failed to read #args\n");
+    return 0;
+  }
+  scoped_array<Value> args(new Value[numArgs]);
+  for (int i = 0; i < numArgs; ++i) {
+    if (!channel.readValue(args[i])) {
+      // TODO(jat): error handling
+      printf("Failed to read arg[%d]\n", i);
+      return 0;
+    }
+  }
+  return new InvokeMessage(thisRef, methodName, numArgs, args.release());
+}
+
+/**
+ * Request the server invoke a method on an object and return the result.
+ * 
+ * Note that the method to be invoked is sent as an integer (a dispatch id) to the server.
+ */
+bool InvokeMessage::send(HostChannel& channel, const Value& thisRef, int methodDispatchId,
+    int numArgs, const Value* args) {
+  if (!channel.sendByte(TYPE)) return false;
+  if (!channel.sendInt(methodDispatchId)) return false;
+  if (!channel.sendValue(thisRef)) return false;
+  if (!channel.sendInt(numArgs)) return false;
+  for (int i = 0; i < numArgs; ++i) {
+    if (!channel.sendValue(args[i])) return false;
+  }
+  return true;
+}
diff --git a/plugins/common/InvokeMessage.h b/plugins/common/InvokeMessage.h
new file mode 100644
index 0000000..7d57e30
--- /dev/null
+++ b/plugins/common/InvokeMessage.h
@@ -0,0 +1,67 @@
+#ifndef __INVOKEMESSAGE_H
+#define __INVOKEMESSAGE_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
+ * 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 InvokeMessage received from the server, and a way
+ * to send an invoke message to the server.
+ *
+ * Note that the wire protocol is different in the two directions, as the
+ * server sends a string for the method name and the client send an integer
+ * dispatchID.
+ */
+class InvokeMessage : public Message {
+public:
+  static const char TYPE = MESSAGE_TYPE_INVOKE;
+  static const int TOSTRING_DISP_ID = 0;
+private:
+  Value thisRef;
+  std::string methodName;
+  int methodDispatchId;
+  int numArgs;
+  const Value* args;
+
+protected:
+  /**
+   * @param args array of arguments -- InvokeMessage takes ownership and will
+   *     destroy when it is destroyed.
+   */
+  InvokeMessage(const Value& thisRef, const std::string& methodName,
+      int numArgs, const Value* args) : thisRef(thisRef), methodName(methodName),
+      numArgs(numArgs), args(args) {}
+
+public:
+  ~InvokeMessage();
+  virtual char getType() const;
+
+  Value getThis() const { return thisRef; }
+  const std::string& getMethodName() const { return methodName; }
+  int getNumArgs() const { return numArgs; }
+  const Value* const getArgs() const { return args; }
+
+  static InvokeMessage* receive(HostChannel& channel);
+  static bool send(HostChannel& channel, const Value& thisRef, int methodDispatchId,
+      int numArgs, const Value* args);
+};
+#endif
diff --git a/plugins/common/InvokeSpecialMessage.cpp b/plugins/common/InvokeSpecialMessage.cpp
new file mode 100644
index 0000000..5fd1540
--- /dev/null
+++ b/plugins/common/InvokeSpecialMessage.cpp
@@ -0,0 +1,74 @@
+/*
+ * 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 "InvokeSpecialMessage.h"
+#include "HostChannel.h"
+#include "SessionHandler.h"
+#include "scoped_ptr/scoped_ptr.h"
+
+InvokeSpecialMessage::~InvokeSpecialMessage() {
+  delete[] args;
+}
+
+char InvokeSpecialMessage::getType() const {
+  return TYPE;
+}
+
+/**
+ * Receive an InvokeSpecial message from the channel (note that the message
+ * type has already been read).  Caller is responsible for destroying
+ * returned message.  Returns null on error.
+ */
+InvokeSpecialMessage* InvokeSpecialMessage::receive(HostChannel& channel) {
+  char dispatchId;
+  if (!channel.readByte(dispatchId)) {
+    // TODO(jat): error handling
+    printf("Failed to read method name\n");
+    return 0;
+  }
+  int numArgs;
+  if (!channel.readInt(numArgs)) {
+    // TODO(jat): error handling
+    printf("Failed to read #args\n");
+    return 0;
+  }
+  scoped_array<Value> args(new Value[numArgs]);
+  for (int i = 0; i < numArgs; ++i) {
+    if (!channel.readValue(args[i])) {
+      // TODO(jat): error handling
+      printf("Failed to read arg[%d]\n", i);
+      return 0;
+    }
+  }
+  
+  SessionHandler::SpecialMethodId id =
+    static_cast<SessionHandler::SpecialMethodId>(dispatchId);
+  return new InvokeSpecialMessage(id, numArgs, args.release());
+}
+
+/**
+ * Request the server perform a special method and return the result.
+ */
+bool InvokeSpecialMessage::send(HostChannel& channel, int dispatchId,
+    int numArgs, const Value* args) {
+  if (!channel.sendByte(TYPE)) return false;
+  if (!channel.sendByte(dispatchId)) return false;
+  if (!channel.sendInt(numArgs)) return false;
+  for (int i = 0; i < numArgs; ++i) {
+    if (!channel.sendValue(args[i])) return false;
+  }
+  return true;
+}
diff --git a/plugins/common/InvokeSpecialMessage.h b/plugins/common/InvokeSpecialMessage.h
new file mode 100644
index 0000000..196baa5
--- /dev/null
+++ b/plugins/common/InvokeSpecialMessage.h
@@ -0,0 +1,59 @@
+#ifndef __INVOKESPECIALMESSAGE_H
+#define __INVOKESPECIALMESSAGE_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
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+#include <string>
+#include "Message.h"
+#include "BrowserChannel.h"
+#include "SessionHandler.h"
+#include "Value.h"
+
+class HostChannel;
+
+/**
+ * Class representing an InvokeSpecialMessage received from the server, and a way
+ * to send an invoke message to the server.
+ */
+class InvokeSpecialMessage : public Message {
+public:
+  static const char TYPE = MESSAGE_TYPE_INVOKESPECIAL;
+private:
+  SessionHandler::SpecialMethodId dispatchId;
+  int numArgs;
+  const Value* args;
+
+protected:
+  /**
+   * @param args array of arguments -- InvokeMessage takes ownership and will
+   *     destroy when it is destroyed.
+   */
+  InvokeSpecialMessage(SessionHandler::SpecialMethodId dispatchId, int numArgs, const Value* args) : dispatchId(dispatchId),
+      numArgs(numArgs), args(args) {}
+
+public:
+  ~InvokeSpecialMessage();
+  virtual char getType() const;
+
+  SessionHandler::SpecialMethodId getDispatchId() const { return dispatchId; }
+  int getNumArgs() const { return numArgs; }
+  const Value* const getArgs() const { return args; }
+
+  static InvokeSpecialMessage* receive(HostChannel& channel);
+  static bool send(HostChannel& channel, int dispatchId, int numArgs,
+      const Value* args);
+};
+#endif
diff --git a/plugins/common/LoadJsniMessage.cpp b/plugins/common/LoadJsniMessage.cpp
new file mode 100644
index 0000000..db8b943
--- /dev/null
+++ b/plugins/common/LoadJsniMessage.cpp
@@ -0,0 +1,26 @@
+/*
+ * 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 "LoadJsniMessage.h"
+
+LoadJsniMessage* LoadJsniMessage::receive(HostChannel& channel) {
+  std::string js;
+  if (!channel.readString(js)) {
+    // TODO(jat): error handling
+    return 0;
+  }
+  return new LoadJsniMessage(js);
+}
diff --git a/plugins/common/LoadJsniMessage.h b/plugins/common/LoadJsniMessage.h
new file mode 100644
index 0000000..5b1f8d9
--- /dev/null
+++ b/plugins/common/LoadJsniMessage.h
@@ -0,0 +1,43 @@
+#ifndef __H_LoadJsniMessage
+#define __H_LoadJsniMessage
+/*
+ * 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 <string>
+#include "Message.h"
+#include "BrowserChannel.h"
+#include "HostChannel.h"
+
+class LoadJsniMessage : public Message {
+public:  
+  static const char TYPE = MESSAGE_TYPE_LOADJSNI;
+private:
+  const std::string js;
+  
+  LoadJsniMessage(const std::string& js) : js(js) {}
+  
+public:  
+  virtual char getType() const {
+    return TYPE;
+  }
+  
+  std::string getJs() const {
+    return js;
+  }
+
+  static LoadJsniMessage* receive(HostChannel& channel);
+};
+#endif
diff --git a/plugins/common/LoadModuleMessage.cpp b/plugins/common/LoadModuleMessage.cpp
new file mode 100644
index 0000000..a436961
--- /dev/null
+++ b/plugins/common/LoadModuleMessage.cpp
@@ -0,0 +1,44 @@
+/*
+ * 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 "Debug.h"
+
+#include <cstring>
+#include <string>
+
+#include "LoadModuleMessage.h"
+#include "scoped_ptr/scoped_ptr.h"
+
+char LoadModuleMessage::getType() const {
+  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)))) {
+    return false;
+  }
+  scoped_ptr<ReturnMessage> ret(channel.reactToMessagesWhileWaitingForReturn(handler));
+  if (!ret.get()) {
+    return false;
+  }
+
+  return !ret.get()->isException();
+}
diff --git a/plugins/common/LoadModuleMessage.h b/plugins/common/LoadModuleMessage.h
new file mode 100644
index 0000000..3091c46
--- /dev/null
+++ b/plugins/common/LoadModuleMessage.h
@@ -0,0 +1,47 @@
+#ifndef __LOADMODULEMESSAGE_H
+#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
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+#include <string>
+
+#include "Message.h"
+#include "BrowserChannel.h"
+#include "HostChannel.h"
+#include "SessionHandler.h"
+
+class HostChannel;
+
+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) { }
+
+  int getVersion() const { return version; }
+  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);
+private:
+  int version;
+  std::string moduleName;
+  std::string userAgent;
+};
+#endif
diff --git a/plugins/common/Makefile b/plugins/common/Makefile
new file mode 100644
index 0000000..b22fd27
--- /dev/null
+++ b/plugins/common/Makefile
@@ -0,0 +1,93 @@
+# 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 ../config.mk
+
+HDRS= HostChannel.h InvokeMessage.h LoadModuleMessage.h Message.h \
+      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
+
+SRCS=	HostChannel.cpp LoadModuleMessage.cpp InvokeMessage.cpp \
+	ReturnMessage.cpp ServerMethods.cpp Debug.cpp Socket.cpp \
+	AllowedConnections.cpp LoadJsniMessage.cpp InvokeSpecialMessage.cpp \
+	FreeValueMessage.cpp
+
+LIBCOMMON= libcommon$(FLAG32BIT).a
+OBJDIR= obj$(FLAG32BIT)
+OBJS= $(patsubst %.cpp,$(OBJDIR)/%.o,$(SRCS))
+
+all:: $(OBJDIR) $(LIBCOMMON)
+
+$(OBJDIR):
+	-mkdir $@
+
+$(LIBCOMMON): $(OBJS)
+	$(AR) $(ARFLAGS) $@ $(OBJS)
+
+$(OBJDIR)/%.o: %.cpp
+	$(CXX) $(CXXFLAGS) -c $< -o $@
+
+.PHONY: clean depend testdebug
+
+testdebug:
+	(cd testing; CXX=$(CXX) CXXFLAGS="$(CFLAGS) -m32" ./testdebug)
+	(cd testing; CXX=$(CXX) CXXFLAGS="$(CFLAGS) -m64" ./testdebug)
+
+clean:
+	rm -rf obj32 obj64 libcommon32.a libcommon64.a
+
+depend:
+	g++ -MM $(CFLAGS) $(SRCS) >>Makefile
+#	makedepend -- $(CFLAGS) -- $(SRCS)
+
+# 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 \
+  scoped_ptr/scoped_ptr.h
+LoadModuleMessage.o: LoadModuleMessage.cpp Debug.h Platform.h \
+  DebugLevel.h LoadModuleMessage.h Message.h BrowserChannel.h \
+  HostChannel.h ByteOrder.h Socket.h AllowedConnections.h ReturnMessage.h \
+  Value.h SessionHandler.h scoped_ptr/scoped_ptr.h
+InvokeMessage.o: InvokeMessage.cpp InvokeMessage.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
+ReturnMessage.o: ReturnMessage.cpp ReturnMessage.h Message.h \
+  BrowserChannel.h Value.h Debug.h Platform.h DebugLevel.h HostChannel.h \
+  ByteOrder.h Socket.h AllowedConnections.h SessionHandler.h
+ServerMethods.o: ServerMethods.cpp Debug.h Platform.h DebugLevel.h \
+  FreeValueMessage.h Message.h BrowserChannel.h HostChannel.h ByteOrder.h \
+  Socket.h AllowedConnections.h ReturnMessage.h Value.h SessionHandler.h \
+  InvokeMessage.h InvokeSpecialMessage.h ServerMethods.h \
+  scoped_ptr/scoped_ptr.h
+Debug.o: Debug.cpp Debug.h Platform.h DebugLevel.h
+Socket.o: Socket.cpp Platform.h Socket.h Debug.h DebugLevel.h
+AllowedConnections.o: AllowedConnections.cpp Debug.h Platform.h \
+  DebugLevel.h AllowedConnections.h
+LoadJsniMessage.o: LoadJsniMessage.cpp LoadJsniMessage.h Message.h \
+  BrowserChannel.h HostChannel.h Debug.h Platform.h DebugLevel.h \
+  ByteOrder.h Socket.h AllowedConnections.h ReturnMessage.h Value.h \
+  SessionHandler.h
+InvokeSpecialMessage.o: InvokeSpecialMessage.cpp InvokeSpecialMessage.h \
+  Message.h BrowserChannel.h SessionHandler.h Value.h Debug.h Platform.h \
+  DebugLevel.h HostChannel.h ByteOrder.h Socket.h AllowedConnections.h \
+  ReturnMessage.h scoped_ptr/scoped_ptr.h
+FreeValueMessage.o: FreeValueMessage.cpp FreeValueMessage.h Message.h \
+  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
diff --git a/plugins/common/Makefile.sun b/plugins/common/Makefile.sun
new file mode 100644
index 0000000..2043187
--- /dev/null
+++ b/plugins/common/Makefile.sun
@@ -0,0 +1,115 @@
+# Set to classpath value to get GWT classes from
+#GWTDEV=../build/staging/gwt-linux-0.0.0/gwt-dev-linux.jar
+GWTDEV=../eclipse/dev/linux/bin
+
+INC=-I..
+#CFLAGS=-fast -g0 -Kpic $(INC) -Bdynamic -noex
+# SunC appears to miscompile Socket::writeByte by not incrementing the
+# buffer pointer, so no optimization for now
+#CFLAGS=-g -Kpic $(INC) -Bdynamic -noex
+CFLAGS=-g0 -Kpic -noex -xO1 -xlibmil -xlibmopt -features=tmplife -xbuiltin=%all -mt $(INC)
+CXXFLAGS=$(CFLAGS)
+CXX=CC
+
+HDRS= HostChannel.h InvokeMessage.h LoadModuleMessage.h Message.h \
+      ReturnMessage.h Value.h BrowserChannel.h Debug.h DebugLevel.h \
+      SessionHandler.h ServerMethods.h Socket.h AllowedConnections.h \
+      LoadJsniMessage.h InvokeSpecialMessage.h FreeValueMessage.h
+
+OBJS=	HostChannel.o LoadModuleMessage.o InvokeMessage.o \
+	ReturnMessage.o ServerMethods.o Debug.o Socket.o \
+	AllowedConnections.o LoadJsniMessage.o InvokeSpecialMessage.o \
+	FreeValueMessage.o
+
+SRCS=	HostChannel.cpp LoadModuleMessage.cpp InvokeMessage.cpp \
+	ReturnMessage.cpp ServerMethods.cpp Debug.cpp Socket.cpp \
+	AllowedConnections.cpp LoadJsniMessage.cpp InvokeSpecialMessage.cpp \
+	FreeValueMessage.cpp
+
+OBJ32= $(patsubst %.cpp,obj32/%.o,$(SRCS))
+OBJ64= $(patsubst %.cpp,obj64/%.o,$(SRCS))
+
+all:: libcommon32.a libcommon64.a
+
+libcommon32.a: $(OBJ32) obj32.dir
+	ar -rv $@ $(OBJ32)
+
+libcommon64.a: $(OBJ64) obj64.dir
+	ar -rv $@ $(OBJ64)
+
+obj32.dir:
+	-mkdir obj32
+	touch obj32.dir
+
+obj64.dir:
+	-mkdir obj64
+	touch obj64.dir
+
+obj32/%.o: %.cpp obj32.dir
+	$(CXX) $(CXXFLAGS) -m32 -c $< -o $@
+
+obj64/%.o: %.cpp obj64.dir
+	$(CXX) $(CXXFLAGS) -m64 -c $< -o $@
+
+.PHONY: all clean depend
+
+clean:
+	-rm $(OBJ32) $(OBJ64) libcommon32.a libcommon64.a
+
+depend:
+	$(CXX) -xMMF $(CFLAGS) $(SRCS) >>Makefile.sun
+#	makedepend -- $(CFLAGS) -- $(SRCS)
+
+# DO NOT DELETE
+obj32/HostChannel.o obj64/HostChannel.o: Makefile.sun \
+  HostChannel.cpp HostChannel.h Platform.h Message.h \
+  ReturnMessage.h BrowserChannel.h Value.h SessionHandler.h \
+  InvokeMessage.h QuitMessage.h scoped_ptr/scoped_ptr.h
+obj32/LoadModuleMessage.o obj64/LoadModuleMessage.o: Makefile.sun \
+  LoadModuleMessage.cpp LoadModuleMessage.h Message.h \
+  BrowserChannel.h HostChannel.h Platform.h ReturnMessage.h Value.h \
+  SessionHandler.h scoped_ptr/scoped_ptr.h
+obj32/InvokeMessage.o obj64/InvokeMessage.o: Makefile.sun \
+  InvokeMessage.cpp InvokeMessage.h Message.h \
+  BrowserChannel.h Value.h HostChannel.h Platform.h ReturnMessage.h \
+  SessionHandler.h
+obj32/ReturnMessage.o obj64/ReturnMessage.o: Makefile.sun \
+  ReturnMessage.cpp ReturnMessage.h Message.h \
+  BrowserChannel.h Value.h HostChannel.h Platform.h SessionHandler.h
+obj32/ServerMethods.o obj64/ServerMethods.o: Makefile.sun \
+  ServerMethods.cpp ServerMethods.h Value.h \
+  BrowserChannel.h HostChannel.h Platform.h Message.h ReturnMessage.h \
+  SessionHandler.h InvokeMessage.h scoped_ptr/scoped_ptr.h
+obj32/HostChannel.o obj64/HostChannel.o: Makefile.sun \
+  HostChannel.cpp HostChannel.h Platform.h Message.h \
+  ReturnMessage.h BrowserChannel.h Value.h SessionHandler.h \
+  InvokeMessage.h QuitMessage.h scoped_ptr/scoped_ptr.h
+obj32/LoadModuleMessage.o obj64/LoadModuleMessage.o: Makefile.sun \
+  LoadModuleMessage.cpp LoadModuleMessage.h Message.h \
+  BrowserChannel.h HostChannel.h Platform.h ReturnMessage.h Value.h \
+  SessionHandler.h scoped_ptr/scoped_ptr.h
+obj32/InvokeMessage.o obj64/InvokeMessage.o: Makefile.sun \
+  InvokeMessage.cpp InvokeMessage.h Message.h \
+  BrowserChannel.h Value.h HostChannel.h Platform.h ReturnMessage.h \
+  SessionHandler.h
+obj32/InvokeSpecialMessage.o obj64/InvokeSpecialMessage.o: Makefile.sun \
+  InvokeSpecialMessage.cpp InvokeSpecialMessage.h Message.h \
+  BrowserChannel.h Value.h HostChannel.h Platform.h ReturnMessage.h \
+  SessionHandler.h
+obj32/FreeValueMesssage.o obj64/FreeValueMesssage.o: Makefile.sun \
+  FreeValueMesssage.cpp FreeValueMesssage.h Message.h \
+  BrowserChannel.h Value.h HostChannel.h Platform.h ReturnMessage.h \
+  SessionHandler.h
+obj32/ReturnMessage.o obj64/ReturnMessage.o: Makefile.sun \
+  ReturnMessage.cpp ReturnMessage.h Message.h \
+  BrowserChannel.h Value.h HostChannel.h Platform.h SessionHandler.h
+obj32/ServerMethods.o obj64/ServerMethods.o: Makefile.sun \
+  ServerMethods.cpp ServerMethods.h Value.h \
+  BrowserChannel.h HostChannel.h Platform.h Message.h ReturnMessage.h \
+  SessionHandler.h InvokeMessage.h scoped_ptr/scoped_ptr.h
+obj32/Debug.o obj64/Debug.o: Makefile.sun \
+  Debug.cpp Debug.h DebugLevel.h
+obj32/Socket.o obj64/Socket.o: Makefile.sun \
+  Socket.cpp Socket.h Debug.h DebugLevel.h
+obj32/AllowedConnections.o obj64/AllowedConnections.o: Makefile.sun \
+  AllowedConnections.cpp AllowedConnections.h Debug.h DebugLevel.h
diff --git a/plugins/common/Message.h b/plugins/common/Message.h
new file mode 100644
index 0000000..a244e0b
--- /dev/null
+++ b/plugins/common/Message.h
@@ -0,0 +1,28 @@
+#ifndef __MESSAGE_H
+#define __MESSAGE_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
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+class Message {
+public:
+  virtual char getType() const = 0;
+  virtual bool isAsynchronous() const {
+    return false;
+  }
+  virtual ~Message() {}
+};
+
+#endif
diff --git a/plugins/common/Platform.h b/plugins/common/Platform.h
new file mode 100644
index 0000000..bbc0334
--- /dev/null
+++ b/plugins/common/Platform.h
@@ -0,0 +1,46 @@
+#ifndef _H_Platform
+#define _H_Platform
+/*
+ * 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.
+ */
+
+// Platform-specific hacks to enable more shared code elsewhere
+#ifdef _WINDOWS
+typedef __int32 int32_t;
+typedef unsigned __int32 uint32_t; 
+typedef __int16 int16_t;
+typedef unsigned __int16 uint16_t;
+typedef __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+typedef long ssize_t;
+
+#define snprintf sprintf_s
+#define SOCKETTYPE SOCKET
+// Bogus conversion from size_t -> unsigned int warnings.
+#pragma warning(disable:4267)
+#else
+#define SOCKETTYPE int
+#endif
+
+// Set the float byte-order if we know it -- see ByteOrder.h FloatByteOrder
+#if defined(i386) || defined(i586) || defined(i686) || defined(_x86)
+#define PLATFORM_FLOAT_ENDIANESS FLOAT_LITTLE_ENDIAN
+#endif
+
+#if defined(__sparc)
+#define PLATFORM_FLOAT_ENDIANESS FLOAT_BIG_ENDIAN
+#endif
+
+#endif
diff --git a/plugins/common/QuitMessage.h b/plugins/common/QuitMessage.h
new file mode 100644
index 0000000..344612f
--- /dev/null
+++ b/plugins/common/QuitMessage.h
@@ -0,0 +1,38 @@
+#ifndef __H_QuitMessage
+#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
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+#include <string>
+#include "Message.h"
+#include "BrowserChannel.h"
+
+class QuitMessage : public Message {
+public:  
+  static const char TYPE = MESSAGE_TYPE_QUIT;
+private:
+  QuitMessage() {}
+  
+public:  
+  virtual char getType() const {
+    return TYPE;
+  }
+  
+  static bool send(HostChannel& channel) {
+    return channel.sendByte(TYPE);
+  }
+};
+#endif
diff --git a/plugins/common/ReturnMessage.cpp b/plugins/common/ReturnMessage.cpp
new file mode 100644
index 0000000..0149c1f
--- /dev/null
+++ b/plugins/common/ReturnMessage.cpp
@@ -0,0 +1,42 @@
+/*
+ * 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 "ReturnMessage.h"
+#include "HostChannel.h"
+
+char ReturnMessage::getType() const {
+  return TYPE;
+}
+  
+ReturnMessage* ReturnMessage::receive(HostChannel& channel) {
+  char isException;
+  if (!channel.readByte(isException)) {
+    // TODO(jat): error handling
+    return 0;
+  }
+  Value retval;
+  if (!channel.readValue(retval)) {
+    // TODO(jat): error handling
+    return 0;
+  }
+  return new ReturnMessage(isException != 0, retval);
+}
+
+bool ReturnMessage::send(HostChannel& channel, bool isException, const Value& retval) {
+  if (!channel.sendByte(TYPE)) return false;
+  if (!channel.sendByte(isException ? 1 : 0)) return false;
+  return channel.sendValue(retval);
+}
diff --git a/plugins/common/ReturnMessage.h b/plugins/common/ReturnMessage.h
new file mode 100644
index 0000000..fddf9ec
--- /dev/null
+++ b/plugins/common/ReturnMessage.h
@@ -0,0 +1,43 @@
+#ifndef __RETURNMESSAGE_H
+#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
+ * 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 ReturnMessage : public Message {
+  static const char TYPE = MESSAGE_TYPE_RETURN;
+private:
+  bool bisException;
+  Value retval;
+  
+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);
+};
+#endif
diff --git a/plugins/common/ServerMethods.cpp b/plugins/common/ServerMethods.cpp
new file mode 100644
index 0000000..5a18bcb
--- /dev/null
+++ b/plugins/common/ServerMethods.cpp
@@ -0,0 +1,129 @@
+/*
+ * 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 <string>
+
+#include "Debug.h"
+#include "FreeValueMessage.h"
+#include "HostChannel.h"
+#include "InvokeMessage.h"
+#include "InvokeSpecialMessage.h"
+#include "ReturnMessage.h"
+#include "ServerMethods.h"
+#include "scoped_ptr/scoped_ptr.h"
+
+using std::string;
+
+Value ServerMethods::getProperty(HostChannel& channel, SessionHandler* handler, int objectRef,
+    int dispatchId) {
+  Value args[2];
+  args[0].setInt(objectRef);
+  args[1].setInt(dispatchId);
+  if (!InvokeSpecialMessage::send(channel, SPECIAL_GET_PROPERTY, 2, args)) {
+    Debug::log(Debug::Error) << "  failed to send invoke of GetProperty(disp=" << dispatchId
+        << ", obj=" << objectRef << ")" << Debug::flush;
+    return Value();
+  }
+  scoped_ptr<ReturnMessage> retMsg(channel.reactToMessagesWhileWaitingForReturn(handler));
+  if (!retMsg.get()) {
+    Debug::log(Debug::Error) << "getProperty: get return value failed for GetProperty(disp="
+        << dispatchId << ", obj=" << objectRef << ")" << Debug::flush;
+    return Value();
+  }
+  return retMsg->getReturnValue();
+}
+
+int ServerMethods::hasMethod(HostChannel& channel, SessionHandler* handler, int classId,
+    const std::string& name) {
+  if (name != "toString" && name.find("::") == string::npos) {
+    // only JSNI-style names and toString are valid
+    return -1;
+  }
+  Value arg;
+  arg.setString(name);
+  if (!InvokeSpecialMessage::send(channel, SPECIAL_HAS_METHOD, 1, &arg)) {
+    Debug::log(Debug::Error) << "hasMethod: invoke(hasMethod) failed" << Debug::flush;
+    return -2;
+  }
+  scoped_ptr<ReturnMessage> retMsg(channel.reactToMessagesWhileWaitingForReturn(handler));
+  if (!retMsg.get()) {
+    Debug::log(Debug::Error) << "hasMethod: get return value failed" << Debug::flush;
+    return -2;
+  }
+  Value retval = retMsg->getReturnValue();
+  // TODO(jat): better error handling?
+  return retval.isInt() ? retval.getInt() : -2;
+}
+
+int ServerMethods::hasProperty(HostChannel& channel, SessionHandler* handler, int classId,
+    const std::string& name) {
+  if (name != "toString" && name.find("::") == string::npos) {
+    // only JSNI-style names and toString are valid
+    return -1;
+  }
+  Value arg;
+  arg.setString(name);
+  if (!InvokeSpecialMessage::send(channel, SPECIAL_HAS_PROPERTY, 1, &arg)) {
+    Debug::log(Debug::Error) << "hasProperty: invoke(hasProperty) failed" << Debug::flush;
+    return -2;
+  }
+  scoped_ptr<ReturnMessage> retMsg(channel.reactToMessagesWhileWaitingForReturn(handler));
+  if (!retMsg.get()) {
+    Debug::log(Debug::Error) << "hasProperty: get return value failed" << Debug::flush;
+    return -2;
+  }
+  Value retval = retMsg->getReturnValue();
+  // TODO(jat): better error handling?
+  return retval.isInt() ? retval.getInt() : -2;
+}
+
+bool ServerMethods::setProperty(HostChannel& channel, SessionHandler* handler, int objectRef,
+    int dispatchId, const Value& value) {
+  // TODO(jat): error handling?
+  Value args[3];
+  args[0].setInt(objectRef);
+  args[1].setInt(dispatchId);
+  args[2] = value;
+  if (!InvokeSpecialMessage::send(channel, SPECIAL_SET_PROPERTY, 3, args)) {
+    Debug::log(Debug::Error) << "  failed to send invoke of SetProperty(disp=" << dispatchId
+        << ", obj=" << objectRef << ")" << Debug::flush;
+    return false;
+  }
+  scoped_ptr<ReturnMessage> retMsg(channel.reactToMessagesWhileWaitingForReturn(handler));
+  if (!retMsg.get()) {
+    Debug::log(Debug::Error) << "setProperty: get return value failed for SetProperty(disp="
+        << dispatchId << ", obj=" << objectRef << ")" << Debug::flush;
+    return false;
+  }
+  // TODO: use the returned exception?
+  return !retMsg.get()->isException();
+}
+
+bool ServerMethods::freeJava(HostChannel& channel, SessionHandler* handler, int idCount,
+      const int* ids) {
+  // If we are disconnected, assume the server will free all of these anyway.
+  // This deals with the problem of getting finalizers called after the channel is dropped.
+  if (!channel.isConnected()) {
+    Debug::log(Debug::Debugging) << "Ignoring freeJava after disconnect"
+        << Debug::flush;
+    return true;
+  }
+  if (!FreeValueMessage::send(channel, idCount, ids)) {
+    Debug::log(Debug::Error) << "  failed to send FreeValues message" << Debug::flush;
+    return false;
+  }
+  return true;
+}
diff --git a/plugins/common/ServerMethods.h b/plugins/common/ServerMethods.h
new file mode 100644
index 0000000..3ff0134
--- /dev/null
+++ b/plugins/common/ServerMethods.h
@@ -0,0 +1,78 @@
+#ifndef _H_ServerMethods
+#define _H_ServerMethods
+/*
+ * 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 "Value.h"
+
+class HostChannel;
+class SessionHandler;
+
+/**
+ * Encapsulates the methods defined on the special server object.
+ */
+class ServerMethods {
+public:
+  /**
+   * Get the value of a property on an object.
+   * 
+   * @param objectRef ID of object to fetch field on
+   * @param dispatchID dispatch ID of field
+   * @return the value of the property, undef if none (or on error)
+   */
+  static Value getProperty(HostChannel& channel, SessionHandler* handler, int objectRef,
+      int dispatchId);
+  
+  /**
+   * Lookup the named method on the specified class.
+   * 
+   * @return the dispatch ID (non-negative) of the method if present, or -1 if not.
+   * If an error is encountered, -2 is returned.
+   */
+  static int hasMethod(HostChannel& channel, SessionHandler* handler, int classId,
+      const std::string& name);
+  
+  /**
+   * Lookup the named property on the specified class.
+   * 
+   * @return the dispatch ID (non-negative) of the property if present, or -1 if not.
+   * If an error is encountered, -2 is returned.
+   */
+  static int hasProperty(HostChannel& channel, SessionHandler* handler, int classId,
+      const std::string& name);
+
+  /**
+   * Set the value of a property on an object.
+   * 
+   * @param objectRef ID of object to fetch field on
+   * @param dispatchID dispatch ID of field
+   * @param value value to store in the property
+   * @return false if an error occurred
+   */
+  static bool setProperty(HostChannel& channel, SessionHandler* handler, int objectRef,
+      int dispatchId, const Value& value);
+  
+  /**
+   * Tell the server that the client no longer has any references to the specified
+   * Java object.
+   * 
+   * @param objcetRef ID of object to free
+   * @return false if an error occurred
+   */ 
+  static bool freeJava(HostChannel& channel, SessionHandler* handler, int idCount, const int* ids);
+};
+
+#endif
diff --git a/plugins/common/SessionHandler.h b/plugins/common/SessionHandler.h
new file mode 100644
index 0000000..217dce4
--- /dev/null
+++ b/plugins/common/SessionHandler.h
@@ -0,0 +1,82 @@
+#ifndef _H_SessionHandler
+#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
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+#include "BrowserChannel.h"
+#include "Value.h"
+
+class HostChannel;
+
+/**
+ * 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
+ * };
+ */
+class SessionHandler {
+  friend class HostChannel;
+public:
+  enum SpecialMethodId {
+    HasMethod = SPECIAL_HAS_METHOD,
+    HasProperty = SPECIAL_HAS_PROPERTY,
+    GetProperty = SPECIAL_GET_PROPERTY,
+    SetProperty = SPECIAL_SET_PROPERTY
+  };
+protected:
+  virtual void freeValue(HostChannel& channel, int idCount, const int* ids) = 0;
+
+  virtual void loadJsni(HostChannel& channel, const std::string& js) = 0;
+
+  /**
+   * 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,
+      const Value* const args, Value* returnValue) = 0;
+
+  /**
+   * Send any queued up free values back to the server.
+   */
+  virtual void sendFreeValues(HostChannel& channel) = 0;
+
+  virtual ~SessionHandler() {}
+};
+
+#endif
diff --git a/plugins/common/Socket.cpp b/plugins/common/Socket.cpp
new file mode 100644
index 0000000..0d6fae5
--- /dev/null
+++ b/plugins/common/Socket.cpp
@@ -0,0 +1,172 @@
+/*
+ * 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 "Platform.h"
+
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <cerrno>
+
+#include "Socket.h"
+
+void Socket::init() {
+#ifdef _WINDOWS
+  // version 2.2 supported on Win95OSR2/WinNT4 and up
+  WORD winsockVers = MAKEWORD(2, 2);
+  WSADATA wsaData;
+  int err = WSAStartup(winsockVers, &wsaData);
+  if (err) {
+    // TODO(jat): report error
+    Debug::log(Debug::Error) << "WSAStartup(vers=2.2): err=" << err << Debug::flush;
+  }
+#endif
+}
+
+bool Socket::connect(const char* host, int port) {
+  Debug::log(Debug::Debugging) << "Socket::connect(host=" << host << ",port=" << port << ")"
+      << Debug::flush;
+  if (isConnected()) {
+    Debug::log(Debug::Error) << "Socket::connect - already connected" << Debug::flush;
+    return false;
+  }
+
+  SOCKETTYPE fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  if (fd < 0) {
+    Debug::log(Debug::Error) << "Socket::connect - can't get socket" << Debug::flush;
+    return false;
+  }
+#ifdef SO_NOSIGPIPE
+  // On BSD, we need to suppress the SIGPIPE if the remote end disconnects.
+  int option_value = 1;
+  if (setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &option_value, sizeof(int))) {
+    Debug::log(Debug::Error) << "Socket::connect - can't set NOSIGPIPE option" << Debug::flush;
+    return false;
+  }
+#endif
+
+  struct sockaddr_in sockAddr;
+  memset(&sockAddr, 0, static_cast<int>(sizeof(sockAddr)));
+  // check for numeric IP4 addresses first
+  // TODO(jat): handle IPv6 addresses
+  unsigned long numericAddr = inet_addr(host);
+  if (numericAddr != 0xFFFFFFFF) {
+    sockAddr.sin_addr.s_addr = numericAddr;
+    sockAddr.sin_family = AF_INET;
+  } else {
+    struct hostent* hent = gethostbyname(host);
+    if (!hent || !hent->h_addr_list[0]) {
+      Debug::log(Debug::Error) << "Unable to get address for " << host << Debug::flush;
+      return false;
+    }
+    memcpy(&(sockAddr.sin_addr), hent->h_addr_list[0], hent->h_length);
+    sockAddr.sin_family = hent->h_addrtype;
+  }
+  sockAddr.sin_port = htons(port);
+
+  if (::connect(fd, (struct sockaddr*) &sockAddr, sizeof(sockAddr)) < 0) {
+#ifdef _WINDOWS
+    char buf[256];
+    strerror_s(buf, sizeof(buf), errno);
+    Debug::log(Debug::Error) << "Can't connect to " << host << ":" << port << " -- "
+        << buf << Debug::flush;
+    closesocket(fd);
+#else
+    Debug::log(Debug::Error) << "Can't connect to " << host << ":" << port << " -- "
+        << strerror(errno) << Debug::flush;
+    close(fd);
+#endif
+    return false;
+  }
+  sock = fd;
+  connected = true;
+  readBufPtr = readValid = readBuf;
+  writeBufPtr = writeBuf;
+#ifdef _WINDOWS
+  Debug::log(Debug::Spam) << "  connected" << Debug::flush;
+#else
+  Debug::log(Debug::Spam) << "  connected, fd=" << fd << Debug::flush;
+#endif
+  return true;
+}
+
+bool Socket::disconnect(bool doFlush) {
+  if (connected) {
+    Debug::log(Debug::Debugging) << "Disconnecting socket" << Debug::flush;
+    if (doFlush) {
+      flush();
+    }
+    connected = false;
+#ifdef _WINDOWS
+    closesocket(sock);
+#else
+    shutdown(sock, SHUT_RDWR);
+    close(sock);
+#endif
+  }
+  return true;
+}
+  
+bool Socket::emptyWriteBuf() {
+  size_t len = writeBufPtr - writeBuf;
+  Debug::log(Debug::Spam) << "Socket::emptyWriteBuf: len=" << len << Debug::flush;
+  ++numWrites;
+  totWriteBytes += len;
+  if (len > maxWriteBytes) {
+    maxWriteBytes = len;
+  }
+  for (char* ptr = writeBuf; len > 0; ) {
+    ssize_t n = send(sock, ptr, len, 0);
+    if (n <= 0) {
+      if (errno == EPIPE) {
+        Debug::log(Debug::Warning) << "Other end of socket disconnected" << Debug::flush;
+        disconnect(false);
+        return false;
+      }
+      Debug::log(Debug::Error) << "Error " << errno << " writing " << len << " bytes to socket"
+          << Debug::flush;
+      return false;
+    }
+    ptr += n;
+    len -= n;
+  }
+  writeBufPtr = writeBuf;
+  return true;
+}
+  
+bool Socket::fillReadBuf() {
+  readBufPtr = readBuf;
+  errno = 0;
+  ssize_t n = recv(sock, readBuf, BUF_SIZE, 0);
+  if (n <= 0) {
+    // EOF results in no error
+    if (!errno || errno == EPIPE) {
+      Debug::log(Debug::Warning) << "Other end of socket disconnected" << Debug::flush;
+      disconnect(false);
+      return false;
+    }
+    Debug::log(Debug::Error) << "Error " << errno << " reading " << BUF_SIZE << " bytes from socket"
+        << Debug::flush;
+    return false;
+  }
+  ++numReads;
+  totReadBytes += n;
+  if (static_cast<size_t>(n) > maxReadBytes) {
+    maxReadBytes = n;
+  }
+  readValid = readBuf + n;
+  return true;
+}
diff --git a/plugins/common/Socket.h b/plugins/common/Socket.h
new file mode 100644
index 0000000..90298f6
--- /dev/null
+++ b/plugins/common/Socket.h
@@ -0,0 +1,170 @@
+#ifndef _H_Socket
+#define _H_Socket
+/*
+ * 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 "Platform.h"
+#include "Debug.h"
+
+#include <string>
+
+#ifdef _WINDOWS
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#else
+#include <netdb.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include <sys/time.h>
+#endif
+
+/**
+ * Encapsulates platform dependencies regarding buffered sockets.
+ */
+class Socket {
+private:
+  // Buffer size, chosen to fit in a single packet after TCP/IP overhead.
+  static const int BUF_SIZE = 1400;
+  
+  // Can't rely on a sentinel value for the socket descriptor
+  bool connected;
+  
+  SOCKETTYPE sock;
+  
+  // Read buffer
+  char* readBuf;
+  
+  // One bye past end of valid data in readBuf
+  char* readValid;
+  
+  // Current read pointer
+  char* readBufPtr;
+
+  // Write buffer
+  char* writeBuf;
+  
+  // Current write pointer
+  char* writeBufPtr;
+
+  // Stats
+  unsigned long numReads;
+  unsigned long long totReadBytes;
+  size_t maxReadBytes;
+
+  unsigned long numWrites;
+  unsigned long long totWriteBytes;
+  size_t maxWriteBytes;
+
+private:
+  void init();
+  bool fillReadBuf();
+  bool emptyWriteBuf();
+
+public:
+  Socket() : connected(false), readBuf(new char[BUF_SIZE]), writeBuf(new char[BUF_SIZE]) {
+    readBufPtr = readValid = readBuf;
+    writeBufPtr = writeBuf;
+    numReads = numWrites = 0;
+    maxReadBytes = maxWriteBytes = 0;
+    totReadBytes = totWriteBytes = 0;
+    init();
+  }
+  
+  ~Socket() {
+    disconnect();
+#ifdef _WINDOWS
+    if (0) WSACleanup();
+#endif
+    // TODO(jat): LEAK LEAK LEAK
+    // delete[] readBuf;
+    // delete[] writeBuf;
+    Debug::log(Debug::Debugging) << "Socket: #r=" << numReads << ", bytes/read="
+        << (numReads ? totReadBytes / numReads : 0) << ", maxr=" << maxReadBytes << "; #w="
+        << numWrites << ", bytes/write=" << (numWrites ? totWriteBytes / numWrites : 0) << ", maxw="
+        << maxWriteBytes << Debug::flush;
+  }
+
+  /**
+   * Connects this socket to a specified port on a host.
+   * 
+   * @param host host name or IP address to connect to
+   * @param port TCP port to connect to
+   * @return true if the connection succeeds
+   */ 
+  bool connect(const char* host, int port);
+  
+  /**
+   * Returns true if the socket is connected.
+   */
+  bool isConnected() const {
+    return connected;
+  }
+  
+  /**
+   * Disconnect this socket.
+   * 
+   * @param doFlush true (the default value) if the socket should be flushed.
+   * @return true if disconnect succeeds
+   */
+  bool disconnect(bool doFlush = true);
+  
+  /**
+   * Read a single byte from the socket.
+   *
+   * @return -1 on error, otherwise unsigned byte read.
+   */
+  int readByte() {
+    if (readBufPtr >= readValid) {
+      if (!fillReadBuf()) {
+        return -1;
+      }
+    }
+    return static_cast<unsigned char>(*readBufPtr++);
+  }
+  
+  /**
+   * Write a single byte to the socket.
+   * 
+   * @return true on success.
+   */
+  bool writeByte(char c) {
+    if (writeBufPtr >= writeBuf + BUF_SIZE) {
+      if (!emptyWriteBuf()) {
+        return false;
+      }
+    }
+    *writeBufPtr++ = c;
+    return true;
+  }
+  
+  /**
+   * Flush any pending writes on the socket.
+   *
+   * @return true on success
+   */
+  bool flush() {
+    if (writeBufPtr > writeBuf) {
+      if (!emptyWriteBuf()) {
+        return false;
+      }
+    }
+    return true;
+  }
+};
+
+#endif
diff --git a/plugins/common/Value.h b/plugins/common/Value.h
new file mode 100644
index 0000000..4401893
--- /dev/null
+++ b/plugins/common/Value.h
@@ -0,0 +1,387 @@
+#ifndef _H_Value
+#define _H_Value
+/*
+ * 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.
+ */
+
+#ifndef _WINDOWS
+// TODO(jat): remove; for abort() which should probably go away
+#include <stdlib.h>
+#endif
+
+#include <string>
+
+#include "Debug.h"
+
+#include "BrowserChannel.h"
+
+class Value {
+public:
+  enum ValueType {
+    NULL_TYPE = VALUE_TYPE_NULL,
+    BOOLEAN = VALUE_TYPE_BOOLEAN,
+    BYTE = VALUE_TYPE_BYTE,
+    CHAR = VALUE_TYPE_CHAR,
+    SHORT = VALUE_TYPE_SHORT,
+    INT = VALUE_TYPE_INT,
+    LONG = VALUE_TYPE_LONG,
+    FLOAT = VALUE_TYPE_FLOAT,
+    DOUBLE = VALUE_TYPE_DOUBLE,
+    STRING = VALUE_TYPE_STRING,
+    JAVA_OBJECT = VALUE_TYPE_JAVA_OBJECT,
+    JS_OBJECT = VALUE_TYPE_JS_OBJECT,
+    UNDEFINED = VALUE_TYPE_UNDEFINED
+  };
+
+private:
+  ValueType type;
+  union {
+    bool  boolValue;
+    unsigned char byteValue;
+    unsigned short charValue;
+    double doubleValue;
+    float floatValue;
+    int32_t intValue;
+    int64_t longValue;
+    short shortValue;
+    std::string* stringValue;
+  } value;
+
+public:
+  Value() {
+    type = UNDEFINED;
+  }
+
+  Value(const Value& other) {
+    copyValue(other);
+  }
+
+  Value& operator=(const Value& other) {
+    clearOldValue();
+    copyValue(other);
+    return *this;
+  }
+
+  ~Value() {
+    clearOldValue();
+  }
+
+  bool getBoolean() const {
+    assertType(BOOLEAN);
+    return value.boolValue;
+  }
+
+  unsigned char getByte() const {
+    assertType(BYTE);
+    return value.byteValue;
+  }
+
+  unsigned short getChar() const {
+    assertType(CHAR);
+    return value.charValue;
+  }
+
+  double getDouble() const {
+    assertType(DOUBLE);
+    return value.doubleValue;
+  }
+
+  float getFloat() const {
+    assertType(FLOAT);
+    return value.floatValue;
+  }
+
+  int getInt() const {
+    assertType(INT);
+    return value.intValue;
+  }
+
+  int getJavaObjectId() const {
+    assertType(JAVA_OBJECT);
+    return value.intValue;
+  }
+
+  int getJsObjectId() const {
+    assertType(JS_OBJECT);
+    return value.intValue;
+  }
+
+  int64_t getLong() const {
+    assertType(LONG);
+    return value.longValue;
+  }
+
+  short getShort() const {
+    assertType(SHORT);
+    return value.shortValue;
+  }
+
+  const std::string getString() const {
+    assertType(STRING);
+    return std::string(*value.stringValue);
+  }
+
+  ValueType getType() const {
+    return type;
+  }
+
+  bool isBoolean() const {
+    return type == BOOLEAN;
+  }
+
+  bool isByte() const {
+    return type == BYTE;
+  }
+
+  bool isChar() const {
+    return type == CHAR;
+  }
+
+  bool isDouble() const {
+    return type == DOUBLE;
+  }
+
+  bool isFloat() const {
+    return type == FLOAT;
+  }
+
+  bool isInt() const {
+    return type == INT;
+  }
+
+  bool isJavaObject() const {
+    return type == JAVA_OBJECT;
+  }
+
+  bool isJsObject() const {
+    return type == JS_OBJECT;
+  }
+
+  bool isLong() const {
+    return type == LONG;
+  }
+
+  bool isNull() const {
+    return type == NULL_TYPE;
+  }
+
+  bool isNumber() const {
+    switch (type) {
+      case BYTE:
+      case CHAR:
+      case DOUBLE:
+      case FLOAT:
+      case INT:
+      case LONG:
+      case SHORT:
+        return true;
+      default:
+        return false;
+    }
+  }
+
+  bool isPrimitive() const {
+    switch (type) {
+      case BOOLEAN:
+      case BYTE:
+      case CHAR:
+      case DOUBLE:
+      case FLOAT:
+      case INT:
+      case LONG:
+      case SHORT:
+        return true;
+      default:
+        return false;
+    }
+  }
+
+  bool isShort() const {
+    return type == SHORT;
+  }
+
+  bool isString() const {
+    return type == STRING;
+  }
+
+  bool isUndefined() const {
+    return type == UNDEFINED;
+  }
+
+  void setBoolean(bool val) {
+    clearOldValue();
+    type = BOOLEAN;
+    value.boolValue = val;
+  }
+
+  void setByte(unsigned char val) {
+    clearOldValue();
+    type = BYTE;
+    value.byteValue = val;
+  }
+
+  void setChar(unsigned short val) {
+    clearOldValue();
+    type = CHAR;
+    value.charValue = val;
+  }
+
+  void setDouble(double val) {
+    clearOldValue();
+    type = DOUBLE;
+    value.doubleValue = val;
+  }
+
+  void setFloat(float val) {
+    clearOldValue();
+    type = FLOAT;
+    value.floatValue = val;
+  }
+
+  void setInt(int val) {
+    clearOldValue();
+    type = INT;
+    value.intValue = val;
+  }
+
+  void setJavaObject(int objectId) {
+    clearOldValue();
+    type = JAVA_OBJECT;
+    value.intValue = objectId;
+  }
+
+  void setJsObjectId(int val) {
+    clearOldValue();
+    type = JS_OBJECT;
+    value.intValue = val;
+  }
+
+  void setLong(int64_t val) {
+    clearOldValue();
+    type = LONG;
+    value.longValue = val;
+  }
+
+  void setNull() {
+    clearOldValue();
+    type = NULL_TYPE;
+  }
+
+  void setShort(short val) {
+    clearOldValue();
+    type = SHORT;
+    value.shortValue = val;
+  }
+
+  void setString(const char* chars, int len) {
+    setString(std::string(chars, len));
+  }
+
+  void setString(const std::string& val) {
+    clearOldValue();
+    type = STRING;
+    value.stringValue = new std::string(val);
+  }
+
+  void setUndefined() {
+    clearOldValue();
+    type = UNDEFINED;
+  }
+
+  std::string toString() const {
+    char buf[30];
+    switch (type) {
+      case NULL_TYPE:
+        return "null";
+      case BOOLEAN:
+        snprintf(buf, sizeof(buf), "boolean(%s)", getBoolean() ? "true"
+            : "false");
+        return std::string(buf);
+      case BYTE:
+        snprintf(buf, sizeof(buf), "byte(%d)", getByte());
+        return std::string(buf);
+      case CHAR:
+        snprintf(buf, sizeof(buf), "char(%d)", getChar());
+        return std::string(buf);
+      case SHORT:
+        snprintf(buf, sizeof(buf), "short(%d)", getShort());
+        return std::string(buf);
+      case INT:
+        snprintf(buf, sizeof(buf), "int(%d)", getInt());
+        return std::string(buf);
+      case LONG:
+        snprintf(buf, sizeof(buf), "long(%lld)",
+            static_cast<long long>(getLong()));
+        return std::string(buf);
+      case FLOAT:
+        snprintf(buf, sizeof(buf), "float(%f)", getFloat());
+        return std::string(buf);
+      case DOUBLE:
+        snprintf(buf, sizeof(buf), "double(%lf)", getDouble());
+        return std::string(buf);
+      case STRING:
+        snprintf(buf, sizeof(buf), "string(%.20s)", getString().c_str());
+        return std::string(buf);
+      case JAVA_OBJECT:
+        snprintf(buf, sizeof(buf), "JavaObj(%d)", getJavaObjectId());
+        return std::string(buf);
+      case JS_OBJECT:
+        snprintf(buf, sizeof(buf), "JsObj(%d)", getJsObjectId());
+        return std::string(buf);
+      case UNDEFINED:
+        return "undefined";
+      default:
+        return "Unknown type";
+    }
+  }
+
+private:
+  void assertType(ValueType reqType) const {
+    if (type != reqType) {
+      Debug::log(Debug::Error) << "Value::assertType - expecting type "
+          << int(reqType) << ", was " << int(type) << Debug::flush;
+      // TODO(jat): is this portable?  Should we do something else here?
+      abort();
+    }
+  }
+
+  void clearOldValue() {
+    if (type == STRING) {
+      delete value.stringValue;
+      type = UNDEFINED;
+    }
+  }
+
+  // Precondition: existing value, if any, has been cleared
+  void copyValue(const Value& other) {
+    type = other.type;
+    value = other.value;
+    // handle deep copies of value types that need it
+    switch (type) {
+      case STRING:
+        value.stringValue = new std::string(*value.stringValue);
+        break;
+      default:
+        // no other values need deep copies
+        break;
+    }
+  }
+};
+
+inline Debug::DebugStream& operator<<(Debug::DebugStream& dbg, const Value& val) {
+  return dbg << val.toString();
+}
+
+#endif
diff --git a/plugins/common/scoped_ptr/README.google b/plugins/common/scoped_ptr/README.google
new file mode 100644
index 0000000..d513e21
--- /dev/null
+++ b/plugins/common/scoped_ptr/README.google
@@ -0,0 +1,27 @@
+Description
+===========
+
+This is the scoped_ptr from Boost with some additions by Google.
+
+Homepage
+========
+
+http://www.boost.org/
+http://www.boost.org/libs/smart_ptr/scoped_ptr.htm
+
+License
+=======
+
+http://boost.org/LICENSE_1_0.txt
+
+Source files and modifications
+==============================
+
+scoped_ptr_malloc added in by Ray Sidney of Google.  When one of these goes
+out of scope, instead of doing a delete or delete[], it calls free().
+scoped_ptr_malloc<char> is likely to see much more use than any other
+specializations.
+
+release() added in by Spencer Kimball of Google. Use this to conditionally
+transfer ownership of a heap-allocated object to the caller, usually on
+method success.
diff --git a/plugins/common/scoped_ptr/scoped_ptr.h b/plugins/common/scoped_ptr/scoped_ptr.h
new file mode 100644
index 0000000..1ae1b96
--- /dev/null
+++ b/plugins/common/scoped_ptr/scoped_ptr.h
@@ -0,0 +1,364 @@
+#ifndef SCOPED_PTR_H
+#define SCOPED_PTR_H
+
+// (C) Copyright Greg Colvin and Beman Dawes 1998, 1999.
+// Copyright (c) 2001, 2002 Peter Dimov
+// 
+// Permission is hereby granted, free of charge, to any person or organization
+// obtaining a copy of the software and accompanying documentation covered by
+// this license (the "Software") to use, reproduce, display, distribute,
+// execute, and transmit the Software, and to prepare derivative works of the
+// Software, and to permit third-parties to whom the Software is furnished to
+// do so, all subject to the following:
+//
+// The copyright notices in the Software and this entire statement, including
+// the above license grant, this restriction and the following disclaimer,
+// must be included in all copies of the Software, in whole or in part, and
+// all derivative works of the Software, unless such copies or derivative
+// works are solely in the form of machine-executable object code generated by
+// a source language processor.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+//  See http://www.boost.org/libs/smart_ptr/scoped_ptr.htm for documentation.
+//
+//
+//  scoped_ptr mimics a built-in pointer except that it guarantees deletion
+//  of the object pointed to, either on destruction of the scoped_ptr or via
+//  an explicit reset(). scoped_ptr is a simple solution for simple needs;
+//  use shared_ptr if your needs are more complex.
+//
+//  *** NOTE ***
+//  If your scoped_ptr is a class member of class FOO pointing to a 
+//  forward declared type BAR (as shown below), then at creation (and 
+//  destruction) of an object of type FOO, BAR must be complete.  You can do
+//  this by either:
+//   - Making all FOO constructors and destructors non-inlined to FOO's class
+//     definition, instead placing them in foo.cc below an include of bar.h
+//   - Including bar.h before any creation or destruction of any object of
+//     type FOO
+//  The former is probably the less error-prone method, as shown below.
+//
+//  Example:
+//
+//  -- foo.h --
+//  class BAR;
+//
+//  class FOO {
+//   public:
+//    FOO();   // Required for sources that instantiate class FOO to compile!
+//    ~FOO();  // Required for sources that instantiate class FOO to compile!
+//    
+//   private:
+//    scoped_ptr<BAR> bar_;
+//  };
+//
+//  -- foo.cc --
+//  #include "bar.h"
+//  #include "foo.h"
+//  FOO::FOO() {}  // Empty, but must be non-inlined to FOO's class definition.
+//  FOO::~FOO() {} // Empty, but must be non-inlined to FOO's class definition.
+//
+//  scoped_ptr_malloc added in by Ray Sidney of Google.  When one of
+//  these goes out of scope, instead of doing a delete or delete[], it
+//  calls free().  scoped_ptr_malloc<char> is likely to see much more
+//  use than any other specializations.
+//
+//  release() added in by Spencer Kimball of Google. Use this to conditionally
+//  transfer ownership of a heap-allocated object to the caller, usually on
+//  method success.
+
+#include <cstddef>            // for std::ptrdiff_t
+#include <assert.h>           // for assert
+#include <stdlib.h>           // for free() decl
+
+template <typename T>
+class scoped_ptr;
+
+template <typename T>
+class scoped_ptr {
+ private:
+
+  T* ptr;
+
+  // scoped_ptr's must not be copied.  We make sure of that by making the
+  // copy constructor prototype private.  At the same time, there is no body
+  // for this constructor.  Thus, if anything that has access to private
+  // members of scoped_ptr ever (inadvertently) copies a scoped_ptr, the
+  // linker will complain about missing symbols.  This is a good thing!
+  scoped_ptr(scoped_ptr const &);
+  scoped_ptr & operator=(scoped_ptr const &);
+
+ public:
+
+  typedef T element_type;
+
+  explicit scoped_ptr(T* p = 0): ptr(p) {}
+
+  ~scoped_ptr() {
+    typedef char type_must_be_complete[sizeof(T)];
+    delete ptr;
+  }
+
+  void reset(T* p = 0) {
+    typedef char type_must_be_complete[sizeof(T)];
+
+    if (ptr != p) {
+      delete ptr;
+      ptr = p;
+    }
+  }
+
+  T& operator*() const {
+    assert(ptr != 0);
+    return *ptr;
+  }
+
+  T* operator->() const  {
+    assert(ptr != 0);
+    return ptr;
+  }
+
+  bool operator==(T* p) const {
+    return ptr == p;
+  }
+
+  bool operator!=(T* p) const {
+    return ptr != p;
+  }
+
+  T* get() const  {
+    return ptr;
+  }
+
+  void swap(scoped_ptr & b) {
+    T* tmp = b.ptr;
+    b.ptr = ptr;
+    ptr = tmp;
+  }
+
+  T* release() {
+    T* tmp = ptr;
+    ptr = 0;
+    return tmp;
+  }
+
+ private:
+
+  // no reason to use these: each scoped_ptr should have its own object
+  template <typename U> bool operator==(scoped_ptr<U> const& p) const;
+  template <typename U> bool operator!=(scoped_ptr<U> const& p) const;
+};
+
+template<typename T> inline
+void swap(scoped_ptr<T>& a, scoped_ptr<T>& b) {
+  a.swap(b);
+}
+
+template<typename T> inline
+bool operator==(T* p, const scoped_ptr<T>& b) {
+  return p == b.get();
+}
+
+template<typename T> inline
+bool operator!=(T* p, const scoped_ptr<T>& b) {
+  return p != b.get();
+}
+
+//  scoped_array extends scoped_ptr to arrays. Deletion of the array pointed to
+//  is guaranteed, either on destruction of the scoped_array or via an explicit
+//  reset(). Use shared_array or std::vector if your needs are more complex.
+
+template<typename T>
+class scoped_array {
+ private:
+
+  T* ptr;
+
+  scoped_array(scoped_array const &);
+  scoped_array & operator=(scoped_array const &);
+
+ public:
+
+  typedef T element_type;
+
+  explicit scoped_array(T* p = 0) : ptr(p) {}
+
+  ~scoped_array() {
+    typedef char type_must_be_complete[sizeof(T)];
+    delete[] ptr;
+  }
+
+  void reset(T* p = 0) {
+    typedef char type_must_be_complete[sizeof(T)];
+
+    if (ptr != p) {
+      delete [] ptr;
+      ptr = p;
+    }
+  }
+
+  T& operator[](std::ptrdiff_t i) const {
+    assert(ptr != 0);
+    assert(i >= 0);
+    return ptr[i];
+  }
+
+  bool operator==(T* p) const {
+    return ptr == p;
+  }
+
+  bool operator!=(T* p) const {
+    return ptr != p;
+  }
+
+  T* get() const {
+    return ptr;
+  }
+
+  void swap(scoped_array & b) {
+    T* tmp = b.ptr;
+    b.ptr = ptr;
+    ptr = tmp;
+  }
+
+  T* release() {
+    T* tmp = ptr;
+    ptr = 0;
+    return tmp;
+  }
+
+ private:
+
+  // no reason to use these: each scoped_array should have its own object
+  template <typename U> bool operator==(scoped_array<U> const& p) const;
+  template <typename U> bool operator!=(scoped_array<U> const& p) const;
+};
+
+template<class T> inline
+void swap(scoped_array<T>& a, scoped_array<T>& b) {
+  a.swap(b);
+}
+
+template<typename T> inline
+bool operator==(T* p, const scoped_array<T>& b) {
+  return p == b.get();
+}
+
+template<typename T> inline
+bool operator!=(T* p, const scoped_array<T>& b) {
+  return p != b.get();
+}
+
+
+// This class wraps the c library function free() in a class that can be
+// passed as a template argument to scoped_ptr_malloc below.
+class ScopedPtrMallocFree {
+ public:
+  inline void operator()(void* x) const {
+    free(x);
+  }
+};
+
+// scoped_ptr_malloc<> is similar to scoped_ptr<>, but it accepts a
+// second template argument, the functor used to free the object.
+
+template<typename T, typename FreeProc = ScopedPtrMallocFree>
+class scoped_ptr_malloc {
+ private:
+
+  T* ptr;
+
+  scoped_ptr_malloc(scoped_ptr_malloc const &);
+  scoped_ptr_malloc & operator=(scoped_ptr_malloc const &);
+
+ public:
+
+  typedef T element_type;
+
+  explicit scoped_ptr_malloc(T* p = 0): ptr(p) {}
+
+  ~scoped_ptr_malloc() {
+    typedef char type_must_be_complete[sizeof(T)];
+    free_((void*) ptr);
+  }
+
+  void reset(T* p = 0) {
+    typedef char type_must_be_complete[sizeof(T)];
+
+    if (ptr != p) {
+      free_((void*) ptr);
+      ptr = p;
+    }
+  }
+
+  T& operator*() const {
+    assert(ptr != 0);
+    return *ptr;
+  }
+
+  T* operator->() const {
+    assert(ptr != 0);
+    return ptr;
+  }
+
+  bool operator==(T* p) const {
+    return ptr == p;
+  }
+
+  bool operator!=(T* p) const {
+    return ptr != p;
+  }
+
+  T* get() const {
+    return ptr;
+  }
+
+  void swap(scoped_ptr_malloc & b) {
+    T* tmp = b.ptr;
+    b.ptr = ptr;
+    ptr = tmp;
+  }
+
+  T* release() {
+    T* tmp = ptr;
+    ptr = 0;
+    return tmp;
+  }
+
+ private:
+
+  // no reason to use these: each scoped_ptr_malloc should have its own object
+  template <typename U, typename GP>
+  bool operator==(scoped_ptr_malloc<U, GP> const& p) const;
+  template <typename U, typename GP>
+  bool operator!=(scoped_ptr_malloc<U, GP> const& p) const;
+
+  static FreeProc const free_;
+};
+
+template<typename T, typename FP>
+FP const scoped_ptr_malloc<T,FP>::free_ = FP();
+
+template<typename T, typename FP> inline
+void swap(scoped_ptr_malloc<T,FP>& a, scoped_ptr_malloc<T,FP>& b) {
+  a.swap(b);
+}
+
+template<typename T, typename FP> inline
+bool operator==(T* p, const scoped_ptr_malloc<T,FP>& b) {
+  return p == b.get();
+}
+
+template<typename T, typename FP> inline
+bool operator!=(T* p, const scoped_ptr_malloc<T,FP>& b) {
+  return p != b.get();
+}
+
+#endif  // #ifndef SCOPED_PTR_H
diff --git a/plugins/common/testing/DebugTest.cpp b/plugins/common/testing/DebugTest.cpp
new file mode 100644
index 0000000..add1357
--- /dev/null
+++ b/plugins/common/testing/DebugTest.cpp
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+// This file exists to verify that the debugging code leaves nothing
+// behind when disabled or at an appropriate level.
+//
+// Compile with, for example, g++ -O3 -D* -S DebugTest.cpp and inspect the DebugTest.s file.
+//   where * is GWT_DEBUGDISABLE or GWT_DEBUGLEVEL=Spam (etc)
+//
+// testdebug is a shell script to automate this test
+
+// #define GWT_DEBUGDISABLE
+// #define GWT_DEBUGLEVEL Info
+
+#include "../Debug.h"
+
+void foo(int i) {
+  Debug::log(Debug::Error) << "Error GarbalDeGook" << i << Debug::flush;
+  Debug::log(Debug::Warning) << "Warning GarbalDeGook" << i << Debug::flush;
+  Debug::log(Debug::Info) << "Info GarbalDeGook" << i << Debug::flush;
+  Debug::log(Debug::Debugging) << "Debugging GarbalDeGook" << i << Debug::flush;
+  Debug::log(Debug::Spam) << "Spam GarbalDeGook" << i << Debug::flush;
+  if (Debug::level(Debug::Spam)) {
+    extern int ExpensiveCall();
+    Debug::log(Debug::Spam) << "Filtered spam GarbalDeGook" << ExpensiveCall() << Debug::flush;
+  }
+}
diff --git a/plugins/common/testing/testdebug b/plugins/common/testing/testdebug
new file mode 100755
index 0000000..e2e8ea4
--- /dev/null
+++ b/plugins/common/testing/testdebug
@@ -0,0 +1,61 @@
+#!/bin/sh
+# 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.
+
+# this verifies that debug code is elided if it is not needed
+
+# The C++ compiler is specified in CXX, and its flags in CXXFLAGS
+# Defaults for GCC are used if not supplied.  Note that CXXFLAGS should
+# include optimizations intended to be used.  It is assumed that the
+# compiler uses -S to produce assembly output and -o - works to get that
+# output on stdout, and -Dsym=val is used to define preprocessor symbols.
+#
+# Note that debugging symbols should not be included as generally the
+# debugging info contains references to elided calls etc.
+if [ "x$CXX" == "x" ]
+then
+  CXX=g++
+fi
+
+if [ "x$CXXFLAGS" == "x" ]
+then
+  CXXFLAGS=-O3
+else
+  # remove -g if supplied
+  CXXFLAGS=`echo $CXXFLAGS | sed 's/-g\S*//'`
+fi
+
+CMD="$CXX $CXXFLAGS -S -o -"
+
+err=0
+$CMD -DGWT_DEBUGDISABLE DebugTest.cpp | egrep '(GarbalDeGook|ExpensiveCall)' >/dev/null
+if [ $? -eq 0 ]
+then
+  echo "Debug disabled leaves debug code around"
+  err=1
+fi
+$CMD -DGWT_DEBUGLEVEL=Error DebugTest.cpp | egrep '(Warning|ExpensiveCall)' >/dev/null
+if [ $? -eq 0 ]
+then
+  echo "Debug level Error leaves lower-level debug code around"
+  err=1
+fi
+$CMD -DGWT_DEBUGLEVEL=Spam DebugTest.cpp | grep 'ExpensiveCall' >/dev/null
+if [ $? -eq 1 ]
+then
+  echo "Debug level Spam does not include code that should be included"
+  err=1
+fi
+
+exit $err