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