diff options
Diffstat (limited to 'ipc/ipc_message_utils.h')
-rwxr-xr-x | ipc/ipc_message_utils.h | 1238 |
1 files changed, 1238 insertions, 0 deletions
diff --git a/ipc/ipc_message_utils.h b/ipc/ipc_message_utils.h new file mode 100755 index 000000000000..8c2014f35056 --- /dev/null +++ b/ipc/ipc_message_utils.h @@ -0,0 +1,1238 @@ +// Copyright (c) 2011 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_ +#pragma once + +#include <algorithm> +#include <map> +#include <set> +#include <string> +#include <vector> + +#include "base/compiler_specific.h" +//#include "base/format_macros.h" +//#include "base/string16.h" +//#include "base/stringprintf.h" +//#include "base/string_util.h" +#include "base/tuple.h" +#include "ipc/ipc_param_traits.h" +#include "ipc/ipc_sync_message.h" + +#if defined(COMPILER_GCC) +// GCC "helpfully" tries to inline template methods in release mode. Except we +// want the majority of the template junk being expanded once in the +// implementation file (and only provide the definitions in +// ipc_message_utils_impl.h in those files) and exported, instead of expanded +// at every call site. Special note: GCC happily accepts the attribute before +// the method declaration, but only acts on it if it is after. +#if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100) >= 40500 +// Starting in gcc 4.5, the noinline no longer implies the concept covered by +// the introduced noclone attribute, which will create specialized versions of +// functions/methods when certain types are constant. +// www.gnu.org/software/gcc/gcc-4.5/changes.html +#define IPC_MSG_NOINLINE __attribute__((noinline, noclone)); +#else +#define IPC_MSG_NOINLINE __attribute__((noinline)); +#endif +#elif defined(COMPILER_MSVC) +// MSVC++ doesn't do this. +#define IPC_MSG_NOINLINE +#else +#error "Please add the noinline property for your new compiler here." +#endif + +// 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 { + AutomationMsgStart = 0, + PushServiceMsgStart, + CmcStrRegistryManagerStart, + LastIPCMsgStart // Must come last. +}; + +class FilePath; +class NullableString16; + +namespace base { +class DictionaryValue; +class ListValue; +class Time; +class TimeDelta; +struct FileDescriptor; +} + +namespace IPC { + +struct ChannelHandle; + +//----------------------------------------------------------------------------- +// 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 = -1; + if (!msg_.ReadInt(&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; + } +*/ + void NextData(const char** data, int* length) const { + if (!msg_.ReadData(&iter_, data, length)) { + NOTREACHED(); + } + } + private: + const Message& msg_; + mutable void* iter_; +}; + +//----------------------------------------------------------------------------- +// A dummy struct to place first just to allow leading commas for all +// members in the macro-generated constructor initializer lists. +struct NoParams { +}; + +//----------------------------------------------------------------------------- +// ParamTraits specializations, etc. + +template <class P> +static inline void WriteParam(Message* m, const P& p) { + typedef typename SimilarTypeTraits<P>::Type Type; + ParamTraits<Type>::Write(m, static_cast<const Type& >(p)); +} + +template <class P> +static inline bool WARN_UNUSED_RESULT ReadParam(const Message* m, void** iter, + P* p) { + typedef typename SimilarTypeTraits<P>::Type Type; + return ParamTraits<Type>::Read(m, iter, reinterpret_cast<Type* >(p)); +} + + +template <class P> +static inline void LogParam(const P& p, std::string* l) { + typedef typename SimilarTypeTraits<P>::Type Type; + ParamTraits<Type>::Log(static_cast<const Type& >(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::string* l) { + l->append(p ? "true" : "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); + } + IPC_EXPORT static void Log(const param_type& p, std::string* l); +}; + +template <> +struct ParamTraits<unsigned int> { + typedef unsigned 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, reinterpret_cast<int*>(r)); + } + IPC_EXPORT static void Log(const param_type& p, std::string* l); +}; + +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); + } + IPC_EXPORT static void Log(const param_type& p, std::string* l); +}; + +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) { + return m->ReadLong(iter, reinterpret_cast<long*>(r)); + } + IPC_EXPORT static void Log(const param_type& p, std::string* l); +}; + +template <> +struct ParamTraits<long long> { + typedef long long 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)); + } + IPC_EXPORT static void Log(const param_type& p, std::string* l); +}; + +template <> +struct ParamTraits<unsigned long long> { + typedef unsigned long long 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, reinterpret_cast<int64*>(r)); + } + IPC_EXPORT static void Log(const param_type& p, std::string* l); +}; + +template <> +struct IPC_EXPORT ParamTraits<unsigned short> { + typedef unsigned short 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::string* l); +}; + +// Note that the IPC layer doesn't sanitize NaNs and +/- INF values. Clients +// should be sure to check the sanity of these values after receiving them over +// IPC. +template <> +struct ParamTraits<float> { + typedef float 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; + if (!m->ReadData(iter, &data, &data_size) || + data_size != sizeof(param_type)) { + NOTREACHED(); + return false; + } + memcpy(r, data, sizeof(param_type)); + return true; + } + + static void Log(const param_type& p, std::string* l) { + //l->append(StringPrintf("%e", 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; + if (!m->ReadData(iter, &data, &data_size) || + data_size != sizeof(param_type)) { + NOTREACHED(); + return false; + } + memcpy(r, data, sizeof(param_type)); + return true; + } + + static void Log(const param_type& p, std::string* l) { + //l->append(StringPrintf("%e", p)); + } + +}; + +/* +template <> +struct IPC_EXPORT ParamTraits<base::Time> { + typedef base::Time 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::string* l); +}; + +template <> +struct IPC_EXPORT ParamTraits<base::TimeDelta> { + typedef base::TimeDelta 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::string* 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::string* l) { +// l->append(StringPrintf("<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; + } + static void Log(const param_type& p, std::string* l) { + l->append("<MSG>"); + } +}; +#endif // defined(OS_WIN) + +template <> +struct IPC_EXPORT ParamTraits<base::DictionaryValue> { + typedef base::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::string* l); +}; + +template <> +struct IPC_EXPORT ParamTraits<base::ListValue> { + typedef base::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::string* 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::string* l) { + l->append(p); + } +}; + +/* +template<typename CharType> +static void LogBytes(const std::vector<CharType>& data, std::string* out) { +#if defined(OS_WIN) + // Windows has a GUI for logging, which can handle arbitrary binary data. + for (size_t i = 0; i < data.size(); ++i) + out->push_back(data[i]); +#else + // On POSIX, we log to stdout, which we assume can display ASCII. + static const size_t kMaxBytesToLog = 100; + for (size_t i = 0; i < std::min(data.size(), kMaxBytesToLog); ++i) { + if (isprint(data[i])) + out->push_back(data[i]); + else + { + // out->append(StringPrintf("[%02X]", static_cast<unsigned char>(data[i]))); + } + } + if (data.size() > kMaxBytesToLog) { +// out->append( +// StringPrintf(" and %u more bytes", +// static_cast<unsigned>(data.size() - kMaxBytesToLog))); + } +#endif +} +*/ + +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.empty()) { + 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::string* l) { + // LogBytes(p, l); + } +}; + +template <> +struct ParamTraits<std::vector<char> > { + typedef std::vector<char> param_type; + static void Write(Message* m, const param_type& p) { + if (p.empty()) { + 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::string* l) { + //LogBytes(p, l); + } +}; + +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; + // ReadLength() checks for < 0 itself. + if (!m->ReadLength(iter, &size)) + return false; + // Resizing beforehand is not safe, see BUG 1006367 for details. + if (INT_MAX / sizeof(P) <= static_cast<size_t>(size)) + return false; + r->resize(size); + for (int i = 0; i < size; i++) { + if (!ReadParam(m, iter, &(*r)[i])) + return false; + } + return true; + } + static void Log(const param_type& p, std::string* l) { +// for (size_t i = 0; i < p.size(); ++i) { +// if (i != 0) +// l->append(" "); +// LogParam((p[i]), l); +// } + } +}; + +/* +template <class P> +struct ParamTraits<std::set<P> > { + typedef std::set<P> 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); + } + static bool Read(const Message* m, void** iter, param_type* r) { + int size; + if (!m->ReadLength(iter, &size)) + return false; + for (int i = 0; i < size; ++i) { + P item; + if (!ReadParam(m, iter, &item)) + return false; + r->insert(item); + } + return true; + } + static void Log(const param_type& p, std::string* l) { + l->append("<std::set>"); + } +}; + + +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::string* l) { + l->append("<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); + } + IPC_EXPORT static void Log(const param_type& p, std::string* l); +}; + +template <class A, class B> +struct ParamTraits<std::pair<A, B> > { + typedef std::pair<A, B> param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.first); + WriteParam(m, p.second); + } + static bool Read(const Message* m, void** iter, param_type* r) { + return ReadParam(m, iter, &r->first) && ReadParam(m, iter, &r->second); + } + static void Log(const param_type& p, std::string* l) { + l->append("("); + LogParam(p.first, l); + l->append(", "); + LogParam(p.second, l); + l->append(")"); + } +}; + +template <> +struct IPC_EXPORT ParamTraits<NullableString16> { + typedef NullableString16 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::string* l); +}; + +// 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); + } + IPC_EXPORT static void Log(const param_type& p, std::string* l); +}; +#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) { + // Note that HWNDs/HANDLE/HCURSOR/HACCEL etc are always 32 bits, even on 64 + // bit systems. + m->WriteUInt32(reinterpret_cast<uint32>(p)); + } + static bool Read(const Message* m, void** iter, param_type* r) { + DCHECK_EQ(sizeof(param_type), sizeof(uint32)); + return m->ReadUInt32(iter, reinterpret_cast<uint32*>(r)); + } + static void Log(const param_type& p, std::string* l) { +// l->append(StringPrintf("0x%X", p)); + } +}; + +template <> +struct ParamTraits<HCURSOR> { + typedef HCURSOR param_type; + static void Write(Message* m, const param_type& p) { + m->WriteUInt32(reinterpret_cast<uint32>(p)); + } + static bool Read(const Message* m, void** iter, param_type* r) { + DCHECK_EQ(sizeof(param_type), sizeof(uint32)); + return m->ReadUInt32(iter, reinterpret_cast<uint32*>(r)); + } + static void Log(const param_type& p, std::string* l) { +// l->append(StringPrintf("0x%X", p)); + } +}; + +template <> +struct ParamTraits<HACCEL> { + typedef HACCEL param_type; + static void Write(Message* m, const param_type& p) { + m->WriteUInt32(reinterpret_cast<uint32>(p)); + } + static bool Read(const Message* m, void** iter, param_type* r) { + DCHECK_EQ(sizeof(param_type), sizeof(uint32)); + return m->ReadUInt32(iter, reinterpret_cast<uint32*>(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::string* l) { +// l->append(StringPrintf("(%d, %d)", p.x, p.y)); + } +}; +#endif // defined(OS_WIN) + +template <> +struct IPC_EXPORT ParamTraits<FilePath> { + typedef FilePath 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::string* 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 IPC_EXPORT ParamTraits<base::FileDescriptor> { + typedef base::FileDescriptor 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::string* l); +}; +#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 IPC_EXPORT ParamTraits<IPC::ChannelHandle> { + typedef ChannelHandle 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::string* 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::string* l) { + l->append("<XFORM>"); + } +}; +#endif // defined(OS_WIN) + +struct IPC_EXPORT LogData { + LogData(); + ~LogData(); + + std::string channel; + int32 routing_id; + uint32 type; // "User-defined" message type, from ipc_message.h. + std::string 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::string message_name; + std::string params; +}; + +template <> +struct IPC_EXPORT ParamTraits<LogData> { + typedef LogData 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::string* l) { + // Doesn't make sense to implement this! + } +}; + +*/ +template <> +struct ParamTraits<Message> { + static void Write(Message* m, const Message& p) { + DCHECK(p.size() <= INT_MAX); + int message_size = static_cast<int>(p.size()); + m->WriteInt(message_size); + m->WriteData(reinterpret_cast<const char*>(p.data()), message_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::string* l) { + l->append("<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::string* 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::string* 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::string* l) { + LogParam(p.a, l); + l->append(", "); + 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::string* l) { + LogParam(p.a, l); + l->append(", "); + LogParam(p.b, l); + l->append(", "); + 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::string* l) { + LogParam(p.a, l); + l->append(", "); + LogParam(p.b, l); + l->append(", "); + LogParam(p.c, l); + l->append(", "); + 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::string* l) { + LogParam(p.a, l); + l->append(", "); + LogParam(p.b, l); + l->append(", "); + LogParam(p.c, l); + l->append(", "); + LogParam(p.d, l); + l->append(", "); + LogParam(p.e, l); + } +}; + +template <class A, class B, class C, class D, class E, class F> +struct ParamTraits< Tuple6<A, B, C, D, E, F> > { +typedef Tuple6<A, B, C, D, E, F> 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); + WriteParam(m, p.f); + } + 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) && + ReadParam(m, iter, &r->f)); + } + static void Log(const param_type& p, std::string* l) { + LogParam(p.a, l); + l->append(", "); + LogParam(p.b, l); + l->append(", "); + LogParam(p.c, l); + l->append(", "); + LogParam(p.d, l); + l->append(", "); + LogParam(p.e, l); + l->append(", "); + LogParam(p.f, l); + } +}; + +//----------------------------------------------------------------------------- +// Generic message subclasses + +// Used for asynchronous messages. +template <class ParamType> +class __attribute__((visibility("default"))) MessageWithTuple : public Message { + public: + typedef ParamType Param; + typedef typename TupleTypes<ParamType>::ParamTuple RefParam; + + // The constructor and the Read() method's templated implementations are in + // ipc_message_utils_impl.h. The subclass constructor and Log() methods call + // the templated versions of these and make sure there are instantiations in + // those translation units. + MessageWithTuple(int32 routing_id, uint32 type, const RefParam& p); + + static bool Read(const Message* msg, Param* p) IPC_MSG_NOINLINE; + + // Generic dispatcher. Should cover most cases. + template<class T, class S, class Method> + static bool Dispatch(const Message* msg, T* obj, S* sender, 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, class S, typename TA> + static bool Dispatch(const Message* msg, T* obj, S* sender, + void (T::*func)(const Message&, TA)) { + Param p; + if (Read(msg, &p)) { + (obj->*func)(*msg, p.a); + return true; + } + return false; + } + + template<class T, class S, typename TA, typename TB> + static bool Dispatch(const Message* msg, T* obj, S* sender, + 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, class S, typename TA, typename TB, typename TC> + static bool Dispatch(const Message* msg, T* obj, S* sender, + 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, class S, typename TA, typename TB, typename TC, typename TD> + static bool Dispatch(const Message* msg, T* obj, S* sender, + 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, class S, typename TA, typename TB, typename TC, typename TD, + typename TE> + static bool Dispatch(const Message* msg, T* obj, S* sender, + 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; + } + + // 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; + } +}; + +// defined in ipc_logging.cc +IPC_EXPORT void GenerateLogData(const std::string& channel, + const Message& message, + LogData* data); + + +#if defined(IPC_MESSAGE_LOG_ENABLED) +inline void AddOutputParamsToLog(const Message* msg, std::string* l) { + const std::string& output_params = msg->output_params(); + if (!l->empty() && !output_params.empty()) + l->append(", "); + + l->append(output_params); +} + +template <class ReplyParamType> +inline void LogReplyParamsToMessage(const ReplyParamType& reply_params, + const Message* msg) { + if (msg->received_time() != 0) { + std::string output_params; + LogParam(reply_params, &output_params); + msg->set_output_params(output_params); + } +} + +inline void ConnectMessageAndReply(const Message* msg, Message* reply) { + 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); + } +} +#else +inline void AddOutputParamsToLog(const Message* msg, std::string* l) {} + +template <class ReplyParamType> +inline void LogReplyParamsToMessage(const ReplyParamType& reply_params, + const Message* msg) {} + +inline void ConnectMessageAndReply(const Message* msg, Message* reply) {} +#endif + +// This class assumes that its template argument is a RefTuple (a Tuple with +// reference elements). This would go into ipc_message_utils_impl.h, but it is +// also used by chrome_frame. +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_; +}; + +// Used for synchronous messages. +template <class SendParamType, class ReplyParamType> +class __attribute__((visibility("default"))) MessageWithReply : public SyncMessage { + public: + typedef SendParamType SendParam; + typedef typename TupleTypes<SendParam>::ParamTuple RefSendParam; + typedef ReplyParamType ReplyParam; + + MessageWithReply(int32 routing_id, uint32 type, + const RefSendParam& send, const ReplyParam& reply); + static bool ReadSendParam(const Message* msg, SendParam* p) IPC_MSG_NOINLINE; + static bool ReadReplyParam( + const Message* msg, + typename TupleTypes<ReplyParam>::ValueTuple* p) IPC_MSG_NOINLINE; + + template<class T, class S, class Method> + static bool Dispatch(const Message* msg, T* obj, S* sender, Method func) { + SendParam send_params; + Message* reply = GenerateReply(msg); + bool error; + if (ReadSendParam(msg, &send_params)) { + typename TupleTypes<ReplyParam>::ValueTuple reply_params; + DispatchToMethod(obj, func, send_params, &reply_params); + WriteParam(reply, reply_params); + error = false; + LogReplyParamsToMessage(reply_params, msg); + } else { + NOTREACHED() << "Error deserializing message " << msg->type(); + reply->set_reply_error(); + error = true; + } + + sender->Send(reply); + return !error; + } + + template<class T, class Method> + static bool DispatchDelayReply(const Message* msg, T* obj, Method func) { + SendParam send_params; + Message* reply = GenerateReply(msg); + bool error; + if (ReadSendParam(msg, &send_params)) { + Tuple1<Message&> t = MakeRefTuple(*reply); + ConnectMessageAndReply(msg, reply); + 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_ |