| // 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/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, |
| ViewMsgStart, |
| PluginMsgStart, |
| ProfileImportMsgStart, |
| TestMsgStart, |
| DevToolsMsgStart, |
| WorkerMsgStart, |
| NaClMsgStart, |
| UtilityMsgStart, |
| GpuMsgStart, |
| ServiceMsgStart, |
| PpapiMsgStart, |
| FirefoxImporterUnittestMsgStart, |
| FileUtilitiesMsgStart, |
| MimeRegistryMsgStart, |
| DatabaseMsgStart, |
| DOMStorageMsgStart, |
| IndexedDBMsgStart, |
| PepperFileMsgStart, |
| SpeechInputMsgStart, |
| PepperMsgStart, |
| AutofillMsgStart, |
| SafeBrowsingMsgStart, |
| P2PMsgStart, |
| SocketStreamMsgStart, |
| ResourceMsgStart, |
| FileSystemMsgStart, |
| ChildProcessMsgStart, |
| ClipboardMsgStart, |
| BlobMsgStart, |
| AppCacheMsgStart, |
| DeviceOrientationMsgStart, |
| DesktopNotificationMsgStart, |
| GeolocationMsgStart, |
| AudioMsgStart, |
| ChromeMsgStart, |
| DragMsgStart, |
| PrintMsgStart, |
| SpellCheckMsgStart, |
| ExtensionMsgStart, |
| VideoCaptureMsgStart, |
| QuotaMsgStart, |
| IconMsgStart, |
| TextInputClientMsgStart, |
| ChromeUtilityMsgStart, |
| LastIPCMsgStart // Must come last. |
| }; |
| |
| class DictionaryValue; |
| class FilePath; |
| class ListValue; |
| class NullableString16; |
| |
| namespace base { |
| 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); |
| } |
| 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)); |
| } |
| 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); |
| } |
| 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)); |
| } |
| 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)); |
| } |
| 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)); |
| } |
| static void Log(const param_type& p, std::string* l); |
| }; |
| |
| template <> |
| struct 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 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 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 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::string* 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::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); |
| } |
| 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 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); |
| } |
| 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 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 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 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 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 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); |
| } |
| }; |
| |
| //----------------------------------------------------------------------------- |
| // Generic message subclasses |
| |
| // Used for asynchronous messages. |
| template <class ParamType> |
| class 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 |
| 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 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_ |