/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ // Copyright (c) 2006-2008 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 CHROME_COMMON_IPC_MESSAGE_UTILS_H_ #define CHROME_COMMON_IPC_MESSAGE_UTILS_H_ #include #include #include #include "base/file_path.h" #include "base/string_util.h" #include "base/string16.h" #include "base/time.h" #if defined(OS_POSIX) #include "chrome/common/file_descriptor_set_posix.h" #endif #include "chrome/common/ipc_message.h" #include "chrome/common/transport_dib.h" namespace IPC { //----------------------------------------------------------------------------- // An iterator class for reading the fields contained within a Message. class MessageIterator { public: explicit MessageIterator(const Message& m) : msg_(m), iter_(m) { } int NextInt() const { int val; if (!msg_.ReadInt(&iter_, &val)) NOTREACHED(); return val; } intptr_t NextIntPtr() const { intptr_t val; if (!msg_.ReadIntPtr(&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; } private: const Message& msg_; mutable PickleIterator iter_; }; //----------------------------------------------------------------------------- // ParamTraits specializations, etc. // // The full set of types ParamTraits is specialized upon contains *possibly* // repeated types: unsigned long may be uint32_t or size_t, unsigned long long // may be uint64_t or size_t, nsresult may be uint32_t, and so on. You can't // have ParamTraits *and* ParamTraits if unsigned int // is uint32_t -- that's multiple definitions, and you can only have one. // // You could use #ifs and macro conditions to avoid duplicates, but they'd be // hairy: heavily dependent upon OS and compiler author choices, forced to // address all conflicts by hand. Happily there's a better way. The basic // idea looks like this, where T -> U represents T inheriting from U: // // class ParamTraits

// | // --> class ParamTraits1

// | // --> class ParamTraits2

// | // --> class ParamTraitsN

// or however many levels // // The default specialization of ParamTraits{M}

is an empty class that // inherits from ParamTraits{M + 1}

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

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

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

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

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

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

::Log(p, l); } // Fundamental types. template struct ParamTraitsFundamental {}; template <> struct ParamTraitsFundamental { typedef bool param_type; static void Write(Message* m, const param_type& p) { m->WriteBool(p); } static bool Read(const Message* m, PickleIterator* iter, param_type* r) { return m->ReadBool(iter, r); } static void Log(const param_type& p, std::wstring* l) { l->append(p ? L"true" : L"false"); } }; template <> struct ParamTraitsFundamental { typedef int param_type; static void Write(Message* m, const param_type& p) { m->WriteInt(p); } static bool Read(const Message* m, PickleIterator* iter, param_type* r) { return m->ReadInt(iter, r); } static void Log(const param_type& p, std::wstring* l) { l->append(StringPrintf(L"%d", p)); } }; template <> struct ParamTraitsFundamental { typedef long param_type; static void Write(Message* m, const param_type& p) { m->WriteLong(p); } static bool Read(const Message* m, PickleIterator* iter, param_type* r) { return m->ReadLong(iter, r); } static void Log(const param_type& p, std::wstring* l) { l->append(StringPrintf(L"%l", p)); } }; template <> struct ParamTraitsFundamental { typedef unsigned long param_type; static void Write(Message* m, const param_type& p) { m->WriteULong(p); } static bool Read(const Message* m, PickleIterator* iter, param_type* r) { return m->ReadULong(iter, r); } static void Log(const param_type& p, std::wstring* l) { l->append(StringPrintf(L"%ul", p)); } }; template <> struct ParamTraitsFundamental { typedef long long param_type; static void Write(Message* m, const param_type& p) { m->WriteBytes(&p, sizeof(param_type)); } static bool Read(const Message* m, PickleIterator* iter, param_type* r) { return m->ReadBytesInto(iter, r, sizeof(*r)); } static void Log(const param_type& p, std::wstring* l) { l->append(StringPrintf(L"%ll", p)); } }; template <> struct ParamTraitsFundamental { typedef unsigned long long param_type; static void Write(Message* m, const param_type& p) { m->WriteBytes(&p, sizeof(param_type)); } static bool Read(const Message* m, PickleIterator* iter, param_type* r) { return m->ReadBytesInto(iter, r, sizeof(*r)); } static void Log(const param_type& p, std::wstring* l) { l->append(StringPrintf(L"%ull", p)); } }; template <> struct ParamTraitsFundamental { typedef double param_type; static void Write(Message* m, const param_type& p) { m->WriteDouble(p); } static bool Read(const Message* m, PickleIterator* iter, param_type* r) { return m->ReadDouble(iter, r); } static void Log(const param_type& p, std::wstring* l) { l->append(StringPrintf(L"e", p)); } }; // Fixed-size types. template struct ParamTraitsFixed : ParamTraitsFundamental

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

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

{}; template <> struct ParamTraitsStd { typedef std::string param_type; static void Write(Message* m, const param_type& p) { m->WriteString(p); } static bool Read(const Message* m, PickleIterator* iter, param_type* r) { return m->ReadString(iter, r); } static void Log(const param_type& p, std::wstring* l) { l->append(UTF8ToWide(p)); } }; template <> struct ParamTraitsStd { typedef std::wstring param_type; static void Write(Message* m, const param_type& p) { m->WriteWString(p); } static bool Read(const Message* m, PickleIterator* iter, param_type* r) { return m->ReadWString(iter, r); } static void Log(const param_type& p, std::wstring* l) { l->append(p); } }; template struct ParamTraitsStd > { typedef std::map param_type; static void Write(Message* m, const param_type& p) { WriteParam(m, static_cast(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, 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::wstring* l) { l->append(L""); } }; // Windows-specific types. template struct ParamTraitsWindows : ParamTraitsStd

{}; #if defined(OS_WIN) template <> struct ParamTraitsWindows { typedef HANDLE param_type; static void Write(Message* m, const param_type& p) { m->WriteIntPtr(reinterpret_cast(p)); } static bool Read(const Message* m, PickleIterator* iter, param_type* r) { DCHECK_EQ(sizeof(param_type), sizeof(intptr_t)); return m->ReadIntPtr(iter, reinterpret_cast(r)); } static void Log(const param_type& p, std::wstring* l) { l->append(StringPrintf(L"0x%X", p)); } }; template <> struct ParamTraitsWindows { typedef HWND param_type; static void Write(Message* m, const param_type& p) { m->WriteIntPtr(reinterpret_cast(p)); } static bool Read(const Message* m, PickleIterator* iter, param_type* r) { DCHECK_EQ(sizeof(param_type), sizeof(intptr_t)); return m->ReadIntPtr(iter, reinterpret_cast(r)); } static void Log(const param_type& p, std::wstring* l) { l->append(StringPrintf(L"0x%X", p)); } }; #endif // defined(OS_WIN) // Various ipc/chromium types. template struct ParamTraitsIPC : ParamTraitsWindows

{}; #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 ParamTraitsIPC { typedef base::FileDescriptor param_type; static void Write(Message* m, const param_type& p) { const bool valid = p.fd >= 0; WriteParam(m, valid); if (valid) { if (!m->WriteFileDescriptor(p)) { NOTREACHED() << "Too many file descriptors for one message!"; } } } static bool Read(const Message* m, PickleIterator* iter, param_type* r) { bool valid; if (!ReadParam(m, iter, &valid)) return false; if (!valid) { r->fd = -1; r->auto_close = false; return true; } return m->ReadFileDescriptor(iter, r); } static void Log(const param_type& p, std::wstring* l) { if (p.auto_close) { l->append(StringPrintf(L"FD(%d auto-close)", p.fd)); } else { l->append(StringPrintf(L"FD(%d)", p.fd)); } } }; #endif // defined(OS_POSIX) #if defined(OS_WIN) template<> struct ParamTraitsIPC { typedef TransportDIB::Id param_type; static void Write(Message* m, const param_type& p) { WriteParam(m, p.handle); WriteParam(m, p.sequence_num); } static bool Read(const Message* m, PickleIterator* iter, param_type* r) { return (ReadParam(m, iter, &r->handle) && ReadParam(m, iter, &r->sequence_num)); } static void Log(const param_type& p, std::wstring* l) { l->append(L"TransportDIB("); LogParam(p.handle, l); l->append(L", "); LogParam(p.sequence_num, l); l->append(L")"); } }; #endif // Mozilla-specific types. template struct ParamTraitsMozilla : ParamTraitsIPC

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

{}; } // namespace IPC #endif // CHROME_COMMON_IPC_MESSAGE_UTILS_H_