Index: ipc/ipc_message_utils.h |
diff --git a/ipc/ipc_message_utils.h b/ipc/ipc_message_utils.h |
new file mode 100644 |
index 0000000000000000000000000000000000000000..3fd8123863c9188314d40aa91d3845df1746bde1 |
--- /dev/null |
+++ b/ipc/ipc_message_utils.h |
@@ -0,0 +1,1221 @@ |
+// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#ifndef IPC_IPC_MESSAGE_UTILS_H_ |
+#define IPC_IPC_MESSAGE_UTILS_H_ |
+ |
+#include <string> |
+#include <vector> |
+#include <map> |
+ |
+#include "base/file_path.h" |
+#include "base/format_macros.h" |
+#include "base/string16.h" |
+#include "base/string_util.h" |
+#include "base/time.h" |
+#include "base/tuple.h" |
+#include "base/values.h" |
+#if defined(OS_POSIX) |
+#include "ipc/file_descriptor_set_posix.h" |
+#endif |
+#include "ipc/ipc_channel_handle.h" |
+#include "ipc/ipc_sync_message.h" |
+ |
+// Used by IPC_BEGIN_MESSAGES so that each message class starts from a unique |
+// base. Messages have unique IDs across channels in order for the IPC logging |
+// code to figure out the message class from its ID. |
+enum IPCMessageStart { |
+ // By using a start value of 0 for automation messages, we keep backward |
+ // compatibility with old builds. |
+ AutomationMsgStart = 0, |
+ ViewMsgStart, |
+ ViewHostMsgStart, |
+ PluginProcessMsgStart, |
+ PluginProcessHostMsgStart, |
+ PluginMsgStart, |
+ PluginHostMsgStart, |
+ NPObjectMsgStart, |
+ TestMsgStart, |
+ DevToolsAgentMsgStart, |
+ DevToolsClientMsgStart, |
+ WorkerProcessMsgStart, |
+ WorkerProcessHostMsgStart, |
+ WorkerMsgStart, |
+ WorkerHostMsgStart, |
+ // NOTE: When you add a new message class, also update |
+ // IPCStatusView::IPCStatusView to ensure logging works. |
+ // NOTE: this enum is used by IPC_MESSAGE_MACRO to generate a unique message |
+ // id. Only 4 bits are used for the message type, so if this enum needs more |
+ // than 16 entries, that code needs to be updated. |
+ LastMsgIndex |
+}; |
+ |
+COMPILE_ASSERT(LastMsgIndex <= 16, need_to_update_IPC_MESSAGE_MACRO); |
+ |
+ |
+namespace IPC { |
+ |
+//----------------------------------------------------------------------------- |
+// An iterator class for reading the fields contained within a Message. |
+ |
+class MessageIterator { |
+ public: |
+ explicit MessageIterator(const Message& m) : msg_(m), iter_(NULL) { |
+ } |
+ int NextInt() const { |
+ int val; |
+ if (!msg_.ReadInt(&iter_, &val)) |
+ NOTREACHED(); |
+ return val; |
+ } |
+ intptr_t NextIntPtr() const { |
+ intptr_t val; |
+ if (!msg_.ReadIntPtr(&iter_, &val)) |
+ NOTREACHED(); |
+ return val; |
+ } |
+ const std::string NextString() const { |
+ std::string val; |
+ if (!msg_.ReadString(&iter_, &val)) |
+ NOTREACHED(); |
+ return val; |
+ } |
+ const std::wstring NextWString() const { |
+ std::wstring val; |
+ if (!msg_.ReadWString(&iter_, &val)) |
+ NOTREACHED(); |
+ return val; |
+ } |
+ const void NextData(const char** data, int* length) const { |
+ if (!msg_.ReadData(&iter_, data, length)) { |
+ NOTREACHED(); |
+ } |
+ } |
+ private: |
+ const Message& msg_; |
+ mutable void* iter_; |
+}; |
+ |
+//----------------------------------------------------------------------------- |
+// ParamTraits specializations, etc. |
+ |
+template <class P> struct ParamTraits {}; |
+ |
+template <class P> |
+static inline void WriteParam(Message* m, const P& p) { |
+ ParamTraits<P>::Write(m, p); |
+} |
+ |
+template <class P> |
+static inline bool WARN_UNUSED_RESULT ReadParam(const Message* m, void** iter, |
+ P* p) { |
+ return ParamTraits<P>::Read(m, iter, p); |
+} |
+ |
+template <class P> |
+static inline void LogParam(const P& p, std::wstring* l) { |
+ ParamTraits<P>::Log(p, l); |
+} |
+ |
+template <> |
+struct ParamTraits<bool> { |
+ typedef bool param_type; |
+ static void Write(Message* m, const param_type& p) { |
+ m->WriteBool(p); |
+ } |
+ static bool Read(const Message* m, void** iter, param_type* r) { |
+ return m->ReadBool(iter, r); |
+ } |
+ static void Log(const param_type& p, std::wstring* l) { |
+ l->append(p ? L"true" : L"false"); |
+ } |
+}; |
+ |
+template <> |
+struct ParamTraits<int> { |
+ typedef int param_type; |
+ static void Write(Message* m, const param_type& p) { |
+ m->WriteInt(p); |
+ } |
+ static bool Read(const Message* m, void** iter, param_type* r) { |
+ return m->ReadInt(iter, r); |
+ } |
+ static void Log(const param_type& p, std::wstring* l) { |
+ l->append(StringPrintf(L"%d", p)); |
+ } |
+}; |
+ |
+template <> |
+struct ParamTraits<long> { |
+ typedef long param_type; |
+ static void Write(Message* m, const param_type& p) { |
+ m->WriteLong(p); |
+ } |
+ static bool Read(const Message* m, void** iter, param_type* r) { |
+ return m->ReadLong(iter, r); |
+ } |
+ static void Log(const param_type& p, std::wstring* l) { |
+ l->append(StringPrintf(L"%l", p)); |
+ } |
+}; |
+ |
+#if defined(OS_LINUX) || defined(OS_WIN) |
+// On Linux, unsigned long is used for serializing X window ids. |
+// On Windows, it's used for serializing process ids. |
+// On Mac, it conflicts with some other definition. |
+template <> |
+struct ParamTraits<unsigned long> { |
+ typedef unsigned long param_type; |
+ static void Write(Message* m, const param_type& p) { |
+ m->WriteLong(p); |
+ } |
+ static bool Read(const Message* m, void** iter, param_type* r) { |
+ long read_output; |
+ if (!m->ReadLong(iter, &read_output)) |
+ return false; |
+ *r = static_cast<unsigned long>(read_output); |
+ return true; |
+ } |
+ static void Log(const param_type& p, std::wstring* l) { |
+ l->append(StringPrintf(L"%ul", p)); |
+ } |
+}; |
+#endif |
+ |
+template <> |
+struct ParamTraits<size_t> { |
+ typedef size_t param_type; |
+ static void Write(Message* m, const param_type& p) { |
+ m->WriteSize(p); |
+ } |
+ static bool Read(const Message* m, void** iter, param_type* r) { |
+ return m->ReadSize(iter, r); |
+ } |
+ static void Log(const param_type& p, std::wstring* l) { |
+ l->append(StringPrintf(L"%u", p)); |
+ } |
+}; |
+ |
+#if defined(OS_MACOSX) |
+// On Linux size_t & uint32 can be the same type. |
+// TODO(playmobil): Fix compilation if this is not the case. |
+template <> |
+struct ParamTraits<uint32> { |
+ typedef uint32 param_type; |
+ static void Write(Message* m, const param_type& p) { |
+ m->WriteUInt32(p); |
+ } |
+ static bool Read(const Message* m, void** iter, param_type* r) { |
+ return m->ReadUInt32(iter, r); |
+ } |
+ static void Log(const param_type& p, std::wstring* l) { |
+ l->append(StringPrintf(L"%u", p)); |
+ } |
+}; |
+#endif // defined(OS_MACOSX) |
+ |
+template <> |
+struct ParamTraits<int64> { |
+ typedef int64 param_type; |
+ static void Write(Message* m, const param_type& p) { |
+ m->WriteInt64(p); |
+ } |
+ static bool Read(const Message* m, void** iter, param_type* r) { |
+ return m->ReadInt64(iter, r); |
+ } |
+ static void Log(const param_type& p, std::wstring* l) { |
+ l->append(StringPrintf(L"%" WidePRId64, p)); |
+ } |
+}; |
+ |
+template <> |
+struct ParamTraits<uint64> { |
+ typedef uint64 param_type; |
+ static void Write(Message* m, const param_type& p) { |
+ m->WriteInt64(static_cast<int64>(p)); |
+ } |
+ static bool Read(const Message* m, void** iter, param_type* r) { |
+ return m->ReadInt64(iter, reinterpret_cast<int64*>(r)); |
+ } |
+ static void Log(const param_type& p, std::wstring* l) { |
+ l->append(StringPrintf(L"%" WidePRId64, p)); |
+ } |
+}; |
+ |
+template <> |
+struct ParamTraits<double> { |
+ typedef double param_type; |
+ static void Write(Message* m, const param_type& p) { |
+ m->WriteData(reinterpret_cast<const char*>(&p), sizeof(param_type)); |
+ } |
+ static bool Read(const Message* m, void** iter, param_type* r) { |
+ const char *data; |
+ int data_size = 0; |
+ bool result = m->ReadData(iter, &data, &data_size); |
+ if (result && data_size == sizeof(param_type)) { |
+ memcpy(r, data, sizeof(param_type)); |
+ } else { |
+ result = false; |
+ NOTREACHED(); |
+ } |
+ |
+ return result; |
+ } |
+ static void Log(const param_type& p, std::wstring* l) { |
+ l->append(StringPrintf(L"e", p)); |
+ } |
+}; |
+ |
+template <> |
+struct ParamTraits<wchar_t> { |
+ typedef wchar_t param_type; |
+ static void Write(Message* m, const param_type& p) { |
+ m->WriteData(reinterpret_cast<const char*>(&p), sizeof(param_type)); |
+ } |
+ static bool Read(const Message* m, void** iter, param_type* r) { |
+ const char *data; |
+ int data_size = 0; |
+ bool result = m->ReadData(iter, &data, &data_size); |
+ if (result && data_size == sizeof(param_type)) { |
+ memcpy(r, data, sizeof(param_type)); |
+ } else { |
+ result = false; |
+ NOTREACHED(); |
+ } |
+ |
+ return result; |
+ } |
+ static void Log(const param_type& p, std::wstring* l) { |
+ l->append(StringPrintf(L"%lc", p)); |
+ } |
+}; |
+ |
+template <> |
+struct ParamTraits<base::Time> { |
+ typedef base::Time param_type; |
+ static void Write(Message* m, const param_type& p) { |
+ ParamTraits<int64>::Write(m, p.ToInternalValue()); |
+ } |
+ static bool Read(const Message* m, void** iter, param_type* r) { |
+ int64 value; |
+ if (!ParamTraits<int64>::Read(m, iter, &value)) |
+ return false; |
+ *r = base::Time::FromInternalValue(value); |
+ return true; |
+ } |
+ static void Log(const param_type& p, std::wstring* l) { |
+ ParamTraits<int64>::Log(p.ToInternalValue(), l); |
+ } |
+}; |
+ |
+#if defined(OS_WIN) |
+template <> |
+struct ParamTraits<LOGFONT> { |
+ typedef LOGFONT param_type; |
+ static void Write(Message* m, const param_type& p) { |
+ m->WriteData(reinterpret_cast<const char*>(&p), sizeof(LOGFONT)); |
+ } |
+ static bool Read(const Message* m, void** iter, param_type* r) { |
+ const char *data; |
+ int data_size = 0; |
+ bool result = m->ReadData(iter, &data, &data_size); |
+ if (result && data_size == sizeof(LOGFONT)) { |
+ memcpy(r, data, sizeof(LOGFONT)); |
+ } else { |
+ result = false; |
+ NOTREACHED(); |
+ } |
+ |
+ return result; |
+ } |
+ static void Log(const param_type& p, std::wstring* l) { |
+ l->append(StringPrintf(L"<LOGFONT>")); |
+ } |
+}; |
+ |
+template <> |
+struct ParamTraits<MSG> { |
+ typedef MSG param_type; |
+ static void Write(Message* m, const param_type& p) { |
+ m->WriteData(reinterpret_cast<const char*>(&p), sizeof(MSG)); |
+ } |
+ static bool Read(const Message* m, void** iter, param_type* r) { |
+ const char *data; |
+ int data_size = 0; |
+ bool result = m->ReadData(iter, &data, &data_size); |
+ if (result && data_size == sizeof(MSG)) { |
+ memcpy(r, data, sizeof(MSG)); |
+ } else { |
+ result = false; |
+ NOTREACHED(); |
+ } |
+ |
+ return result; |
+ } |
+}; |
+#endif // defined(OS_WIN) |
+ |
+template <> |
+struct ParamTraits<DictionaryValue> { |
+ typedef DictionaryValue param_type; |
+ static void Write(Message* m, const param_type& p); |
+ static bool Read(const Message* m, void** iter, param_type* r); |
+ static void Log(const param_type& p, std::wstring* l); |
+}; |
+ |
+template <> |
+struct ParamTraits<ListValue> { |
+ typedef ListValue param_type; |
+ static void Write(Message* m, const param_type& p); |
+ static bool Read(const Message* m, void** iter, param_type* r); |
+ static void Log(const param_type& p, std::wstring* l); |
+}; |
+ |
+template <> |
+struct ParamTraits<std::string> { |
+ typedef std::string param_type; |
+ static void Write(Message* m, const param_type& p) { |
+ m->WriteString(p); |
+ } |
+ static bool Read(const Message* m, void** iter, param_type* r) { |
+ return m->ReadString(iter, r); |
+ } |
+ static void Log(const param_type& p, std::wstring* l) { |
+ l->append(UTF8ToWide(p)); |
+ } |
+}; |
+ |
+template <> |
+struct ParamTraits<std::vector<unsigned char> > { |
+ typedef std::vector<unsigned char> param_type; |
+ static void Write(Message* m, const param_type& p) { |
+ if (p.size() == 0) { |
+ m->WriteData(NULL, 0); |
+ } else { |
+ m->WriteData(reinterpret_cast<const char*>(&p.front()), |
+ static_cast<int>(p.size())); |
+ } |
+ } |
+ static bool Read(const Message* m, void** iter, param_type* r) { |
+ const char *data; |
+ int data_size = 0; |
+ if (!m->ReadData(iter, &data, &data_size) || data_size < 0) |
+ return false; |
+ r->resize(data_size); |
+ if (data_size) |
+ memcpy(&r->front(), data, data_size); |
+ return true; |
+ } |
+ static void Log(const param_type& p, std::wstring* l) { |
+ for (size_t i = 0; i < p.size(); ++i) |
+ l->push_back(p[i]); |
+ } |
+}; |
+ |
+template <> |
+struct ParamTraits<std::vector<char> > { |
+ typedef std::vector<char> param_type; |
+ static void Write(Message* m, const param_type& p) { |
+ if (p.size() == 0) { |
+ m->WriteData(NULL, 0); |
+ } else { |
+ m->WriteData(&p.front(), static_cast<int>(p.size())); |
+ } |
+ } |
+ static bool Read(const Message* m, void** iter, param_type* r) { |
+ const char *data; |
+ int data_size = 0; |
+ if (!m->ReadData(iter, &data, &data_size) || data_size < 0) |
+ return false; |
+ r->resize(data_size); |
+ if (data_size) |
+ memcpy(&r->front(), data, data_size); |
+ return true; |
+ } |
+ static void Log(const param_type& p, std::wstring* l) { |
+ for (size_t i = 0; i < p.size(); ++i) |
+ l->push_back(p[i]); |
+ } |
+}; |
+ |
+template <class P> |
+struct ParamTraits<std::vector<P> > { |
+ typedef std::vector<P> param_type; |
+ static void Write(Message* m, const param_type& p) { |
+ WriteParam(m, static_cast<int>(p.size())); |
+ for (size_t i = 0; i < p.size(); i++) |
+ WriteParam(m, p[i]); |
+ } |
+ static bool Read(const Message* m, void** iter, param_type* r) { |
+ int size; |
+ if (!m->ReadLength(iter, &size)) |
+ return false; |
+ // Resizing beforehand is not safe, see BUG 1006367 for details. |
+ if (m->IteratorHasRoomFor(*iter, size * sizeof(P))) { |
+ r->resize(size); |
+ for (int i = 0; i < size; i++) { |
+ if (!ReadParam(m, iter, &(*r)[i])) |
+ return false; |
+ } |
+ } else { |
+ for (int i = 0; i < size; i++) { |
+ P element; |
+ if (!ReadParam(m, iter, &element)) |
+ return false; |
+ r->push_back(element); |
+ } |
+ } |
+ return true; |
+ } |
+ static void Log(const param_type& p, std::wstring* l) { |
+ for (size_t i = 0; i < p.size(); ++i) { |
+ if (i != 0) |
+ l->append(L" "); |
+ |
+ LogParam((p[i]), l); |
+ } |
+ } |
+}; |
+ |
+template <class K, class V> |
+struct ParamTraits<std::map<K, V> > { |
+ typedef std::map<K, V> param_type; |
+ static void Write(Message* m, const param_type& p) { |
+ WriteParam(m, static_cast<int>(p.size())); |
+ typename param_type::const_iterator iter; |
+ for (iter = p.begin(); iter != p.end(); ++iter) { |
+ WriteParam(m, iter->first); |
+ WriteParam(m, iter->second); |
+ } |
+ } |
+ static bool Read(const Message* m, void** iter, param_type* r) { |
+ int size; |
+ if (!ReadParam(m, iter, &size) || size < 0) |
+ return false; |
+ for (int i = 0; i < size; ++i) { |
+ K k; |
+ if (!ReadParam(m, iter, &k)) |
+ return false; |
+ V& value = (*r)[k]; |
+ if (!ReadParam(m, iter, &value)) |
+ return false; |
+ } |
+ return true; |
+ } |
+ static void Log(const param_type& p, std::wstring* l) { |
+ l->append(L"<std::map>"); |
+ } |
+}; |
+ |
+ |
+template <> |
+struct ParamTraits<std::wstring> { |
+ typedef std::wstring param_type; |
+ static void Write(Message* m, const param_type& p) { |
+ m->WriteWString(p); |
+ } |
+ static bool Read(const Message* m, void** iter, param_type* r) { |
+ return m->ReadWString(iter, r); |
+ } |
+ static void Log(const param_type& p, std::wstring* l) { |
+ l->append(p); |
+ } |
+}; |
+ |
+// If WCHAR_T_IS_UTF16 is defined, then string16 is a std::wstring so we don't |
+// need this trait. |
+#if !defined(WCHAR_T_IS_UTF16) |
+template <> |
+struct ParamTraits<string16> { |
+ typedef string16 param_type; |
+ static void Write(Message* m, const param_type& p) { |
+ m->WriteString16(p); |
+ } |
+ static bool Read(const Message* m, void** iter, param_type* r) { |
+ return m->ReadString16(iter, r); |
+ } |
+ static void Log(const param_type& p, std::wstring* l) { |
+ l->append(UTF16ToWide(p)); |
+ } |
+}; |
+#endif |
+ |
+// and, a few more useful types... |
+#if defined(OS_WIN) |
+template <> |
+struct ParamTraits<HANDLE> { |
+ typedef HANDLE param_type; |
+ static void Write(Message* m, const param_type& p) { |
+ m->WriteIntPtr(reinterpret_cast<intptr_t>(p)); |
+ } |
+ static bool Read(const Message* m, void** iter, param_type* r) { |
+ DCHECK_EQ(sizeof(param_type), sizeof(intptr_t)); |
+ return m->ReadIntPtr(iter, reinterpret_cast<intptr_t*>(r)); |
+ } |
+ static void Log(const param_type& p, std::wstring* l) { |
+ l->append(StringPrintf(L"0x%X", p)); |
+ } |
+}; |
+ |
+template <> |
+struct ParamTraits<HCURSOR> { |
+ typedef HCURSOR param_type; |
+ static void Write(Message* m, const param_type& p) { |
+ m->WriteIntPtr(reinterpret_cast<intptr_t>(p)); |
+ } |
+ static bool Read(const Message* m, void** iter, param_type* r) { |
+ DCHECK_EQ(sizeof(param_type), sizeof(intptr_t)); |
+ return m->ReadIntPtr(iter, reinterpret_cast<intptr_t*>(r)); |
+ } |
+ static void Log(const param_type& p, std::wstring* l) { |
+ l->append(StringPrintf(L"0x%X", p)); |
+ } |
+}; |
+ |
+template <> |
+struct ParamTraits<HACCEL> { |
+ typedef HACCEL param_type; |
+ static void Write(Message* m, const param_type& p) { |
+ m->WriteIntPtr(reinterpret_cast<intptr_t>(p)); |
+ } |
+ static bool Read(const Message* m, void** iter, param_type* r) { |
+ DCHECK_EQ(sizeof(param_type), sizeof(intptr_t)); |
+ return m->ReadIntPtr(iter, reinterpret_cast<intptr_t*>(r)); |
+ } |
+}; |
+ |
+template <> |
+struct ParamTraits<POINT> { |
+ typedef POINT param_type; |
+ static void Write(Message* m, const param_type& p) { |
+ m->WriteInt(p.x); |
+ m->WriteInt(p.y); |
+ } |
+ static bool Read(const Message* m, void** iter, param_type* r) { |
+ int x, y; |
+ if (!m->ReadInt(iter, &x) || !m->ReadInt(iter, &y)) |
+ return false; |
+ r->x = x; |
+ r->y = y; |
+ return true; |
+ } |
+ static void Log(const param_type& p, std::wstring* l) { |
+ l->append(StringPrintf(L"(%d, %d)", p.x, p.y)); |
+ } |
+}; |
+#endif // defined(OS_WIN) |
+ |
+template <> |
+struct ParamTraits<FilePath> { |
+ typedef FilePath param_type; |
+ static void Write(Message* m, const param_type& p) { |
+ ParamTraits<FilePath::StringType>::Write(m, p.value()); |
+ } |
+ static bool Read(const Message* m, void** iter, param_type* r) { |
+ FilePath::StringType value; |
+ if (!ParamTraits<FilePath::StringType>::Read(m, iter, &value)) |
+ return false; |
+ *r = FilePath(value); |
+ return true; |
+ } |
+ static void Log(const param_type& p, std::wstring* l) { |
+ ParamTraits<FilePath::StringType>::Log(p.value(), l); |
+ } |
+}; |
+ |
+#if defined(OS_POSIX) |
+// FileDescriptors may be serialised over IPC channels on POSIX. On the |
+// receiving side, the FileDescriptor is a valid duplicate of the file |
+// descriptor which was transmitted: *it is not just a copy of the integer like |
+// HANDLEs on Windows*. The only exception is if the file descriptor is < 0. In |
+// this case, the receiving end will see a value of -1. *Zero is a valid file |
+// descriptor*. |
+// |
+// The received file descriptor will have the |auto_close| flag set to true. The |
+// code which handles the message is responsible for taking ownership of it. |
+// File descriptors are OS resources and must be closed when no longer needed. |
+// |
+// When sending a file descriptor, the file descriptor must be valid at the time |
+// of transmission. Since transmission is not synchronous, one should consider |
+// dup()ing any file descriptors to be transmitted and setting the |auto_close| |
+// flag, which causes the file descriptor to be closed after writing. |
+template<> |
+struct ParamTraits<base::FileDescriptor> { |
+ typedef base::FileDescriptor param_type; |
+ static void Write(Message* m, const param_type& p) { |
+ const bool valid = p.fd >= 0; |
+ WriteParam(m, valid); |
+ |
+ if (valid) { |
+ if (!m->WriteFileDescriptor(p)) |
+ NOTREACHED(); |
+ } |
+ } |
+ static bool Read(const Message* m, void** iter, param_type* r) { |
+ bool valid; |
+ if (!ReadParam(m, iter, &valid)) |
+ return false; |
+ |
+ if (!valid) { |
+ r->fd = -1; |
+ r->auto_close = false; |
+ return true; |
+ } |
+ |
+ return m->ReadFileDescriptor(iter, r); |
+ } |
+ static void Log(const param_type& p, std::wstring* l) { |
+ if (p.auto_close) { |
+ l->append(StringPrintf(L"FD(%d auto-close)", p.fd)); |
+ } else { |
+ l->append(StringPrintf(L"FD(%d)", p.fd)); |
+ } |
+ } |
+}; |
+#endif // defined(OS_POSIX) |
+ |
+// A ChannelHandle is basically a platform-inspecific wrapper around the |
+// fact that IPC endpoints are handled specially on POSIX. See above comments |
+// on FileDescriptor for more background. |
+template<> |
+struct ParamTraits<IPC::ChannelHandle> { |
+ typedef ChannelHandle param_type; |
+ static void Write(Message* m, const param_type& p) { |
+ WriteParam(m, p.name); |
+#if defined(OS_POSIX) |
+ WriteParam(m, p.socket); |
+#endif |
+ } |
+ static bool Read(const Message* m, void** iter, param_type* r) { |
+ return ReadParam(m, iter, &r->name) |
+#if defined(OS_POSIX) |
+ && ReadParam(m, iter, &r->socket) |
+#endif |
+ ; |
+ } |
+ static void Log(const param_type& p, std::wstring* l) { |
+ l->append(ASCIIToWide(StringPrintf("ChannelHandle(%s", p.name.c_str()))); |
+#if defined(OS_POSIX) |
+ ParamTraits<base::FileDescriptor>::Log(p.socket, l); |
+#endif |
+ l->append(L")"); |
+ } |
+}; |
+ |
+#if defined(OS_WIN) |
+template <> |
+struct ParamTraits<XFORM> { |
+ typedef XFORM param_type; |
+ static void Write(Message* m, const param_type& p) { |
+ m->WriteData(reinterpret_cast<const char*>(&p), sizeof(XFORM)); |
+ } |
+ static bool Read(const Message* m, void** iter, param_type* r) { |
+ const char *data; |
+ int data_size = 0; |
+ bool result = m->ReadData(iter, &data, &data_size); |
+ if (result && data_size == sizeof(XFORM)) { |
+ memcpy(r, data, sizeof(XFORM)); |
+ } else { |
+ result = false; |
+ NOTREACHED(); |
+ } |
+ |
+ return result; |
+ } |
+ static void Log(const param_type& p, std::wstring* l) { |
+ l->append(L"<XFORM>"); |
+ } |
+}; |
+#endif // defined(OS_WIN) |
+ |
+struct LogData { |
+ std::string channel; |
+ int32 routing_id; |
+ uint16 type; |
+ std::wstring flags; |
+ int64 sent; // Time that the message was sent (i.e. at Send()). |
+ int64 receive; // Time before it was dispatched (i.e. before calling |
+ // OnMessageReceived). |
+ int64 dispatch; // Time after it was dispatched (i.e. after calling |
+ // OnMessageReceived). |
+ std::wstring message_name; |
+ std::wstring params; |
+}; |
+ |
+template <> |
+struct ParamTraits<LogData> { |
+ typedef LogData param_type; |
+ static void Write(Message* m, const param_type& p) { |
+ WriteParam(m, p.channel); |
+ WriteParam(m, p.routing_id); |
+ WriteParam(m, static_cast<int>(p.type)); |
+ WriteParam(m, p.flags); |
+ WriteParam(m, p.sent); |
+ WriteParam(m, p.receive); |
+ WriteParam(m, p.dispatch); |
+ WriteParam(m, p.params); |
+ } |
+ static bool Read(const Message* m, void** iter, param_type* r) { |
+ int type; |
+ bool result = |
+ ReadParam(m, iter, &r->channel) && |
+ ReadParam(m, iter, &r->routing_id); |
+ ReadParam(m, iter, &type) && |
+ ReadParam(m, iter, &r->flags) && |
+ ReadParam(m, iter, &r->sent) && |
+ ReadParam(m, iter, &r->receive) && |
+ ReadParam(m, iter, &r->dispatch) && |
+ ReadParam(m, iter, &r->params); |
+ r->type = static_cast<uint16>(type); |
+ return result; |
+ } |
+ static void Log(const param_type& p, std::wstring* l) { |
+ // Doesn't make sense to implement this! |
+ } |
+}; |
+ |
+ |
+template <> |
+struct ParamTraits<Message> { |
+ static void Write(Message* m, const Message& p) { |
+ m->WriteInt(p.size()); |
+ m->WriteData(reinterpret_cast<const char*>(p.data()), p.size()); |
+ } |
+ static bool Read(const Message* m, void** iter, Message* r) { |
+ int size; |
+ if (!m->ReadInt(iter, &size)) |
+ return false; |
+ const char* data; |
+ if (!m->ReadData(iter, &data, &size)) |
+ return false; |
+ *r = Message(data, size); |
+ return true; |
+ } |
+ static void Log(const Message& p, std::wstring* l) { |
+ l->append(L"<IPC::Message>"); |
+ } |
+}; |
+ |
+template <> |
+struct ParamTraits<Tuple0> { |
+ typedef Tuple0 param_type; |
+ static void Write(Message* m, const param_type& p) { |
+ } |
+ static bool Read(const Message* m, void** iter, param_type* r) { |
+ return true; |
+ } |
+ static void Log(const param_type& p, std::wstring* l) { |
+ } |
+}; |
+ |
+template <class A> |
+struct ParamTraits< Tuple1<A> > { |
+ typedef Tuple1<A> param_type; |
+ static void Write(Message* m, const param_type& p) { |
+ WriteParam(m, p.a); |
+ } |
+ static bool Read(const Message* m, void** iter, param_type* r) { |
+ return ReadParam(m, iter, &r->a); |
+ } |
+ static void Log(const param_type& p, std::wstring* l) { |
+ LogParam(p.a, l); |
+ } |
+}; |
+ |
+template <class A, class B> |
+struct ParamTraits< Tuple2<A, B> > { |
+ typedef Tuple2<A, B> param_type; |
+ static void Write(Message* m, const param_type& p) { |
+ WriteParam(m, p.a); |
+ WriteParam(m, p.b); |
+ } |
+ static bool Read(const Message* m, void** iter, param_type* r) { |
+ return (ReadParam(m, iter, &r->a) && |
+ ReadParam(m, iter, &r->b)); |
+ } |
+ static void Log(const param_type& p, std::wstring* l) { |
+ LogParam(p.a, l); |
+ l->append(L", "); |
+ LogParam(p.b, l); |
+ } |
+}; |
+ |
+template <class A, class B, class C> |
+struct ParamTraits< Tuple3<A, B, C> > { |
+ typedef Tuple3<A, B, C> param_type; |
+ static void Write(Message* m, const param_type& p) { |
+ WriteParam(m, p.a); |
+ WriteParam(m, p.b); |
+ WriteParam(m, p.c); |
+ } |
+ static bool Read(const Message* m, void** iter, param_type* r) { |
+ return (ReadParam(m, iter, &r->a) && |
+ ReadParam(m, iter, &r->b) && |
+ ReadParam(m, iter, &r->c)); |
+ } |
+ static void Log(const param_type& p, std::wstring* l) { |
+ LogParam(p.a, l); |
+ l->append(L", "); |
+ LogParam(p.b, l); |
+ l->append(L", "); |
+ LogParam(p.c, l); |
+ } |
+}; |
+ |
+template <class A, class B, class C, class D> |
+struct ParamTraits< Tuple4<A, B, C, D> > { |
+ typedef Tuple4<A, B, C, D> param_type; |
+ static void Write(Message* m, const param_type& p) { |
+ WriteParam(m, p.a); |
+ WriteParam(m, p.b); |
+ WriteParam(m, p.c); |
+ WriteParam(m, p.d); |
+ } |
+ static bool Read(const Message* m, void** iter, param_type* r) { |
+ return (ReadParam(m, iter, &r->a) && |
+ ReadParam(m, iter, &r->b) && |
+ ReadParam(m, iter, &r->c) && |
+ ReadParam(m, iter, &r->d)); |
+ } |
+ static void Log(const param_type& p, std::wstring* l) { |
+ LogParam(p.a, l); |
+ l->append(L", "); |
+ LogParam(p.b, l); |
+ l->append(L", "); |
+ LogParam(p.c, l); |
+ l->append(L", "); |
+ LogParam(p.d, l); |
+ } |
+}; |
+ |
+template <class A, class B, class C, class D, class E> |
+struct ParamTraits< Tuple5<A, B, C, D, E> > { |
+ typedef Tuple5<A, B, C, D, E> param_type; |
+ static void Write(Message* m, const param_type& p) { |
+ WriteParam(m, p.a); |
+ WriteParam(m, p.b); |
+ WriteParam(m, p.c); |
+ WriteParam(m, p.d); |
+ WriteParam(m, p.e); |
+ } |
+ static bool Read(const Message* m, void** iter, param_type* r) { |
+ return (ReadParam(m, iter, &r->a) && |
+ ReadParam(m, iter, &r->b) && |
+ ReadParam(m, iter, &r->c) && |
+ ReadParam(m, iter, &r->d) && |
+ ReadParam(m, iter, &r->e)); |
+ } |
+ static void Log(const param_type& p, std::wstring* l) { |
+ LogParam(p.a, l); |
+ l->append(L", "); |
+ LogParam(p.b, l); |
+ l->append(L", "); |
+ LogParam(p.c, l); |
+ l->append(L", "); |
+ LogParam(p.d, l); |
+ l->append(L", "); |
+ LogParam(p.e, l); |
+ } |
+}; |
+ |
+//----------------------------------------------------------------------------- |
+// Generic message subclasses |
+ |
+// Used for asynchronous messages. |
+template <class ParamType> |
+class MessageWithTuple : public Message { |
+ public: |
+ typedef ParamType Param; |
+ typedef typename ParamType::ParamTuple RefParam; |
+ |
+ MessageWithTuple(int32 routing_id, uint16 type, const RefParam& p) |
+ : Message(routing_id, type, PRIORITY_NORMAL) { |
+ WriteParam(this, p); |
+ } |
+ |
+ static bool Read(const Message* msg, Param* p) { |
+ void* iter = NULL; |
+ if (ReadParam(msg, &iter, p)) |
+ return true; |
+ NOTREACHED() << "Error deserializing message " << msg->type(); |
+ return false; |
+ } |
+ |
+ // Generic dispatcher. Should cover most cases. |
+ template<class T, class Method> |
+ static bool Dispatch(const Message* msg, T* obj, Method func) { |
+ Param p; |
+ if (Read(msg, &p)) { |
+ DispatchToMethod(obj, func, p); |
+ return true; |
+ } |
+ return false; |
+ } |
+ |
+ // The following dispatchers exist for the case where the callback function |
+ // needs the message as well. They assume that "Param" is a type of Tuple |
+ // (except the one arg case, as there is no Tuple1). |
+ template<class T, typename TA> |
+ static bool Dispatch(const Message* msg, T* obj, |
+ void (T::*func)(const Message&, TA)) { |
+ Param p; |
+ if (Read(msg, &p)) { |
+ (obj->*func)(*msg, p.a); |
+ return true; |
+ } |
+ return false; |
+ } |
+ |
+ template<class T, typename TA, typename TB> |
+ static bool Dispatch(const Message* msg, T* obj, |
+ void (T::*func)(const Message&, TA, TB)) { |
+ Param p; |
+ if (Read(msg, &p)) { |
+ (obj->*func)(*msg, p.a, p.b); |
+ return true; |
+ } |
+ return false; |
+ } |
+ |
+ template<class T, typename TA, typename TB, typename TC> |
+ static bool Dispatch(const Message* msg, T* obj, |
+ void (T::*func)(const Message&, TA, TB, TC)) { |
+ Param p; |
+ if (Read(msg, &p)) { |
+ (obj->*func)(*msg, p.a, p.b, p.c); |
+ return true; |
+ } |
+ return false; |
+ } |
+ |
+ template<class T, typename TA, typename TB, typename TC, typename TD> |
+ static bool Dispatch(const Message* msg, T* obj, |
+ void (T::*func)(const Message&, TA, TB, TC, TD)) { |
+ Param p; |
+ if (Read(msg, &p)) { |
+ (obj->*func)(*msg, p.a, p.b, p.c, p.d); |
+ return true; |
+ } |
+ return false; |
+ } |
+ |
+ template<class T, typename TA, typename TB, typename TC, typename TD, |
+ typename TE> |
+ static bool Dispatch(const Message* msg, T* obj, |
+ void (T::*func)(const Message&, TA, TB, TC, TD, TE)) { |
+ Param p; |
+ if (Read(msg, &p)) { |
+ (obj->*func)(*msg, p.a, p.b, p.c, p.d, p.e); |
+ return true; |
+ } |
+ return false; |
+ } |
+ |
+ static void Log(const Message* msg, std::wstring* l) { |
+ Param p; |
+ if (Read(msg, &p)) |
+ LogParam(p, l); |
+ } |
+ |
+ // Functions used to do manual unpacking. Only used by the automation code, |
+ // these should go away once that code uses SyncChannel. |
+ template<typename TA, typename TB> |
+ static bool Read(const IPC::Message* msg, TA* a, TB* b) { |
+ ParamType params; |
+ if (!Read(msg, ¶ms)) |
+ return false; |
+ *a = params.a; |
+ *b = params.b; |
+ return true; |
+ } |
+ |
+ template<typename TA, typename TB, typename TC> |
+ static bool Read(const IPC::Message* msg, TA* a, TB* b, TC* c) { |
+ ParamType params; |
+ if (!Read(msg, ¶ms)) |
+ return false; |
+ *a = params.a; |
+ *b = params.b; |
+ *c = params.c; |
+ return true; |
+ } |
+ |
+ template<typename TA, typename TB, typename TC, typename TD> |
+ static bool Read(const IPC::Message* msg, TA* a, TB* b, TC* c, TD* d) { |
+ ParamType params; |
+ if (!Read(msg, ¶ms)) |
+ return false; |
+ *a = params.a; |
+ *b = params.b; |
+ *c = params.c; |
+ *d = params.d; |
+ return true; |
+ } |
+ |
+ template<typename TA, typename TB, typename TC, typename TD, typename TE> |
+ static bool Read(const IPC::Message* msg, TA* a, TB* b, TC* c, TD* d, TE* e) { |
+ ParamType params; |
+ if (!Read(msg, ¶ms)) |
+ return false; |
+ *a = params.a; |
+ *b = params.b; |
+ *c = params.c; |
+ *d = params.d; |
+ *e = params.e; |
+ return true; |
+ } |
+}; |
+ |
+// This class assumes that its template argument is a RefTuple (a Tuple with |
+// reference elements). |
+template <class RefTuple> |
+class ParamDeserializer : public MessageReplyDeserializer { |
+ public: |
+ explicit ParamDeserializer(const RefTuple& out) : out_(out) { } |
+ |
+ bool SerializeOutputParameters(const IPC::Message& msg, void* iter) { |
+ return ReadParam(&msg, &iter, &out_); |
+ } |
+ |
+ RefTuple out_; |
+}; |
+ |
+// defined in ipc_logging.cc |
+void GenerateLogData(const std::string& channel, const Message& message, |
+ LogData* data); |
+ |
+// Used for synchronous messages. |
+template <class SendParamType, class ReplyParamType> |
+class MessageWithReply : public SyncMessage { |
+ public: |
+ typedef SendParamType SendParam; |
+ typedef typename SendParam::ParamTuple RefSendParam; |
+ typedef ReplyParamType ReplyParam; |
+ |
+ MessageWithReply(int32 routing_id, uint16 type, |
+ const RefSendParam& send, const ReplyParam& reply) |
+ : SyncMessage(routing_id, type, PRIORITY_NORMAL, |
+ new ParamDeserializer<ReplyParam>(reply)) { |
+ WriteParam(this, send); |
+ } |
+ |
+ static void Log(const Message* msg, std::wstring* l) { |
+ if (msg->is_sync()) { |
+ SendParam p; |
+ void* iter = SyncMessage::GetDataIterator(msg); |
+ if (ReadParam(msg, &iter, &p)) |
+ LogParam(p, l); |
+ |
+#if defined(IPC_MESSAGE_LOG_ENABLED) |
+ const std::wstring& output_params = msg->output_params(); |
+ if (!l->empty() && !output_params.empty()) |
+ l->append(L", "); |
+ |
+ l->append(output_params); |
+#endif |
+ } else { |
+ // This is an outgoing reply. Now that we have the output parameters, we |
+ // can finally log the message. |
+ typename ReplyParam::ValueTuple p; |
+ void* iter = SyncMessage::GetDataIterator(msg); |
+ if (ReadParam(msg, &iter, &p)) |
+ LogParam(p, l); |
+ } |
+ } |
+ |
+ template<class T, class Method> |
+ static bool Dispatch(const Message* msg, T* obj, Method func) { |
+ SendParam send_params; |
+ void* iter = GetDataIterator(msg); |
+ Message* reply = GenerateReply(msg); |
+ bool error; |
+ if (ReadParam(msg, &iter, &send_params)) { |
+ typename ReplyParam::ValueTuple reply_params; |
+ DispatchToMethod(obj, func, send_params, &reply_params); |
+ WriteParam(reply, reply_params); |
+ error = false; |
+#ifdef IPC_MESSAGE_LOG_ENABLED |
+ if (msg->received_time() != 0) { |
+ std::wstring output_params; |
+ LogParam(reply_params, &output_params); |
+ msg->set_output_params(output_params); |
+ } |
+#endif |
+ } else { |
+ NOTREACHED() << "Error deserializing message " << msg->type(); |
+ reply->set_reply_error(); |
+ error = true; |
+ } |
+ |
+ obj->Send(reply); |
+ return !error; |
+ } |
+ |
+ template<class T, class Method> |
+ static bool DispatchDelayReply(const Message* msg, T* obj, Method func) { |
+ SendParam send_params; |
+ void* iter = GetDataIterator(msg); |
+ Message* reply = GenerateReply(msg); |
+ bool error; |
+ if (ReadParam(msg, &iter, &send_params)) { |
+ Tuple1<Message&> t = MakeRefTuple(*reply); |
+ |
+#ifdef IPC_MESSAGE_LOG_ENABLED |
+ if (msg->sent_time()) { |
+ // Don't log the sync message after dispatch, as we don't have the |
+ // output parameters at that point. Instead, save its data and log it |
+ // with the outgoing reply message when it's sent. |
+ LogData* data = new LogData; |
+ GenerateLogData("", *msg, data); |
+ msg->set_dont_log(); |
+ reply->set_sync_log_data(data); |
+ } |
+#endif |
+ DispatchToMethod(obj, func, send_params, &t); |
+ error = false; |
+ } else { |
+ NOTREACHED() << "Error deserializing message " << msg->type(); |
+ reply->set_reply_error(); |
+ obj->Send(reply); |
+ error = true; |
+ } |
+ return !error; |
+ } |
+ |
+ template<typename TA> |
+ static void WriteReplyParams(Message* reply, TA a) { |
+ ReplyParam p(a); |
+ WriteParam(reply, p); |
+ } |
+ |
+ template<typename TA, typename TB> |
+ static void WriteReplyParams(Message* reply, TA a, TB b) { |
+ ReplyParam p(a, b); |
+ WriteParam(reply, p); |
+ } |
+ |
+ template<typename TA, typename TB, typename TC> |
+ static void WriteReplyParams(Message* reply, TA a, TB b, TC c) { |
+ ReplyParam p(a, b, c); |
+ WriteParam(reply, p); |
+ } |
+ |
+ template<typename TA, typename TB, typename TC, typename TD> |
+ static void WriteReplyParams(Message* reply, TA a, TB b, TC c, TD d) { |
+ ReplyParam p(a, b, c, d); |
+ WriteParam(reply, p); |
+ } |
+ |
+ template<typename TA, typename TB, typename TC, typename TD, typename TE> |
+ static void WriteReplyParams(Message* reply, TA a, TB b, TC c, TD d, TE e) { |
+ ReplyParam p(a, b, c, d, e); |
+ WriteParam(reply, p); |
+ } |
+}; |
+ |
+//----------------------------------------------------------------------------- |
+ |
+} // namespace IPC |
+ |
+#endif // IPC_IPC_MESSAGE_UTILS_H_ |