// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef IPC_IPC_MESSAGE_UTILS_H_ #define IPC_IPC_MESSAGE_UTILS_H_ #include <limits.h> #include <stddef.h> #include <stdint.h> #include <algorithm> #include <map> #include <memory> #include <set> #include <string> #include <tuple> #include <vector> #include "base/containers/small_map.h" #include "base/containers/stack_container.h" #include "base/files/file.h" #include "base/format_macros.h" #include "base/memory/scoped_vector.h" #include "base/optional.h" #include "base/strings/string16.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "build/build_config.h" #include "ipc/ipc_message_start.h" #include "ipc/ipc_param_traits.h" #include "ipc/ipc_sync_message.h" namespace base { class DictionaryValue; class FilePath; class ListValue; class NullableString16; class Time; class TimeDelta; class TimeTicks; class UnguessableToken; struct FileDescriptor; #if (defined(OS_MACOSX) && !defined(OS_IOS)) || defined(OS_WIN) class SharedMemoryHandle; #endif // (defined(OS_MACOSX) && !defined(OS_IOS)) || defined(OS_WIN) } namespace IPC { struct ChannelHandle; // ----------------------------------------------------------------------------- // How we send IPC message logs across channels. struct IPC_EXPORT LogData { LogData(); LogData(const LogData& other); ~LogData(); std::string channel; int32_t routing_id; uint32_t type; // "User-defined" message type, from ipc_message.h. std::string flags; int64_t sent; // Time that the message was sent (i.e. at Send()). int64_t receive; // Time before it was dispatched (i.e. before calling // OnMessageReceived). int64_t dispatch; // Time after it was dispatched (i.e. after calling // OnMessageReceived). std::string message_name; std::string params; }; //----------------------------------------------------------------------------- // A dummy struct to place first just to allow leading commas for all // members in the macro-generated constructor initializer lists. struct NoParams { }; // Specializations are checked by 'IPC checker' part of find-bad-constructs // Clang plugin (see WriteParam() below for the details). template <typename... Ts> struct CheckedTuple { typedef std::tuple<Ts...> Tuple; }; template <class P> static inline void GetParamSize(base::PickleSizer* sizer, const P& p) { typedef typename SimilarTypeTraits<P>::Type Type; ParamTraits<Type>::GetSize(sizer, static_cast<const Type&>(p)); } // This function is checked by 'IPC checker' part of find-bad-constructs // Clang plugin to make it's not called on the following types: // 1. long / unsigned long (but not typedefs to) // 2. intmax_t, uintmax_t, intptr_t, uintptr_t, wint_t, // size_t, rsize_t, ssize_t, ptrdiff_t, dev_t, off_t, clock_t, // time_t, suseconds_t (including typedefs to) // 3. Any template referencing types above (e.g. std::vector<size_t>) template <class P> static inline void WriteParam(base::Pickle* 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 base::Pickle* m, base::PickleIterator* 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); } // Primitive ParamTraits ------------------------------------------------------- template <> struct ParamTraits<bool> { typedef bool param_type; static void GetSize(base::PickleSizer* sizer, const param_type& p) { sizer->AddBool(); } static void Write(base::Pickle* m, const param_type& p) { m->WriteBool(p); } static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { return iter->ReadBool(r); } IPC_EXPORT static void Log(const param_type& p, std::string* l); }; template <> struct IPC_EXPORT ParamTraits<signed char> { typedef signed char param_type; static void GetSize(base::PickleSizer* sizer, const param_type& p); static void Write(base::Pickle* m, const param_type& p); static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r); static void Log(const param_type& p, std::string* l); }; template <> struct IPC_EXPORT ParamTraits<unsigned char> { typedef unsigned char param_type; static void GetSize(base::PickleSizer* sizer, const param_type& p); static void Write(base::Pickle* m, const param_type& p); static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r); static void Log(const param_type& p, std::string* l); }; template <> struct IPC_EXPORT ParamTraits<unsigned short> { typedef unsigned short param_type; static void GetSize(base::PickleSizer* sizer, const param_type& p); static void Write(base::Pickle* m, const param_type& p); static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r); static void Log(const param_type& p, std::string* l); }; template <> struct ParamTraits<int> { typedef int param_type; static void GetSize(base::PickleSizer* sizer, const param_type& p) { sizer->AddInt(); } static void Write(base::Pickle* m, const param_type& p) { m->WriteInt(p); } static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { return iter->ReadInt(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 GetSize(base::PickleSizer* sizer, const param_type& p) { sizer->AddInt(); } static void Write(base::Pickle* m, const param_type& p) { m->WriteInt(p); } static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { return iter->ReadInt(reinterpret_cast<int*>(r)); } IPC_EXPORT static void Log(const param_type& p, std::string* l); }; // long isn't safe to send over IPC because it's 4 bytes on 32 bit builds but // 8 bytes on 64 bit builds. So if a 32 bit and 64 bit process have a channel // that would cause problem. // We need to keep this on for a few configs: // 1) Windows because DWORD is typedef'd to it, which is fine because we have // very few IPCs that cross this boundary. // 2) We also need to keep it for Linux for two reasons: int64_t is typedef'd // to long, and gfx::PluginWindow is long and is used in one GPU IPC. // 3) Android 64 bit also has int64_t typedef'd to long. // Since we want to support Android 32<>64 bit IPC, as long as we don't have // these traits for 32 bit ARM then that'll catch any errors. #if defined(OS_WIN) || defined(OS_LINUX) || \ (defined(OS_ANDROID) && defined(ARCH_CPU_64_BITS)) template <> struct ParamTraits<long> { typedef long param_type; static void GetSize(base::PickleSizer* sizer, const param_type& p) { sizer->AddLong(); } static void Write(base::Pickle* m, const param_type& p) { m->WriteLong(p); } static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { return iter->ReadLong(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 GetSize(base::PickleSizer* sizer, const param_type& p) { sizer->AddLong(); } static void Write(base::Pickle* m, const param_type& p) { m->WriteLong(p); } static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { return iter->ReadLong(reinterpret_cast<long*>(r)); } IPC_EXPORT static void Log(const param_type& p, std::string* l); }; #endif template <> struct ParamTraits<long long> { typedef long long param_type; static void GetSize(base::PickleSizer* sizer, const param_type& p) { sizer->AddInt64(); } static void Write(base::Pickle* m, const param_type& p) { m->WriteInt64(static_cast<int64_t>(p)); } static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { return iter->ReadInt64(reinterpret_cast<int64_t*>(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 GetSize(base::PickleSizer* sizer, const param_type& p) { sizer->AddInt64(); } static void Write(base::Pickle* m, const param_type& p) { m->WriteInt64(p); } static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { return iter->ReadInt64(reinterpret_cast<int64_t*>(r)); } IPC_EXPORT 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 IPC_EXPORT ParamTraits<float> { typedef float param_type; static void GetSize(base::PickleSizer* sizer, const param_type& p) { sizer->AddFloat(); } static void Write(base::Pickle* m, const param_type& p) { m->WriteFloat(p); } static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { return iter->ReadFloat(r); } static void Log(const param_type& p, std::string* l); }; template <> struct IPC_EXPORT ParamTraits<double> { typedef double param_type; static void GetSize(base::PickleSizer* sizer, const param_type& p); static void Write(base::Pickle* m, const param_type& p); static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r); static void Log(const param_type& p, std::string* l); }; template <class P, size_t Size> struct ParamTraits<P[Size]> { using param_type = P[Size]; static void GetSize(base::PickleSizer* sizer, const param_type& p) { for (const P& element : p) GetParamSize(sizer, element); } static void Write(base::Pickle* m, const param_type& p) { for (const P& element : p) WriteParam(m, element); } static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { for (P& element : *r) { if (!ReadParam(m, iter, &element)) return false; } return true; } static void Log(const param_type& p, std::string* l) { l->append("["); for (const P& element : p) { if (&element != &p[0]) l->append(" "); LogParam(element, l); } l->append("]"); } }; // STL ParamTraits ------------------------------------------------------------- template <> struct ParamTraits<std::string> { typedef std::string param_type; static void GetSize(base::PickleSizer* sizer, const param_type& p) { sizer->AddString(p); } static void Write(base::Pickle* m, const param_type& p) { m->WriteString(p); } static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { return iter->ReadString(r); } IPC_EXPORT static void Log(const param_type& p, std::string* l); }; template <> struct ParamTraits<base::string16> { typedef base::string16 param_type; static void GetSize(base::PickleSizer* sizer, const param_type& p) { sizer->AddString16(p); } static void Write(base::Pickle* m, const param_type& p) { m->WriteString16(p); } static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { return iter->ReadString16(r); } IPC_EXPORT static void Log(const param_type& p, std::string* l); }; template <> struct IPC_EXPORT ParamTraits<std::vector<char> > { typedef std::vector<char> param_type; static void GetSize(base::PickleSizer* sizer, const param_type& p); static void Write(base::Pickle* m, const param_type& p); static bool Read(const base::Pickle*, base::PickleIterator* iter, param_type* r); static void Log(const param_type& p, std::string* l); }; template <> struct IPC_EXPORT ParamTraits<std::vector<unsigned char> > { typedef std::vector<unsigned char> param_type; static void GetSize(base::PickleSizer* sizer, const param_type& p); static void Write(base::Pickle* m, const param_type& p); static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r); static void Log(const param_type& p, std::string* l); }; template <> struct IPC_EXPORT ParamTraits<std::vector<bool> > { typedef std::vector<bool> param_type; static void GetSize(base::PickleSizer* sizer, const param_type& p); static void Write(base::Pickle* m, const param_type& p); static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r); static void Log(const param_type& p, std::string* l); }; template <class P> struct ParamTraits<std::vector<P>> { typedef std::vector<P> param_type; static void GetSize(base::PickleSizer* sizer, const param_type& p) { GetParamSize(sizer, static_cast<int>(p.size())); for (size_t i = 0; i < p.size(); i++) GetParamSize(sizer, p[i]); } static void Write(base::Pickle* 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 base::Pickle* m, base::PickleIterator* iter, param_type* r) { int size; // ReadLength() checks for < 0 itself. if (!iter->ReadLength(&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 GetSize(base::PickleSizer* sizer, const param_type& p) { GetParamSize(sizer, static_cast<int>(p.size())); typename param_type::const_iterator iter; for (iter = p.begin(); iter != p.end(); ++iter) GetParamSize(sizer, *iter); } static void Write(base::Pickle* 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 base::Pickle* m, base::PickleIterator* iter, param_type* r) { int size; if (!iter->ReadLength(&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, class C, class A> struct ParamTraits<std::map<K, V, C, A> > { typedef std::map<K, V, C, A> param_type; static void GetSize(base::PickleSizer* sizer, const param_type& p) { GetParamSize(sizer, static_cast<int>(p.size())); typename param_type::const_iterator iter; for (iter = p.begin(); iter != p.end(); ++iter) { GetParamSize(sizer, iter->first); GetParamSize(sizer, iter->second); } } static void Write(base::Pickle* 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 base::Pickle* m, base::PickleIterator* 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 <class A, class B> struct ParamTraits<std::pair<A, B> > { typedef std::pair<A, B> param_type; static void GetSize(base::PickleSizer* sizer, const param_type& p) { GetParamSize(sizer, p.first); GetParamSize(sizer, p.second); } static void Write(base::Pickle* m, const param_type& p) { WriteParam(m, p.first); WriteParam(m, p.second); } static bool Read(const base::Pickle* m, base::PickleIterator* 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(")"); } }; // Base ParamTraits ------------------------------------------------------------ template <> struct IPC_EXPORT ParamTraits<base::DictionaryValue> { typedef base::DictionaryValue param_type; static void GetSize(base::PickleSizer* sizer, const param_type& p); static void Write(base::Pickle* m, const param_type& p); static bool Read(const base::Pickle* m, base::PickleIterator* 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 GetSize(base::PickleSizer* sizer, const param_type& p); static void Write(base::Pickle* m, const param_type& p); static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r); static void Log(const param_type& p, std::string* l); }; #endif // defined(OS_POSIX) #if (defined(OS_MACOSX) && !defined(OS_IOS)) || defined(OS_WIN) template <> struct IPC_EXPORT ParamTraits<base::SharedMemoryHandle> { typedef base::SharedMemoryHandle param_type; static void GetSize(base::PickleSizer* sizer, const param_type& p); static void Write(base::Pickle* m, const param_type& p); static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r); static void Log(const param_type& p, std::string* l); }; #endif // (defined(OS_MACOSX) && !defined(OS_IOS)) || defined(OS_WIN) template <> struct IPC_EXPORT ParamTraits<base::FilePath> { typedef base::FilePath param_type; static void GetSize(base::PickleSizer* sizer, const param_type& p); static void Write(base::Pickle* m, const param_type& p); static bool Read(const base::Pickle* m, base::PickleIterator* 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 GetSize(base::PickleSizer* sizer, const param_type& p); static void Write(base::Pickle* m, const param_type& p); static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r); static void Log(const param_type& p, std::string* l); }; template <> struct IPC_EXPORT ParamTraits<base::NullableString16> { typedef base::NullableString16 param_type; static void GetSize(base::PickleSizer* sizer, const param_type& p); static void Write(base::Pickle* m, const param_type& p); static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r); static void Log(const param_type& p, std::string* l); }; template <> struct IPC_EXPORT ParamTraits<base::File::Info> { typedef base::File::Info param_type; static void GetSize(base::PickleSizer* sizer, const param_type& p); static void Write(base::Pickle* m, const param_type& p); static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r); static void Log(const param_type& p, std::string* l); }; template <> struct SimilarTypeTraits<base::File::Error> { typedef int Type; }; #if defined(OS_WIN) template <> struct SimilarTypeTraits<HWND> { typedef HANDLE Type; }; #endif // defined(OS_WIN) template <> struct IPC_EXPORT ParamTraits<base::Time> { typedef base::Time param_type; static void GetSize(base::PickleSizer* sizer, const param_type& p); static void Write(base::Pickle* m, const param_type& p); static bool Read(const base::Pickle* m, base::PickleIterator* 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 GetSize(base::PickleSizer* sizer, const param_type& p); static void Write(base::Pickle* m, const param_type& p); static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r); static void Log(const param_type& p, std::string* l); }; template <> struct IPC_EXPORT ParamTraits<base::TimeTicks> { typedef base::TimeTicks param_type; static void GetSize(base::PickleSizer* sizer, const param_type& p); static void Write(base::Pickle* m, const param_type& p); static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r); static void Log(const param_type& p, std::string* l); }; template <> struct IPC_EXPORT ParamTraits<base::UnguessableToken> { typedef base::UnguessableToken param_type; static void GetSize(base::PickleSizer* sizer, const param_type& p); static void Write(base::Pickle* m, const param_type& p); static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r); static void Log(const param_type& p, std::string* l); }; template <> struct ParamTraits<std::tuple<>> { typedef std::tuple<> param_type; static void GetSize(base::PickleSizer* sizer, const param_type& p) {} static void Write(base::Pickle* m, const param_type& p) {} static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { return true; } static void Log(const param_type& p, std::string* l) { } }; template <class A> struct ParamTraits<std::tuple<A>> { typedef std::tuple<A> param_type; static void GetSize(base::PickleSizer* sizer, const param_type& p) { GetParamSize(sizer, std::get<0>(p)); } static void Write(base::Pickle* m, const param_type& p) { WriteParam(m, std::get<0>(p)); } static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { return ReadParam(m, iter, &std::get<0>(*r)); } static void Log(const param_type& p, std::string* l) { LogParam(std::get<0>(p), l); } }; template <class A, class B> struct ParamTraits<std::tuple<A, B>> { typedef std::tuple<A, B> param_type; static void GetSize(base::PickleSizer* sizer, const param_type& p) { GetParamSize(sizer, std::get<0>(p)); GetParamSize(sizer, std::get<1>(p)); } static void Write(base::Pickle* m, const param_type& p) { WriteParam(m, std::get<0>(p)); WriteParam(m, std::get<1>(p)); } static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { return (ReadParam(m, iter, &std::get<0>(*r)) && ReadParam(m, iter, &std::get<1>(*r))); } static void Log(const param_type& p, std::string* l) { LogParam(std::get<0>(p), l); l->append(", "); LogParam(std::get<1>(p), l); } }; template <class A, class B, class C> struct ParamTraits<std::tuple<A, B, C>> { typedef std::tuple<A, B, C> param_type; static void GetSize(base::PickleSizer* sizer, const param_type& p) { GetParamSize(sizer, std::get<0>(p)); GetParamSize(sizer, std::get<1>(p)); GetParamSize(sizer, std::get<2>(p)); } static void Write(base::Pickle* m, const param_type& p) { WriteParam(m, std::get<0>(p)); WriteParam(m, std::get<1>(p)); WriteParam(m, std::get<2>(p)); } static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { return (ReadParam(m, iter, &std::get<0>(*r)) && ReadParam(m, iter, &std::get<1>(*r)) && ReadParam(m, iter, &std::get<2>(*r))); } static void Log(const param_type& p, std::string* l) { LogParam(std::get<0>(p), l); l->append(", "); LogParam(std::get<1>(p), l); l->append(", "); LogParam(std::get<2>(p), l); } }; template <class A, class B, class C, class D> struct ParamTraits<std::tuple<A, B, C, D>> { typedef std::tuple<A, B, C, D> param_type; static void GetSize(base::PickleSizer* sizer, const param_type& p) { GetParamSize(sizer, std::get<0>(p)); GetParamSize(sizer, std::get<1>(p)); GetParamSize(sizer, std::get<2>(p)); GetParamSize(sizer, std::get<3>(p)); } static void Write(base::Pickle* m, const param_type& p) { WriteParam(m, std::get<0>(p)); WriteParam(m, std::get<1>(p)); WriteParam(m, std::get<2>(p)); WriteParam(m, std::get<3>(p)); } static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { return (ReadParam(m, iter, &std::get<0>(*r)) && ReadParam(m, iter, &std::get<1>(*r)) && ReadParam(m, iter, &std::get<2>(*r)) && ReadParam(m, iter, &std::get<3>(*r))); } static void Log(const param_type& p, std::string* l) { LogParam(std::get<0>(p), l); l->append(", "); LogParam(std::get<1>(p), l); l->append(", "); LogParam(std::get<2>(p), l); l->append(", "); LogParam(std::get<3>(p), l); } }; template <class A, class B, class C, class D, class E> struct ParamTraits<std::tuple<A, B, C, D, E>> { typedef std::tuple<A, B, C, D, E> param_type; static void GetSize(base::PickleSizer* sizer, const param_type& p) { GetParamSize(sizer, std::get<0>(p)); GetParamSize(sizer, std::get<1>(p)); GetParamSize(sizer, std::get<2>(p)); GetParamSize(sizer, std::get<3>(p)); GetParamSize(sizer, std::get<4>(p)); } static void Write(base::Pickle* m, const param_type& p) { WriteParam(m, std::get<0>(p)); WriteParam(m, std::get<1>(p)); WriteParam(m, std::get<2>(p)); WriteParam(m, std::get<3>(p)); WriteParam(m, std::get<4>(p)); } static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { return (ReadParam(m, iter, &std::get<0>(*r)) && ReadParam(m, iter, &std::get<1>(*r)) && ReadParam(m, iter, &std::get<2>(*r)) && ReadParam(m, iter, &std::get<3>(*r)) && ReadParam(m, iter, &std::get<4>(*r))); } static void Log(const param_type& p, std::string* l) { LogParam(std::get<0>(p), l); l->append(", "); LogParam(std::get<1>(p), l); l->append(", "); LogParam(std::get<2>(p), l); l->append(", "); LogParam(std::get<3>(p), l); l->append(", "); LogParam(std::get<4>(p), l); } }; template<class P> struct ParamTraits<ScopedVector<P> > { typedef ScopedVector<P> param_type; static void Write(base::Pickle* 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 base::Pickle* m, base::PickleIterator* iter, param_type* r) { int size = 0; if (!iter->ReadLength(&size)) return false; if (INT_MAX/sizeof(P) <= static_cast<size_t>(size)) return false; r->resize(size); for (int i = 0; i < size; i++) { (*r)[i] = new P(); 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, size_t stack_capacity> struct ParamTraits<base::StackVector<P, stack_capacity> > { typedef base::StackVector<P, stack_capacity> param_type; static void GetSize(base::PickleSizer* sizer, const param_type& p) { GetParamSize(sizer, static_cast<int>(p->size())); for (size_t i = 0; i < p->size(); i++) GetParamSize(sizer, p[i]); } static void Write(base::Pickle* 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 base::Pickle* m, base::PickleIterator* iter, param_type* r) { int size; // ReadLength() checks for < 0 itself. if (!iter->ReadLength(&size)) return false; // Sanity check for the vector size. if (INT_MAX / sizeof(P) <= static_cast<size_t>(size)) return false; P value; for (int i = 0; i < size; i++) { if (!ReadParam(m, iter, &value)) return false; (*r)->push_back(value); } 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 <typename NormalMap, int kArraySize, typename EqualKey, typename MapInit> struct ParamTraits<base::SmallMap<NormalMap, kArraySize, EqualKey, MapInit> > { typedef base::SmallMap<NormalMap, kArraySize, EqualKey, MapInit> param_type; typedef typename param_type::key_type K; typedef typename param_type::data_type V; static void GetSize(base::PickleSizer* sizer, const param_type& p) { GetParamSize(sizer, static_cast<int>(p.size())); typename param_type::const_iterator iter; for (iter = p.begin(); iter != p.end(); ++iter) { GetParamSize(sizer, iter->first); GetParamSize(sizer, iter->second); } } static void Write(base::Pickle* 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 base::Pickle* m, base::PickleIterator* iter, param_type* r) { int size; if (!iter->ReadLength(&size)) return false; for (int i = 0; i < size; ++i) { K key; if (!ReadParam(m, iter, &key)) return false; V& value = (*r)[key]; if (!ReadParam(m, iter, &value)) return false; } return true; } static void Log(const param_type& p, std::string* l) { l->append("<base::SmallMap>"); } }; template <class P> struct ParamTraits<std::unique_ptr<P>> { typedef std::unique_ptr<P> param_type; static void GetSize(base::PickleSizer* sizer, const param_type& p) { bool valid = !!p; GetParamSize(sizer, valid); if (valid) GetParamSize(sizer, *p); } static void Write(base::Pickle* m, const param_type& p) { bool valid = !!p; WriteParam(m, valid); if (valid) WriteParam(m, *p); } static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { bool valid = false; if (!ReadParam(m, iter, &valid)) return false; if (!valid) { r->reset(); return true; } param_type temp(new P()); if (!ReadParam(m, iter, temp.get())) return false; r->swap(temp); return true; } static void Log(const param_type& p, std::string* l) { if (p) LogParam(*p, l); else l->append("NULL"); } }; template <class P> struct ParamTraits<base::Optional<P>> { typedef base::Optional<P> param_type; static void GetSize(base::PickleSizer* sizer, const param_type& p) { const bool is_set = static_cast<bool>(p); GetParamSize(sizer, is_set); if (is_set) GetParamSize(sizer, p.value()); } static void Write(base::Pickle* m, const param_type& p) { const bool is_set = static_cast<bool>(p); WriteParam(m, is_set); if (is_set) WriteParam(m, p.value()); } static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { bool is_set = false; if (!iter->ReadBool(&is_set)) return false; if (is_set) { P value; if (!ReadParam(m, iter, &value)) return false; *r = std::move(value); } return true; } static void Log(const param_type& p, std::string* l) { if (p) LogParam(p.value(), l); else l->append("(unset)"); } }; // IPC types ParamTraits ------------------------------------------------------- // 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 GetSize(base::PickleSizer* sizer, const param_type& p); static void Write(base::Pickle* m, const param_type& p); static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r); static void Log(const param_type& p, std::string* l); }; template <> struct IPC_EXPORT ParamTraits<LogData> { typedef LogData param_type; static void GetSize(base::PickleSizer* sizer, const param_type& p); static void Write(base::Pickle* m, const param_type& p); static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r); static void Log(const param_type& p, std::string* l); }; template <> struct IPC_EXPORT ParamTraits<Message> { static void Write(base::Pickle* m, const Message& p); static bool Read(const base::Pickle* m, base::PickleIterator* iter, Message* r); static void Log(const Message& p, std::string* l); }; // Windows ParamTraits --------------------------------------------------------- #if defined(OS_WIN) template <> struct IPC_EXPORT ParamTraits<HANDLE> { typedef HANDLE param_type; static void GetSize(base::PickleSizer* sizer, const param_type& p); static void Write(base::Pickle* m, const param_type& p); static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r); static void Log(const param_type& p, std::string* l); }; template <> struct IPC_EXPORT ParamTraits<LOGFONT> { typedef LOGFONT param_type; static void GetSize(base::PickleSizer* sizer, const param_type& p); static void Write(base::Pickle* m, const param_type& p); static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r); static void Log(const param_type& p, std::string* l); }; template <> struct IPC_EXPORT ParamTraits<MSG> { typedef MSG param_type; static void GetSize(base::PickleSizer* sizer, const param_type& p); static void Write(base::Pickle* m, const param_type& p); static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r); static void Log(const param_type& p, std::string* l); }; #endif // defined(OS_WIN) //----------------------------------------------------------------------------- // Generic message subclasses // defined in ipc_logging.cc IPC_EXPORT void GenerateLogData(const Message& message, LogData* data, bool get_params); #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, true); 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 } // namespace IPC #endif // IPC_IPC_MESSAGE_UTILS_H_