| // 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/flat_map.h" |
| #include "base/containers/small_map.h" |
| #include "base/containers/stack_container.h" |
| #include "base/files/file.h" |
| #include "base/format_macros.h" |
| #include "base/numerics/safe_conversions.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 SharedMemoryHandle; |
| class Time; |
| class TimeDelta; |
| class TimeTicks; |
| class UnguessableToken; |
| struct FileDescriptor; |
| } |
| |
| namespace IPC { |
| |
| struct ChannelHandle; |
| |
| #if defined(OS_WIN) |
| class PlatformFileForTransit; |
| #endif |
| |
| // ----------------------------------------------------------------------------- |
| // 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) |
| |
| 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); |
| }; |
| |
| #if defined(OS_WIN) |
| template <> |
| struct IPC_EXPORT ParamTraits<PlatformFileForTransit> { |
| typedef PlatformFileForTransit 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) |
| |
| 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, 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::small_map<NormalMap, kArraySize, EqualKey, MapInit>> { |
| using param_type = base::small_map<NormalMap, kArraySize, EqualKey, MapInit>; |
| using K = typename param_type::key_type; |
| using V = typename param_type::data_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 (!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::small_map>"); |
| } |
| }; |
| |
| template <class Key, class Mapped, class Compare> |
| struct ParamTraits<base::flat_map<Key, Mapped, Compare>> { |
| using param_type = base::flat_map<Key, Mapped, Compare>; |
| static void GetSize(base::PickleSizer* sizer, const param_type& p) { |
| DCHECK(base::IsValueInRangeForNumericType<int>(p.size())); |
| GetParamSize(sizer, static_cast<int>(p.size())); |
| for (const auto& iter : p) { |
| GetParamSize(sizer, iter.first); |
| GetParamSize(sizer, iter.second); |
| } |
| } |
| static void Write(base::Pickle* m, const param_type& p) { |
| DCHECK(base::IsValueInRangeForNumericType<int>(p.size())); |
| WriteParam(m, static_cast<int>(p.size())); |
| for (const auto& iter : p) { |
| 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; |
| |
| // Construct by creating in a vector and moving into the flat_map. Properly |
| // serialized flat_maps will be in-order so this will be O(n). Incorrectly |
| // serialized ones will still be handled properly. |
| std::vector<typename param_type::value_type> vect; |
| vect.resize(size); |
| for (int i = 0; i < size; ++i) { |
| if (!ReadParam(m, iter, &vect[i].first)) |
| return false; |
| if (!ReadParam(m, iter, &vect[i].second)) |
| return false; |
| } |
| |
| *r = param_type(std::move(vect), base::KEEP_FIRST_OF_DUPES); |
| return true; |
| } |
| static void Log(const param_type& p, std::string* l) { |
| l->append("<base::flat_map>"); |
| } |
| }; |
| |
| 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 BUILDFLAG(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_ |