michael@0: // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. michael@0: // Use of this source code is governed by a BSD-style license that can be michael@0: // found in the LICENSE file. michael@0: michael@0: #ifndef CHROME_COMMON_IPC_MESSAGE_UTILS_H_ michael@0: #define CHROME_COMMON_IPC_MESSAGE_UTILS_H_ michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: #include "base/file_path.h" michael@0: #include "base/string_util.h" michael@0: #include "base/string16.h" michael@0: #include "base/tuple.h" michael@0: #include "base/time.h" michael@0: michael@0: #if defined(OS_POSIX) michael@0: #include "chrome/common/file_descriptor_set_posix.h" michael@0: #endif michael@0: #include "chrome/common/ipc_sync_message.h" michael@0: #include "chrome/common/transport_dib.h" michael@0: michael@0: namespace IPC { michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: // An iterator class for reading the fields contained within a Message. michael@0: michael@0: class MessageIterator { michael@0: public: michael@0: explicit MessageIterator(const Message& m) : msg_(m), iter_(NULL) { michael@0: } michael@0: int NextInt() const { michael@0: int val; michael@0: if (!msg_.ReadInt(&iter_, &val)) michael@0: NOTREACHED(); michael@0: return val; michael@0: } michael@0: intptr_t NextIntPtr() const { michael@0: intptr_t val; michael@0: if (!msg_.ReadIntPtr(&iter_, &val)) michael@0: NOTREACHED(); michael@0: return val; michael@0: } michael@0: const std::string NextString() const { michael@0: std::string val; michael@0: if (!msg_.ReadString(&iter_, &val)) michael@0: NOTREACHED(); michael@0: return val; michael@0: } michael@0: const std::wstring NextWString() const { michael@0: std::wstring val; michael@0: if (!msg_.ReadWString(&iter_, &val)) michael@0: NOTREACHED(); michael@0: return val; michael@0: } michael@0: const void NextData(const char** data, int* length) const { michael@0: if (!msg_.ReadData(&iter_, data, length)) { michael@0: NOTREACHED(); michael@0: } michael@0: } michael@0: private: michael@0: const Message& msg_; michael@0: mutable void* iter_; michael@0: }; michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: // ParamTraits specializations, etc. michael@0: // michael@0: // The full set of types ParamTraits is specialized upon contains *possibly* michael@0: // repeated types: unsigned long may be uint32_t or size_t, unsigned long long michael@0: // may be uint64_t or size_t, nsresult may be uint32_t, and so on. You can't michael@0: // have ParamTraits *and* ParamTraits if unsigned int michael@0: // is uint32_t -- that's multiple definitions, and you can only have one. michael@0: // michael@0: // You could use #ifs and macro conditions to avoid duplicates, but they'd be michael@0: // hairy: heavily dependent upon OS and compiler author choices, forced to michael@0: // address all conflicts by hand. Happily there's a better way. The basic michael@0: // idea looks like this, where T -> U represents T inheriting from U: michael@0: // michael@0: // class ParamTraits

michael@0: // | michael@0: // --> class ParamTraits1

michael@0: // | michael@0: // --> class ParamTraits2

michael@0: // | michael@0: // --> class ParamTraitsN

// or however many levels michael@0: // michael@0: // The default specialization of ParamTraits{M}

is an empty class that michael@0: // inherits from ParamTraits{M + 1}

(or nothing in the base case). michael@0: // michael@0: // Now partition the set of parameter types into sets without duplicates. michael@0: // Assign each set of types to a level M. Then specialize ParamTraitsM for michael@0: // each of those types. A reference to ParamTraits

will consist of some michael@0: // number of empty classes inheriting in sequence, ending in a non-empty michael@0: // ParamTraits{N}

. It's okay for the parameter types to be duplicative: michael@0: // either name of a type will resolve to the same ParamTraits{N}

. michael@0: // michael@0: // The nice thing is that because templates are instantiated lazily, if we michael@0: // indeed have uint32_t == unsigned int, say, with the former in level N and michael@0: // the latter in M > N, ParamTraitsM won't be created (as long as michael@0: // nobody uses ParamTraitsM, but why would you), and no duplicate michael@0: // code will be compiled or extra symbols generated. It's as efficient at michael@0: // runtime as manually figuring out and avoiding conflicts by #ifs. michael@0: // michael@0: // The scheme we follow below names the various classes according to the types michael@0: // in them, and the number of ParamTraits levels is larger, but otherwise it's michael@0: // exactly the above idea. michael@0: // michael@0: michael@0: template struct ParamTraits; michael@0: michael@0: template michael@0: static inline void WriteParam(Message* m, const P& p) { michael@0: ParamTraits

::Write(m, p); michael@0: } michael@0: michael@0: template michael@0: static inline bool WARN_UNUSED_RESULT ReadParam(const Message* m, void** iter, michael@0: P* p) { michael@0: return ParamTraits

::Read(m, iter, p); michael@0: } michael@0: michael@0: template michael@0: static inline void LogParam(const P& p, std::wstring* l) { michael@0: ParamTraits

::Log(p, l); michael@0: } michael@0: michael@0: // Fundamental types. michael@0: michael@0: template michael@0: struct ParamTraitsFundamental {}; michael@0: michael@0: template <> michael@0: struct ParamTraitsFundamental { michael@0: typedef bool param_type; michael@0: static void Write(Message* m, const param_type& p) { michael@0: m->WriteBool(p); michael@0: } michael@0: static bool Read(const Message* m, void** iter, param_type* r) { michael@0: return m->ReadBool(iter, r); michael@0: } michael@0: static void Log(const param_type& p, std::wstring* l) { michael@0: l->append(p ? L"true" : L"false"); michael@0: } michael@0: }; michael@0: michael@0: template <> michael@0: struct ParamTraitsFundamental { michael@0: typedef int param_type; michael@0: static void Write(Message* m, const param_type& p) { michael@0: m->WriteInt(p); michael@0: } michael@0: static bool Read(const Message* m, void** iter, param_type* r) { michael@0: return m->ReadInt(iter, r); michael@0: } michael@0: static void Log(const param_type& p, std::wstring* l) { michael@0: l->append(StringPrintf(L"%d", p)); michael@0: } michael@0: }; michael@0: michael@0: template <> michael@0: struct ParamTraitsFundamental { michael@0: typedef long param_type; michael@0: static void Write(Message* m, const param_type& p) { michael@0: m->WriteLong(p); michael@0: } michael@0: static bool Read(const Message* m, void** iter, param_type* r) { michael@0: return m->ReadLong(iter, r); michael@0: } michael@0: static void Log(const param_type& p, std::wstring* l) { michael@0: l->append(StringPrintf(L"%l", p)); michael@0: } michael@0: }; michael@0: michael@0: template <> michael@0: struct ParamTraitsFundamental { michael@0: typedef unsigned long param_type; michael@0: static void Write(Message* m, const param_type& p) { michael@0: m->WriteULong(p); michael@0: } michael@0: static bool Read(const Message* m, void** iter, param_type* r) { michael@0: return m->ReadULong(iter, r); michael@0: } michael@0: static void Log(const param_type& p, std::wstring* l) { michael@0: l->append(StringPrintf(L"%ul", p)); michael@0: } michael@0: }; michael@0: michael@0: template <> michael@0: struct ParamTraitsFundamental { michael@0: typedef long long param_type; michael@0: static void Write(Message* m, const param_type& p) { michael@0: m->WriteData(reinterpret_cast(&p), sizeof(param_type)); michael@0: } michael@0: static bool Read(const Message* m, void** iter, param_type* r) { michael@0: const char *data; michael@0: int data_size = 0; michael@0: bool result = m->ReadData(iter, &data, &data_size); michael@0: if (result && data_size == sizeof(param_type)) { michael@0: memcpy(r, data, sizeof(param_type)); michael@0: } else { michael@0: result = false; michael@0: NOTREACHED(); michael@0: } michael@0: return result; michael@0: } michael@0: static void Log(const param_type& p, std::wstring* l) { michael@0: l->append(StringPrintf(L"%ll", p)); michael@0: } michael@0: }; michael@0: michael@0: template <> michael@0: struct ParamTraitsFundamental { michael@0: typedef unsigned long long param_type; michael@0: static void Write(Message* m, const param_type& p) { michael@0: m->WriteData(reinterpret_cast(&p), sizeof(param_type)); michael@0: } michael@0: static bool Read(const Message* m, void** iter, param_type* r) { michael@0: const char *data; michael@0: int data_size = 0; michael@0: bool result = m->ReadData(iter, &data, &data_size); michael@0: if (result && data_size == sizeof(param_type)) { michael@0: memcpy(r, data, sizeof(param_type)); michael@0: } else { michael@0: result = false; michael@0: NOTREACHED(); michael@0: } michael@0: return result; michael@0: } michael@0: static void Log(const param_type& p, std::wstring* l) { michael@0: l->append(StringPrintf(L"%ull", p)); michael@0: } michael@0: }; michael@0: michael@0: template <> michael@0: struct ParamTraitsFundamental { michael@0: typedef double param_type; michael@0: static void Write(Message* m, const param_type& p) { michael@0: m->WriteData(reinterpret_cast(&p), sizeof(param_type)); michael@0: } michael@0: static bool Read(const Message* m, void** iter, param_type* r) { michael@0: const char *data; michael@0: int data_size = 0; michael@0: bool result = m->ReadData(iter, &data, &data_size); michael@0: if (result && data_size == sizeof(param_type)) { michael@0: memcpy(r, data, sizeof(param_type)); michael@0: } else { michael@0: result = false; michael@0: NOTREACHED(); michael@0: } michael@0: michael@0: return result; michael@0: } michael@0: static void Log(const param_type& p, std::wstring* l) { michael@0: l->append(StringPrintf(L"e", p)); michael@0: } michael@0: }; michael@0: michael@0: // Fixed-size types. michael@0: michael@0: template michael@0: struct ParamTraitsFixed : ParamTraitsFundamental

{}; michael@0: michael@0: template <> michael@0: struct ParamTraitsFixed { michael@0: typedef int16_t param_type; michael@0: static void Write(Message* m, const param_type& p) { michael@0: m->WriteInt16(p); michael@0: } michael@0: static bool Read(const Message* m, void** iter, param_type* r) { michael@0: return m->ReadInt16(iter, r); michael@0: } michael@0: static void Log(const param_type& p, std::wstring* l) { michael@0: l->append(StringPrintf(L"%hd", p)); michael@0: } michael@0: }; michael@0: michael@0: template <> michael@0: struct ParamTraitsFixed { michael@0: typedef uint16_t param_type; michael@0: static void Write(Message* m, const param_type& p) { michael@0: m->WriteUInt16(p); michael@0: } michael@0: static bool Read(const Message* m, void** iter, param_type* r) { michael@0: return m->ReadUInt16(iter, r); michael@0: } michael@0: static void Log(const param_type& p, std::wstring* l) { michael@0: l->append(StringPrintf(L"%hu", p)); michael@0: } michael@0: }; michael@0: michael@0: template <> michael@0: struct ParamTraitsFixed { michael@0: typedef uint32_t param_type; michael@0: static void Write(Message* m, const param_type& p) { michael@0: m->WriteUInt32(p); michael@0: } michael@0: static bool Read(const Message* m, void** iter, param_type* r) { michael@0: return m->ReadUInt32(iter, r); michael@0: } michael@0: static void Log(const param_type& p, std::wstring* l) { michael@0: l->append(StringPrintf(L"%u", p)); michael@0: } michael@0: }; michael@0: michael@0: template <> michael@0: struct ParamTraitsFixed { michael@0: typedef int64_t param_type; michael@0: static void Write(Message* m, const param_type& p) { michael@0: m->WriteInt64(p); michael@0: } michael@0: static bool Read(const Message* m, void** iter, param_type* r) { michael@0: return m->ReadInt64(iter, r); michael@0: } michael@0: static void Log(const param_type& p, std::wstring* l) { michael@0: l->append(StringPrintf(L"%" PRId64L, p)); michael@0: } michael@0: }; michael@0: michael@0: template <> michael@0: struct ParamTraitsFixed { michael@0: typedef uint64_t param_type; michael@0: static void Write(Message* m, const param_type& p) { michael@0: m->WriteInt64(static_cast(p)); michael@0: } michael@0: static bool Read(const Message* m, void** iter, param_type* r) { michael@0: return m->ReadInt64(iter, reinterpret_cast(r)); michael@0: } michael@0: static void Log(const param_type& p, std::wstring* l) { michael@0: l->append(StringPrintf(L"%" PRIu64L, p)); michael@0: } michael@0: }; michael@0: michael@0: // Other standard C types. michael@0: michael@0: template michael@0: struct ParamTraitsLibC : ParamTraitsFixed

{}; michael@0: michael@0: template <> michael@0: struct ParamTraitsLibC { michael@0: typedef size_t param_type; michael@0: static void Write(Message* m, const param_type& p) { michael@0: m->WriteSize(p); michael@0: } michael@0: static bool Read(const Message* m, void** iter, param_type* r) { michael@0: return m->ReadSize(iter, r); michael@0: } michael@0: static void Log(const param_type& p, std::wstring* l) { michael@0: l->append(StringPrintf(L"%u", p)); michael@0: } michael@0: }; michael@0: michael@0: // std::* types. michael@0: michael@0: template michael@0: struct ParamTraitsStd : ParamTraitsLibC

{}; michael@0: michael@0: template <> michael@0: struct ParamTraitsStd { michael@0: typedef std::string param_type; michael@0: static void Write(Message* m, const param_type& p) { michael@0: m->WriteString(p); michael@0: } michael@0: static bool Read(const Message* m, void** iter, param_type* r) { michael@0: return m->ReadString(iter, r); michael@0: } michael@0: static void Log(const param_type& p, std::wstring* l) { michael@0: l->append(UTF8ToWide(p)); michael@0: } michael@0: }; michael@0: michael@0: template <> michael@0: struct ParamTraitsStd { michael@0: typedef std::wstring param_type; michael@0: static void Write(Message* m, const param_type& p) { michael@0: m->WriteWString(p); michael@0: } michael@0: static bool Read(const Message* m, void** iter, param_type* r) { michael@0: return m->ReadWString(iter, r); michael@0: } michael@0: static void Log(const param_type& p, std::wstring* l) { michael@0: l->append(p); michael@0: } michael@0: }; michael@0: michael@0: template <> michael@0: struct ParamTraitsStd > { michael@0: typedef std::vector param_type; michael@0: static void Write(Message* m, const param_type& p) { michael@0: if (p.size() == 0) { michael@0: m->WriteData(NULL, 0); michael@0: } else { michael@0: m->WriteData(reinterpret_cast(&p.front()), michael@0: static_cast(p.size())); michael@0: } michael@0: } michael@0: static bool Read(const Message* m, void** iter, param_type* r) { michael@0: const char *data; michael@0: int data_size = 0; michael@0: if (!m->ReadData(iter, &data, &data_size) || data_size < 0) michael@0: return false; michael@0: r->resize(data_size); michael@0: if (data_size) michael@0: memcpy(&r->front(), data, data_size); michael@0: return true; michael@0: } michael@0: static void Log(const param_type& p, std::wstring* l) { michael@0: for (size_t i = 0; i < p.size(); ++i) michael@0: l->push_back(p[i]); michael@0: } michael@0: }; michael@0: michael@0: template <> michael@0: struct ParamTraitsStd > { michael@0: typedef std::vector param_type; michael@0: static void Write(Message* m, const param_type& p) { michael@0: if (p.size() == 0) { michael@0: m->WriteData(NULL, 0); michael@0: } else { michael@0: m->WriteData(&p.front(), static_cast(p.size())); michael@0: } michael@0: } michael@0: static bool Read(const Message* m, void** iter, param_type* r) { michael@0: const char *data; michael@0: int data_size = 0; michael@0: if (!m->ReadData(iter, &data, &data_size) || data_size < 0) michael@0: return false; michael@0: r->resize(data_size); michael@0: if (data_size) michael@0: memcpy(&r->front(), data, data_size); michael@0: return true; michael@0: } michael@0: static void Log(const param_type& p, std::wstring* l) { michael@0: for (size_t i = 0; i < p.size(); ++i) michael@0: l->push_back(p[i]); michael@0: } michael@0: }; michael@0: michael@0: template michael@0: struct ParamTraitsStd > { michael@0: typedef std::vector

param_type; michael@0: static void Write(Message* m, const param_type& p) { michael@0: WriteParam(m, static_cast(p.size())); michael@0: for (size_t i = 0; i < p.size(); i++) michael@0: WriteParam(m, p[i]); michael@0: } michael@0: static bool Read(const Message* m, void** iter, param_type* r) { michael@0: int size; michael@0: if (!m->ReadLength(iter, &size)) michael@0: return false; michael@0: // Resizing beforehand is not safe, see BUG 1006367 for details. michael@0: if (m->IteratorHasRoomFor(*iter, size * sizeof(P))) { michael@0: r->resize(size); michael@0: for (int i = 0; i < size; i++) { michael@0: if (!ReadParam(m, iter, &(*r)[i])) michael@0: return false; michael@0: } michael@0: } else { michael@0: for (int i = 0; i < size; i++) { michael@0: P element; michael@0: if (!ReadParam(m, iter, &element)) michael@0: return false; michael@0: r->push_back(element); michael@0: } michael@0: } michael@0: return true; michael@0: } michael@0: static void Log(const param_type& p, std::wstring* l) { michael@0: for (size_t i = 0; i < p.size(); ++i) { michael@0: if (i != 0) michael@0: l->append(L" "); michael@0: michael@0: LogParam((p[i]), l); michael@0: } michael@0: } michael@0: }; michael@0: michael@0: template michael@0: struct ParamTraitsStd > { michael@0: typedef std::map param_type; michael@0: static void Write(Message* m, const param_type& p) { michael@0: WriteParam(m, static_cast(p.size())); michael@0: typename param_type::const_iterator iter; michael@0: for (iter = p.begin(); iter != p.end(); ++iter) { michael@0: WriteParam(m, iter->first); michael@0: WriteParam(m, iter->second); michael@0: } michael@0: } michael@0: static bool Read(const Message* m, void** iter, param_type* r) { michael@0: int size; michael@0: if (!ReadParam(m, iter, &size) || size < 0) michael@0: return false; michael@0: for (int i = 0; i < size; ++i) { michael@0: K k; michael@0: if (!ReadParam(m, iter, &k)) michael@0: return false; michael@0: V& value = (*r)[k]; michael@0: if (!ReadParam(m, iter, &value)) michael@0: return false; michael@0: } michael@0: return true; michael@0: } michael@0: static void Log(const param_type& p, std::wstring* l) { michael@0: l->append(L""); michael@0: } michael@0: }; michael@0: michael@0: // Windows-specific types. michael@0: michael@0: template michael@0: struct ParamTraitsWindows : ParamTraitsStd

{}; michael@0: michael@0: #if defined(OS_WIN) michael@0: template <> michael@0: struct ParamTraitsWindows { michael@0: typedef LOGFONT param_type; michael@0: static void Write(Message* m, const param_type& p) { michael@0: m->WriteData(reinterpret_cast(&p), sizeof(LOGFONT)); michael@0: } michael@0: static bool Read(const Message* m, void** iter, param_type* r) { michael@0: const char *data; michael@0: int data_size = 0; michael@0: bool result = m->ReadData(iter, &data, &data_size); michael@0: if (result && data_size == sizeof(LOGFONT)) { michael@0: memcpy(r, data, sizeof(LOGFONT)); michael@0: } else { michael@0: result = false; michael@0: NOTREACHED(); michael@0: } michael@0: michael@0: return result; michael@0: } michael@0: static void Log(const param_type& p, std::wstring* l) { michael@0: l->append(StringPrintf(L"")); michael@0: } michael@0: }; michael@0: michael@0: template <> michael@0: struct ParamTraitsWindows { michael@0: typedef MSG param_type; michael@0: static void Write(Message* m, const param_type& p) { michael@0: m->WriteData(reinterpret_cast(&p), sizeof(MSG)); michael@0: } michael@0: static bool Read(const Message* m, void** iter, param_type* r) { michael@0: const char *data; michael@0: int data_size = 0; michael@0: bool result = m->ReadData(iter, &data, &data_size); michael@0: if (result && data_size == sizeof(MSG)) { michael@0: memcpy(r, data, sizeof(MSG)); michael@0: } else { michael@0: result = false; michael@0: NOTREACHED(); michael@0: } michael@0: michael@0: return result; michael@0: } michael@0: }; michael@0: michael@0: template <> michael@0: struct ParamTraitsWindows { michael@0: typedef HANDLE param_type; michael@0: static void Write(Message* m, const param_type& p) { michael@0: m->WriteIntPtr(reinterpret_cast(p)); michael@0: } michael@0: static bool Read(const Message* m, void** iter, param_type* r) { michael@0: DCHECK_EQ(sizeof(param_type), sizeof(intptr_t)); michael@0: return m->ReadIntPtr(iter, reinterpret_cast(r)); michael@0: } michael@0: static void Log(const param_type& p, std::wstring* l) { michael@0: l->append(StringPrintf(L"0x%X", p)); michael@0: } michael@0: }; michael@0: michael@0: template <> michael@0: struct ParamTraitsWindows { michael@0: typedef HCURSOR param_type; michael@0: static void Write(Message* m, const param_type& p) { michael@0: m->WriteIntPtr(reinterpret_cast(p)); michael@0: } michael@0: static bool Read(const Message* m, void** iter, param_type* r) { michael@0: DCHECK_EQ(sizeof(param_type), sizeof(intptr_t)); michael@0: return m->ReadIntPtr(iter, reinterpret_cast(r)); michael@0: } michael@0: static void Log(const param_type& p, std::wstring* l) { michael@0: l->append(StringPrintf(L"0x%X", p)); michael@0: } michael@0: }; michael@0: michael@0: template <> michael@0: struct ParamTraitsWindows { michael@0: typedef HWND param_type; michael@0: static void Write(Message* m, const param_type& p) { michael@0: m->WriteIntPtr(reinterpret_cast(p)); michael@0: } michael@0: static bool Read(const Message* m, void** iter, param_type* r) { michael@0: DCHECK_EQ(sizeof(param_type), sizeof(intptr_t)); michael@0: return m->ReadIntPtr(iter, reinterpret_cast(r)); michael@0: } michael@0: static void Log(const param_type& p, std::wstring* l) { michael@0: l->append(StringPrintf(L"0x%X", p)); michael@0: } michael@0: }; michael@0: michael@0: template <> michael@0: struct ParamTraitsWindows { michael@0: typedef HACCEL param_type; michael@0: static void Write(Message* m, const param_type& p) { michael@0: m->WriteIntPtr(reinterpret_cast(p)); michael@0: } michael@0: static bool Read(const Message* m, void** iter, param_type* r) { michael@0: DCHECK_EQ(sizeof(param_type), sizeof(intptr_t)); michael@0: return m->ReadIntPtr(iter, reinterpret_cast(r)); michael@0: } michael@0: }; michael@0: michael@0: template <> michael@0: struct ParamTraitsWindows { michael@0: typedef POINT param_type; michael@0: static void Write(Message* m, const param_type& p) { michael@0: m->WriteInt(p.x); michael@0: m->WriteInt(p.y); michael@0: } michael@0: static bool Read(const Message* m, void** iter, param_type* r) { michael@0: int x, y; michael@0: if (!m->ReadInt(iter, &x) || !m->ReadInt(iter, &y)) michael@0: return false; michael@0: r->x = x; michael@0: r->y = y; michael@0: return true; michael@0: } michael@0: static void Log(const param_type& p, std::wstring* l) { michael@0: l->append(StringPrintf(L"(%d, %d)", p.x, p.y)); michael@0: } michael@0: }; michael@0: michael@0: template <> michael@0: struct ParamTraitsWindows { michael@0: typedef XFORM param_type; michael@0: static void Write(Message* m, const param_type& p) { michael@0: m->WriteData(reinterpret_cast(&p), sizeof(XFORM)); michael@0: } michael@0: static bool Read(const Message* m, void** iter, param_type* r) { michael@0: const char *data; michael@0: int data_size = 0; michael@0: bool result = m->ReadData(iter, &data, &data_size); michael@0: if (result && data_size == sizeof(XFORM)) { michael@0: memcpy(r, data, sizeof(XFORM)); michael@0: } else { michael@0: result = false; michael@0: NOTREACHED(); michael@0: } michael@0: michael@0: return result; michael@0: } michael@0: static void Log(const param_type& p, std::wstring* l) { michael@0: l->append(L""); michael@0: } michael@0: }; michael@0: #endif // defined(OS_WIN) michael@0: michael@0: // Various ipc/chromium types. michael@0: michael@0: template michael@0: struct ParamTraitsIPC : ParamTraitsWindows

{}; michael@0: michael@0: template <> michael@0: struct ParamTraitsIPC { michael@0: typedef base::Time param_type; michael@0: static inline void Write(Message* m, const param_type& p); michael@0: static inline bool Read(const Message* m, void** iter, param_type* r); michael@0: static inline void Log(const param_type& p, std::wstring* l); michael@0: }; michael@0: michael@0: #if defined(OS_POSIX) michael@0: // FileDescriptors may be serialised over IPC channels on POSIX. On the michael@0: // receiving side, the FileDescriptor is a valid duplicate of the file michael@0: // descriptor which was transmitted: *it is not just a copy of the integer like michael@0: // HANDLEs on Windows*. The only exception is if the file descriptor is < 0. In michael@0: // this case, the receiving end will see a value of -1. *Zero is a valid file michael@0: // descriptor*. michael@0: // michael@0: // The received file descriptor will have the |auto_close| flag set to true. The michael@0: // code which handles the message is responsible for taking ownership of it. michael@0: // File descriptors are OS resources and must be closed when no longer needed. michael@0: // michael@0: // When sending a file descriptor, the file descriptor must be valid at the time michael@0: // of transmission. Since transmission is not synchronous, one should consider michael@0: // dup()ing any file descriptors to be transmitted and setting the |auto_close| michael@0: // flag, which causes the file descriptor to be closed after writing. michael@0: template<> michael@0: struct ParamTraitsIPC { michael@0: typedef base::FileDescriptor param_type; michael@0: static void Write(Message* m, const param_type& p) { michael@0: const bool valid = p.fd >= 0; michael@0: WriteParam(m, valid); michael@0: michael@0: if (valid) { michael@0: if (!m->WriteFileDescriptor(p)) { michael@0: NOTREACHED() << "Too many file descriptors for one message!"; michael@0: } michael@0: } michael@0: } michael@0: static bool Read(const Message* m, void** iter, param_type* r) { michael@0: bool valid; michael@0: if (!ReadParam(m, iter, &valid)) michael@0: return false; michael@0: michael@0: if (!valid) { michael@0: r->fd = -1; michael@0: r->auto_close = false; michael@0: return true; michael@0: } michael@0: michael@0: return m->ReadFileDescriptor(iter, r); michael@0: } michael@0: static void Log(const param_type& p, std::wstring* l) { michael@0: if (p.auto_close) { michael@0: l->append(StringPrintf(L"FD(%d auto-close)", p.fd)); michael@0: } else { michael@0: l->append(StringPrintf(L"FD(%d)", p.fd)); michael@0: } michael@0: } michael@0: }; michael@0: #endif // defined(OS_POSIX) michael@0: michael@0: template <> michael@0: struct ParamTraitsIPC { michael@0: typedef FilePath param_type; michael@0: static void Write(Message* m, const param_type& p); michael@0: static bool Read(const Message* m, void** iter, param_type* r); michael@0: static void Log(const param_type& p, std::wstring* l); michael@0: }; michael@0: michael@0: struct LogData { michael@0: std::wstring channel; michael@0: int32_t routing_id; michael@0: uint16_t type; michael@0: std::wstring flags; michael@0: int64_t sent; // Time that the message was sent (i.e. at Send()). michael@0: int64_t receive; // Time before it was dispatched (i.e. before calling michael@0: // OnMessageReceived). michael@0: int64_t dispatch; // Time after it was dispatched (i.e. after calling michael@0: // OnMessageReceived). michael@0: std::wstring message_name; michael@0: std::wstring params; michael@0: }; michael@0: michael@0: template <> michael@0: struct ParamTraitsIPC { michael@0: typedef LogData param_type; michael@0: static void Write(Message* m, const param_type& p) { michael@0: WriteParam(m, p.channel); michael@0: WriteParam(m, p.routing_id); michael@0: WriteParam(m, static_cast(p.type)); michael@0: WriteParam(m, p.flags); michael@0: WriteParam(m, p.sent); michael@0: WriteParam(m, p.receive); michael@0: WriteParam(m, p.dispatch); michael@0: WriteParam(m, p.params); michael@0: } michael@0: static bool Read(const Message* m, void** iter, param_type* r) { michael@0: int type = 0; michael@0: bool result = michael@0: ReadParam(m, iter, &r->channel) && michael@0: ReadParam(m, iter, &r->routing_id) && michael@0: ReadParam(m, iter, &type) && michael@0: ReadParam(m, iter, &r->flags) && michael@0: ReadParam(m, iter, &r->sent) && michael@0: ReadParam(m, iter, &r->receive) && michael@0: ReadParam(m, iter, &r->dispatch) && michael@0: ReadParam(m, iter, &r->params); michael@0: r->type = static_cast(type); michael@0: return result; michael@0: } michael@0: static void Log(const param_type& p, std::wstring* l) { michael@0: // Doesn't make sense to implement this! michael@0: } michael@0: }; michael@0: michael@0: #if defined(OS_WIN) michael@0: template<> michael@0: struct ParamTraitsIPC { michael@0: typedef TransportDIB::Id param_type; michael@0: static void Write(Message* m, const param_type& p) { michael@0: WriteParam(m, p.handle); michael@0: WriteParam(m, p.sequence_num); michael@0: } michael@0: static bool Read(const Message* m, void** iter, param_type* r) { michael@0: return (ReadParam(m, iter, &r->handle) && michael@0: ReadParam(m, iter, &r->sequence_num)); michael@0: } michael@0: static void Log(const param_type& p, std::wstring* l) { michael@0: l->append(L"TransportDIB("); michael@0: LogParam(p.handle, l); michael@0: l->append(L", "); michael@0: LogParam(p.sequence_num, l); michael@0: l->append(L")"); michael@0: } michael@0: }; michael@0: #endif michael@0: michael@0: template <> michael@0: struct ParamTraitsIPC { michael@0: static void Write(Message* m, const Message& p) { michael@0: m->WriteInt(p.size()); michael@0: m->WriteData(reinterpret_cast(p.data()), p.size()); michael@0: } michael@0: static bool Read(const Message* m, void** iter, Message* r) { michael@0: int size; michael@0: if (!m->ReadInt(iter, &size)) michael@0: return false; michael@0: const char* data; michael@0: if (!m->ReadData(iter, &data, &size)) michael@0: return false; michael@0: *r = Message(data, size); michael@0: return true; michael@0: } michael@0: static void Log(const Message& p, std::wstring* l) { michael@0: l->append(L""); michael@0: } michael@0: }; michael@0: michael@0: template <> michael@0: struct ParamTraitsIPC { michael@0: typedef Tuple0 param_type; michael@0: static void Write(Message* m, const param_type& p) { michael@0: } michael@0: static bool Read(const Message* m, void** iter, param_type* r) { michael@0: return true; michael@0: } michael@0: static void Log(const param_type& p, std::wstring* l) { michael@0: } michael@0: }; michael@0: michael@0: template michael@0: struct ParamTraitsIPC< Tuple1 > { michael@0: typedef Tuple1 param_type; michael@0: static void Write(Message* m, const param_type& p) { michael@0: WriteParam(m, p.a); michael@0: } michael@0: static bool Read(const Message* m, void** iter, param_type* r) { michael@0: return ReadParam(m, iter, &r->a); michael@0: } michael@0: static void Log(const param_type& p, std::wstring* l) { michael@0: LogParam(p.a, l); michael@0: } michael@0: }; michael@0: michael@0: template michael@0: struct ParamTraitsIPC< Tuple2 > { michael@0: typedef Tuple2 param_type; michael@0: static void Write(Message* m, const param_type& p) { michael@0: WriteParam(m, p.a); michael@0: WriteParam(m, p.b); michael@0: } michael@0: static bool Read(const Message* m, void** iter, param_type* r) { michael@0: return (ReadParam(m, iter, &r->a) && michael@0: ReadParam(m, iter, &r->b)); michael@0: } michael@0: static void Log(const param_type& p, std::wstring* l) { michael@0: LogParam(p.a, l); michael@0: l->append(L", "); michael@0: LogParam(p.b, l); michael@0: } michael@0: }; michael@0: michael@0: template michael@0: struct ParamTraitsIPC< Tuple3 > { michael@0: typedef Tuple3 param_type; michael@0: static void Write(Message* m, const param_type& p) { michael@0: WriteParam(m, p.a); michael@0: WriteParam(m, p.b); michael@0: WriteParam(m, p.c); michael@0: } michael@0: static bool Read(const Message* m, void** iter, param_type* r) { michael@0: return (ReadParam(m, iter, &r->a) && michael@0: ReadParam(m, iter, &r->b) && michael@0: ReadParam(m, iter, &r->c)); michael@0: } michael@0: static void Log(const param_type& p, std::wstring* l) { michael@0: LogParam(p.a, l); michael@0: l->append(L", "); michael@0: LogParam(p.b, l); michael@0: l->append(L", "); michael@0: LogParam(p.c, l); michael@0: } michael@0: }; michael@0: michael@0: template michael@0: struct ParamTraitsIPC< Tuple4 > { michael@0: typedef Tuple4 param_type; michael@0: static void Write(Message* m, const param_type& p) { michael@0: WriteParam(m, p.a); michael@0: WriteParam(m, p.b); michael@0: WriteParam(m, p.c); michael@0: WriteParam(m, p.d); michael@0: } michael@0: static bool Read(const Message* m, void** iter, param_type* r) { michael@0: return (ReadParam(m, iter, &r->a) && michael@0: ReadParam(m, iter, &r->b) && michael@0: ReadParam(m, iter, &r->c) && michael@0: ReadParam(m, iter, &r->d)); michael@0: } michael@0: static void Log(const param_type& p, std::wstring* l) { michael@0: LogParam(p.a, l); michael@0: l->append(L", "); michael@0: LogParam(p.b, l); michael@0: l->append(L", "); michael@0: LogParam(p.c, l); michael@0: l->append(L", "); michael@0: LogParam(p.d, l); michael@0: } michael@0: }; michael@0: michael@0: template michael@0: struct ParamTraitsIPC< Tuple5 > { michael@0: typedef Tuple5 param_type; michael@0: static void Write(Message* m, const param_type& p) { michael@0: WriteParam(m, p.a); michael@0: WriteParam(m, p.b); michael@0: WriteParam(m, p.c); michael@0: WriteParam(m, p.d); michael@0: WriteParam(m, p.e); michael@0: } michael@0: static bool Read(const Message* m, void** iter, param_type* r) { michael@0: return (ReadParam(m, iter, &r->a) && michael@0: ReadParam(m, iter, &r->b) && michael@0: ReadParam(m, iter, &r->c) && michael@0: ReadParam(m, iter, &r->d) && michael@0: ReadParam(m, iter, &r->e)); michael@0: } michael@0: static void Log(const param_type& p, std::wstring* l) { michael@0: LogParam(p.a, l); michael@0: l->append(L", "); michael@0: LogParam(p.b, l); michael@0: l->append(L", "); michael@0: LogParam(p.c, l); michael@0: l->append(L", "); michael@0: LogParam(p.d, l); michael@0: l->append(L", "); michael@0: LogParam(p.e, l); michael@0: } michael@0: }; michael@0: michael@0: template michael@0: struct ParamTraitsIPC< Tuple6 > { michael@0: typedef Tuple6 param_type; michael@0: static void Write(Message* m, const param_type& p) { michael@0: WriteParam(m, p.a); michael@0: WriteParam(m, p.b); michael@0: WriteParam(m, p.c); michael@0: WriteParam(m, p.d); michael@0: WriteParam(m, p.e); michael@0: WriteParam(m, p.f); michael@0: } michael@0: static bool Read(const Message* m, void** iter, param_type* r) { michael@0: return (ReadParam(m, iter, &r->a) && michael@0: ReadParam(m, iter, &r->b) && michael@0: ReadParam(m, iter, &r->c) && michael@0: ReadParam(m, iter, &r->d) && michael@0: ReadParam(m, iter, &r->e) && michael@0: ReadParam(m, iter, &r->f)); michael@0: } michael@0: static void Log(const param_type& p, std::wstring* l) { michael@0: LogParam(p.a, l); michael@0: l->append(L", "); michael@0: LogParam(p.b, l); michael@0: l->append(L", "); michael@0: LogParam(p.c, l); michael@0: l->append(L", "); michael@0: LogParam(p.d, l); michael@0: l->append(L", "); michael@0: LogParam(p.e, l); michael@0: l->append(L", "); michael@0: LogParam(p.f, l); michael@0: } michael@0: }; michael@0: michael@0: // Mozilla-specific types. michael@0: michael@0: template michael@0: struct ParamTraitsMozilla : ParamTraitsIPC

{}; michael@0: michael@0: template <> michael@0: struct ParamTraitsMozilla { michael@0: typedef nsresult param_type; michael@0: static void Write(Message* m, const param_type& p) { michael@0: m->WriteUInt32(static_cast(p)); michael@0: } michael@0: static bool Read(const Message* m, void** iter, param_type* r) { michael@0: return m->ReadUInt32(iter, reinterpret_cast(r)); michael@0: } michael@0: static void Log(const param_type& p, std::wstring* l) { michael@0: l->append(StringPrintf(L"%u", static_cast(p))); michael@0: } michael@0: }; michael@0: michael@0: // Finally, ParamTraits itself. michael@0: michael@0: template struct ParamTraits : ParamTraitsMozilla

{}; michael@0: michael@0: // Now go back and define inlines dependent upon various ParamTraits

. michael@0: inline void michael@0: ParamTraitsIPC::Write(Message* m, const param_type& p) { michael@0: ParamTraits::Write(m, p.ToInternalValue()); michael@0: } michael@0: inline bool michael@0: ParamTraitsIPC::Read(const Message* m, void** iter, param_type* r) { michael@0: int64_t value; michael@0: if (!ParamTraits::Read(m, iter, &value)) michael@0: return false; michael@0: *r = base::Time::FromInternalValue(value); michael@0: return true; michael@0: } michael@0: inline void michael@0: ParamTraitsIPC::Log(const param_type& p, std::wstring* l) { michael@0: ParamTraits::Log(p.ToInternalValue(), l); michael@0: } michael@0: michael@0: inline void michael@0: ParamTraitsIPC::Write(Message* m, const param_type& p) { michael@0: ParamTraits::Write(m, p.value()); michael@0: } michael@0: inline bool michael@0: ParamTraitsIPC::Read(const Message* m, void** iter, param_type* r) { michael@0: FilePath::StringType value; michael@0: if (!ParamTraits::Read(m, iter, &value)) michael@0: return false; michael@0: *r = FilePath(value); michael@0: return true; michael@0: } michael@0: inline void michael@0: ParamTraitsIPC::Log(const param_type& p, std::wstring* l) { michael@0: ParamTraits::Log(p.value(), l); michael@0: } michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: // Generic message subclasses michael@0: michael@0: // Used for asynchronous messages. michael@0: template michael@0: class MessageWithTuple : public Message { michael@0: public: michael@0: typedef ParamType Param; michael@0: michael@0: MessageWithTuple(int32_t routing_id, uint16_t type, const Param& p) michael@0: : Message(routing_id, type, PRIORITY_NORMAL) { michael@0: WriteParam(this, p); michael@0: } michael@0: michael@0: static bool Read(const Message* msg, Param* p) { michael@0: void* iter = NULL; michael@0: bool rv = ReadParam(msg, &iter, p); michael@0: DCHECK(rv) << "Error deserializing message " << msg->type(); michael@0: return rv; michael@0: } michael@0: michael@0: // Generic dispatcher. Should cover most cases. michael@0: template michael@0: static bool Dispatch(const Message* msg, T* obj, Method func) { michael@0: Param p; michael@0: if (Read(msg, &p)) { michael@0: DispatchToMethod(obj, func, p); michael@0: return true; michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: // The following dispatchers exist for the case where the callback function michael@0: // needs the message as well. They assume that "Param" is a type of Tuple michael@0: // (except the one arg case, as there is no Tuple1). michael@0: template michael@0: static bool Dispatch(const Message* msg, T* obj, michael@0: void (T::*func)(const Message&, TA)) { michael@0: Param p; michael@0: if (Read(msg, &p)) { michael@0: (obj->*func)(*msg, p); michael@0: return true; michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: template michael@0: static bool Dispatch(const Message* msg, T* obj, michael@0: void (T::*func)(const Message&, TA, TB)) { michael@0: Param p; michael@0: if (Read(msg, &p)) { michael@0: (obj->*func)(*msg, p.a, p.b); michael@0: return true; michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: template michael@0: static bool Dispatch(const Message* msg, T* obj, michael@0: void (T::*func)(const Message&, TA, TB, TC)) { michael@0: Param p; michael@0: if (Read(msg, &p)) { michael@0: (obj->*func)(*msg, p.a, p.b, p.c); michael@0: return true; michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: template michael@0: static bool Dispatch(const Message* msg, T* obj, michael@0: void (T::*func)(const Message&, TA, TB, TC, TD)) { michael@0: Param p; michael@0: if (Read(msg, &p)) { michael@0: (obj->*func)(*msg, p.a, p.b, p.c, p.d); michael@0: return true; michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: template michael@0: static bool Dispatch(const Message* msg, T* obj, michael@0: void (T::*func)(const Message&, TA, TB, TC, TD, TE)) { michael@0: Param p; michael@0: if (Read(msg, &p)) { michael@0: (obj->*func)(*msg, p.a, p.b, p.c, p.d, p.e); michael@0: return true; michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: static void Log(const Message* msg, std::wstring* l) { michael@0: Param p; michael@0: if (Read(msg, &p)) michael@0: LogParam(p, l); michael@0: } michael@0: michael@0: // Functions used to do manual unpacking. Only used by the automation code, michael@0: // these should go away once that code uses SyncChannel. michael@0: template michael@0: static bool Read(const IPC::Message* msg, TA* a, TB* b) { michael@0: ParamType params; michael@0: if (!Read(msg, ¶ms)) michael@0: return false; michael@0: *a = params.a; michael@0: *b = params.b; michael@0: return true; michael@0: } michael@0: michael@0: template michael@0: static bool Read(const IPC::Message* msg, TA* a, TB* b, TC* c) { michael@0: ParamType params; michael@0: if (!Read(msg, ¶ms)) michael@0: return false; michael@0: *a = params.a; michael@0: *b = params.b; michael@0: *c = params.c; michael@0: return true; michael@0: } michael@0: michael@0: template michael@0: static bool Read(const IPC::Message* msg, TA* a, TB* b, TC* c, TD* d) { michael@0: ParamType params; michael@0: if (!Read(msg, ¶ms)) michael@0: return false; michael@0: *a = params.a; michael@0: *b = params.b; michael@0: *c = params.c; michael@0: *d = params.d; michael@0: return true; michael@0: } michael@0: michael@0: template michael@0: static bool Read(const IPC::Message* msg, TA* a, TB* b, TC* c, TD* d, TE* e) { michael@0: ParamType params; michael@0: if (!Read(msg, ¶ms)) michael@0: return false; michael@0: *a = params.a; michael@0: *b = params.b; michael@0: *c = params.c; michael@0: *d = params.d; michael@0: *e = params.e; michael@0: return true; michael@0: } michael@0: }; michael@0: michael@0: // This class assumes that its template argument is a RefTuple (a Tuple with michael@0: // reference elements). michael@0: template michael@0: class ParamDeserializer : public MessageReplyDeserializer { michael@0: public: michael@0: explicit ParamDeserializer(const RefTuple& out) : out_(out) { } michael@0: michael@0: bool SerializeOutputParameters(const IPC::Message& msg, void* iter) { michael@0: return ReadParam(&msg, &iter, &out_); michael@0: } michael@0: michael@0: RefTuple out_; michael@0: }; michael@0: michael@0: // defined in ipc_logging.cc michael@0: void GenerateLogData(const std::wstring& channel, const Message& message, michael@0: LogData* data); michael@0: michael@0: // Used for synchronous messages. michael@0: template michael@0: class MessageWithReply : public SyncMessage { michael@0: public: michael@0: typedef SendParamType SendParam; michael@0: typedef ReplyParamType ReplyParam; michael@0: michael@0: MessageWithReply(int32_t routing_id, uint16_t type, michael@0: const SendParam& send, const ReplyParam& reply) michael@0: : SyncMessage(routing_id, type, PRIORITY_NORMAL, michael@0: new ParamDeserializer(reply)) { michael@0: WriteParam(this, send); michael@0: } michael@0: michael@0: static void Log(const Message* msg, std::wstring* l) { michael@0: if (msg->is_sync()) { michael@0: SendParam p; michael@0: void* iter = SyncMessage::GetDataIterator(msg); michael@0: if (ReadParam(msg, &iter, &p)) michael@0: LogParam(p, l); michael@0: michael@0: #if defined(IPC_MESSAGE_LOG_ENABLED) michael@0: const std::wstring& output_params = msg->output_params(); michael@0: if (!l->empty() && !output_params.empty()) michael@0: l->append(L", "); michael@0: michael@0: l->append(output_params); michael@0: #endif michael@0: } else { michael@0: // This is an outgoing reply. Now that we have the output parameters, we michael@0: // can finally log the message. michael@0: typename ReplyParam::ValueTuple p; michael@0: void* iter = SyncMessage::GetDataIterator(msg); michael@0: if (ReadParam(msg, &iter, &p)) michael@0: LogParam(p, l); michael@0: } michael@0: } michael@0: michael@0: template michael@0: static bool Dispatch(const Message* msg, T* obj, Method func) { michael@0: SendParam send_params; michael@0: void* iter = GetDataIterator(msg); michael@0: Message* reply = GenerateReply(msg); michael@0: bool error; michael@0: if (ReadParam(msg, &iter, &send_params)) { michael@0: typename ReplyParam::ValueTuple reply_params; michael@0: DispatchToMethod(obj, func, send_params, &reply_params); michael@0: WriteParam(reply, reply_params); michael@0: error = false; michael@0: #ifdef IPC_MESSAGE_LOG_ENABLED michael@0: if (msg->received_time() != 0) { michael@0: std::wstring output_params; michael@0: LogParam(reply_params, &output_params); michael@0: msg->set_output_params(output_params); michael@0: } michael@0: #endif michael@0: } else { michael@0: NOTREACHED() << "Error deserializing message " << msg->type(); michael@0: reply->set_reply_error(); michael@0: error = true; michael@0: } michael@0: michael@0: obj->Send(reply); michael@0: return !error; michael@0: } michael@0: michael@0: template michael@0: static bool DispatchDelayReply(const Message* msg, T* obj, Method func) { michael@0: SendParam send_params; michael@0: void* iter = GetDataIterator(msg); michael@0: Message* reply = GenerateReply(msg); michael@0: bool error; michael@0: if (ReadParam(msg, &iter, &send_params)) { michael@0: Tuple1 t = MakeRefTuple(*reply); michael@0: michael@0: #ifdef IPC_MESSAGE_LOG_ENABLED michael@0: if (msg->sent_time()) { michael@0: // Don't log the sync message after dispatch, as we don't have the michael@0: // output parameters at that point. Instead, save its data and log it michael@0: // with the outgoing reply message when it's sent. michael@0: LogData* data = new LogData; michael@0: GenerateLogData(L"", *msg, data); michael@0: msg->set_dont_log(); michael@0: reply->set_sync_log_data(data); michael@0: } michael@0: #endif michael@0: DispatchToMethod(obj, func, send_params, &t); michael@0: error = false; michael@0: } else { michael@0: NOTREACHED() << "Error deserializing message " << msg->type(); michael@0: reply->set_reply_error(); michael@0: obj->Send(reply); michael@0: error = true; michael@0: } michael@0: return !error; michael@0: } michael@0: michael@0: template michael@0: static void WriteReplyParams(Message* reply, TA a) { michael@0: ReplyParam p(a); michael@0: WriteParam(reply, p); michael@0: } michael@0: michael@0: template michael@0: static void WriteReplyParams(Message* reply, TA a, TB b) { michael@0: ReplyParam p(a, b); michael@0: WriteParam(reply, p); michael@0: } michael@0: michael@0: template michael@0: static void WriteReplyParams(Message* reply, TA a, TB b, TC c) { michael@0: ReplyParam p(a, b, c); michael@0: WriteParam(reply, p); michael@0: } michael@0: michael@0: template michael@0: static void WriteReplyParams(Message* reply, TA a, TB b, TC c, TD d) { michael@0: ReplyParam p(a, b, c, d); michael@0: WriteParam(reply, p); michael@0: } michael@0: michael@0: template michael@0: static void WriteReplyParams(Message* reply, TA a, TB b, TC c, TD d, TE e) { michael@0: ReplyParam p(a, b, c, d, e); michael@0: WriteParam(reply, p); michael@0: } michael@0: }; michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: michael@0: } // namespace IPC michael@0: michael@0: #endif // CHROME_COMMON_IPC_MESSAGE_UTILS_H_