// 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. #include "ipc/ipc_message_utils.h" #include #include #include "base/files/file_path.h" #include "base/json/json_writer.h" #include "base/strings/nullable_string16.h" #include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" #include "base/time/time.h" #include "base/unguessable_token.h" #include "base/values.h" #include "build/build_config.h" #include "ipc/ipc_channel_handle.h" #include "ipc/ipc_message_attachment.h" #include "ipc/ipc_message_attachment_set.h" #include "ipc/ipc_mojo_param_traits.h" #if defined(OS_POSIX) #include "ipc/ipc_platform_file_attachment_posix.h" #endif #if (defined(OS_MACOSX) && !defined(OS_IOS)) || defined(OS_WIN) #include "base/memory/shared_memory_handle.h" #endif // (defined(OS_MACOSX) && !defined(OS_IOS)) || defined(OS_WIN) #if defined(OS_MACOSX) && !defined(OS_IOS) #include "ipc/mach_port_mac.h" #endif #if defined(OS_WIN) #include #include "ipc/handle_win.h" #endif namespace IPC { namespace { const int kMaxRecursionDepth = 100; template void LogBytes(const std::vector& 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( base::StringPrintf("[%02X]", static_cast(data[i]))); } if (data.size() > kMaxBytesToLog) { out->append(base::StringPrintf( " and %u more bytes", static_cast(data.size() - kMaxBytesToLog))); } #endif } bool ReadValue(const base::Pickle* m, base::PickleIterator* iter, base::Value** value, int recursion); void GetValueSize(base::PickleSizer* sizer, const base::Value* value, int recursion) { if (recursion > kMaxRecursionDepth) { LOG(WARNING) << "Max recursion depth hit in GetValueSize."; return; } sizer->AddInt(); switch (value->GetType()) { case base::Value::TYPE_NULL: break; case base::Value::TYPE_BOOLEAN: sizer->AddBool(); break; case base::Value::TYPE_INTEGER: sizer->AddInt(); break; case base::Value::TYPE_DOUBLE: sizer->AddDouble(); break; case base::Value::TYPE_STRING: { const base::StringValue* result; value->GetAsString(&result); if (value->GetAsString(&result)) { DCHECK(result); GetParamSize(sizer, result->GetString()); } else { std::string str; bool as_string_result = value->GetAsString(&str); DCHECK(as_string_result); GetParamSize(sizer, str); } break; } case base::Value::TYPE_BINARY: { const base::BinaryValue* binary = static_cast(value); sizer->AddData(static_cast(binary->GetSize())); break; } case base::Value::TYPE_DICTIONARY: { sizer->AddInt(); const base::DictionaryValue* dict = static_cast(value); for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); it.Advance()) { GetParamSize(sizer, it.key()); GetValueSize(sizer, &it.value(), recursion + 1); } break; } case base::Value::TYPE_LIST: { sizer->AddInt(); const base::ListValue* list = static_cast(value); for (const auto& entry : *list) { GetValueSize(sizer, entry.get(), recursion + 1); } break; } default: NOTREACHED() << "Invalid base::Value type."; } } void WriteValue(base::Pickle* m, const base::Value* value, int recursion) { bool result; if (recursion > kMaxRecursionDepth) { LOG(WARNING) << "Max recursion depth hit in WriteValue."; return; } m->WriteInt(value->GetType()); switch (value->GetType()) { case base::Value::TYPE_NULL: break; case base::Value::TYPE_BOOLEAN: { bool val; result = value->GetAsBoolean(&val); DCHECK(result); WriteParam(m, val); break; } case base::Value::TYPE_INTEGER: { int val; result = value->GetAsInteger(&val); DCHECK(result); WriteParam(m, val); break; } case base::Value::TYPE_DOUBLE: { double val; result = value->GetAsDouble(&val); DCHECK(result); WriteParam(m, val); break; } case base::Value::TYPE_STRING: { std::string val; result = value->GetAsString(&val); DCHECK(result); WriteParam(m, val); break; } case base::Value::TYPE_BINARY: { const base::BinaryValue* binary = static_cast(value); m->WriteData(binary->GetBuffer(), static_cast(binary->GetSize())); break; } case base::Value::TYPE_DICTIONARY: { const base::DictionaryValue* dict = static_cast(value); WriteParam(m, static_cast(dict->size())); for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); it.Advance()) { WriteParam(m, it.key()); WriteValue(m, &it.value(), recursion + 1); } break; } case base::Value::TYPE_LIST: { const base::ListValue* list = static_cast(value); WriteParam(m, static_cast(list->GetSize())); for (const auto& entry : *list) { WriteValue(m, entry.get(), recursion + 1); } break; } } } // Helper for ReadValue that reads a DictionaryValue into a pre-allocated // object. bool ReadDictionaryValue(const base::Pickle* m, base::PickleIterator* iter, base::DictionaryValue* value, int recursion) { int size; if (!ReadParam(m, iter, &size)) return false; for (int i = 0; i < size; ++i) { std::string key; base::Value* subval; if (!ReadParam(m, iter, &key) || !ReadValue(m, iter, &subval, recursion + 1)) return false; value->SetWithoutPathExpansion(key, subval); } return true; } // Helper for ReadValue that reads a ReadListValue into a pre-allocated // object. bool ReadListValue(const base::Pickle* m, base::PickleIterator* iter, base::ListValue* value, int recursion) { int size; if (!ReadParam(m, iter, &size)) return false; for (int i = 0; i < size; ++i) { base::Value* subval; if (!ReadValue(m, iter, &subval, recursion + 1)) return false; value->Set(i, subval); } return true; } bool ReadValue(const base::Pickle* m, base::PickleIterator* iter, base::Value** value, int recursion) { if (recursion > kMaxRecursionDepth) { LOG(WARNING) << "Max recursion depth hit in ReadValue."; return false; } int type; if (!ReadParam(m, iter, &type)) return false; switch (type) { case base::Value::TYPE_NULL: *value = base::Value::CreateNullValue().release(); break; case base::Value::TYPE_BOOLEAN: { bool val; if (!ReadParam(m, iter, &val)) return false; *value = new base::FundamentalValue(val); break; } case base::Value::TYPE_INTEGER: { int val; if (!ReadParam(m, iter, &val)) return false; *value = new base::FundamentalValue(val); break; } case base::Value::TYPE_DOUBLE: { double val; if (!ReadParam(m, iter, &val)) return false; *value = new base::FundamentalValue(val); break; } case base::Value::TYPE_STRING: { std::string val; if (!ReadParam(m, iter, &val)) return false; *value = new base::StringValue(val); break; } case base::Value::TYPE_BINARY: { const char* data; int length; if (!iter->ReadData(&data, &length)) return false; std::unique_ptr val = base::BinaryValue::CreateWithCopiedBuffer(data, length); *value = val.release(); break; } case base::Value::TYPE_DICTIONARY: { std::unique_ptr val(new base::DictionaryValue()); if (!ReadDictionaryValue(m, iter, val.get(), recursion)) return false; *value = val.release(); break; } case base::Value::TYPE_LIST: { std::unique_ptr val(new base::ListValue()); if (!ReadListValue(m, iter, val.get(), recursion)) return false; *value = val.release(); break; } default: return false; } return true; } } // namespace // ----------------------------------------------------------------------------- LogData::LogData() : routing_id(0), type(0), sent(0), receive(0), dispatch(0) { } LogData::LogData(const LogData& other) = default; LogData::~LogData() { } void ParamTraits::Log(const param_type& p, std::string* l) { l->append(p ? "true" : "false"); } void ParamTraits::GetSize(base::PickleSizer* sizer, const param_type& p) { sizer->AddBytes(sizeof(param_type)); } void ParamTraits::Write(base::Pickle* m, const param_type& p) { m->WriteBytes(&p, sizeof(param_type)); } bool ParamTraits::Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { const char* data; if (!iter->ReadBytes(&data, sizeof(param_type))) return false; memcpy(r, data, sizeof(param_type)); return true; } void ParamTraits::Log(const param_type& p, std::string* l) { l->append(base::IntToString(p)); } void ParamTraits::GetSize(base::PickleSizer* sizer, const param_type& p) { sizer->AddBytes(sizeof(param_type)); } void ParamTraits::Write(base::Pickle* m, const param_type& p) { m->WriteBytes(&p, sizeof(param_type)); } bool ParamTraits::Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { const char* data; if (!iter->ReadBytes(&data, sizeof(param_type))) return false; memcpy(r, data, sizeof(param_type)); return true; } void ParamTraits::Log(const param_type& p, std::string* l) { l->append(base::UintToString(p)); } void ParamTraits::GetSize(base::PickleSizer* sizer, const param_type& p) { sizer->AddBytes(sizeof(param_type)); } void ParamTraits::Write(base::Pickle* m, const param_type& p) { m->WriteBytes(&p, sizeof(param_type)); } bool ParamTraits::Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { const char* data; if (!iter->ReadBytes(&data, sizeof(param_type))) return false; memcpy(r, data, sizeof(param_type)); return true; } void ParamTraits::Log(const param_type& p, std::string* l) { l->append(base::UintToString(p)); } void ParamTraits::Log(const param_type& p, std::string* l) { l->append(base::IntToString(p)); } void ParamTraits::Log(const param_type& p, std::string* l) { l->append(base::UintToString(p)); } #if defined(OS_WIN) || defined(OS_LINUX) || \ (defined(OS_ANDROID) && defined(ARCH_CPU_64_BITS)) void ParamTraits::Log(const param_type& p, std::string* l) { l->append(base::Int64ToString(static_cast(p))); } void ParamTraits::Log(const param_type& p, std::string* l) { l->append(base::Uint64ToString(static_cast(p))); } #endif void ParamTraits::Log(const param_type& p, std::string* l) { l->append(base::Int64ToString(static_cast(p))); } void ParamTraits::Log(const param_type& p, std::string* l) { l->append(base::Uint64ToString(p)); } void ParamTraits::Log(const param_type& p, std::string* l) { l->append(base::StringPrintf("%e", p)); } void ParamTraits::GetSize(base::PickleSizer* sizer, const param_type& p) { sizer->AddBytes(sizeof(param_type)); } void ParamTraits::Write(base::Pickle* m, const param_type& p) { m->WriteBytes(reinterpret_cast(&p), sizeof(param_type)); } bool ParamTraits::Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { const char *data; if (!iter->ReadBytes(&data, sizeof(*r))) { NOTREACHED(); return false; } memcpy(r, data, sizeof(param_type)); return true; } void ParamTraits::Log(const param_type& p, std::string* l) { l->append(base::StringPrintf("%e", p)); } void ParamTraits::Log(const param_type& p, std::string* l) { l->append(p); } void ParamTraits::Log(const param_type& p, std::string* l) { l->append(base::UTF16ToUTF8(p)); } void ParamTraits>::GetSize(base::PickleSizer* sizer, const param_type& p) { sizer->AddData(static_cast(p.size())); } void ParamTraits>::Write(base::Pickle* m, const param_type& p) { if (p.empty()) { m->WriteData(NULL, 0); } else { m->WriteData(&p.front(), static_cast(p.size())); } } bool ParamTraits>::Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { const char *data; int data_size = 0; if (!iter->ReadData(&data, &data_size) || data_size < 0) return false; r->resize(data_size); if (data_size) memcpy(&r->front(), data, data_size); return true; } void ParamTraits >::Log(const param_type& p, std::string* l) { LogBytes(p, l); } void ParamTraits>::GetSize(base::PickleSizer* sizer, const param_type& p) { sizer->AddData(static_cast(p.size())); } void ParamTraits>::Write(base::Pickle* m, const param_type& p) { if (p.empty()) { m->WriteData(NULL, 0); } else { m->WriteData(reinterpret_cast(&p.front()), static_cast(p.size())); } } bool ParamTraits>::Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { const char *data; int data_size = 0; if (!iter->ReadData(&data, &data_size) || data_size < 0) return false; r->resize(data_size); if (data_size) memcpy(&r->front(), data, data_size); return true; } void ParamTraits >::Log(const param_type& p, std::string* l) { LogBytes(p, l); } void ParamTraits>::GetSize(base::PickleSizer* sizer, const param_type& p) { GetParamSize(sizer, static_cast(p.size())); for (size_t i = 0; i < p.size(); ++i) GetParamSize(sizer, static_cast(p[i])); } void ParamTraits>::Write(base::Pickle* m, const param_type& p) { WriteParam(m, static_cast(p.size())); // Cast to bool below is required because libc++'s // vector::const_reference is different from bool, and we want to avoid // writing an extra specialization of ParamTraits for it. for (size_t i = 0; i < p.size(); i++) WriteParam(m, static_cast(p[i])); } bool ParamTraits>::Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { int size; // ReadLength() checks for < 0 itself. if (!iter->ReadLength(&size)) return false; r->resize(size); for (int i = 0; i < size; i++) { bool value; if (!ReadParam(m, iter, &value)) return false; (*r)[i] = value; } return true; } void ParamTraits >::Log(const param_type& p, std::string* l) { for (size_t i = 0; i < p.size(); ++i) { if (i != 0) l->push_back(' '); LogParam(static_cast(p[i]), l); } } void ParamTraits::Write( base::Pickle* m, const param_type& p) { m->WriteBytes(p.nonce, BrokerableAttachment::kNonceSize); } bool ParamTraits::Read( const base::Pickle* m, base::PickleIterator* iter, param_type* r) { const char* data; if (!iter->ReadBytes(&data, BrokerableAttachment::kNonceSize)) return false; memcpy(r->nonce, data, BrokerableAttachment::kNonceSize); return true; } void ParamTraits::Log(const param_type& p, std::string* l) { l->append(base::HexEncode(p.nonce, BrokerableAttachment::kNonceSize)); } void ParamTraits::GetSize(base::PickleSizer* sizer, const param_type& p) { GetValueSize(sizer, &p, 0); } void ParamTraits::Write(base::Pickle* m, const param_type& p) { WriteValue(m, &p, 0); } bool ParamTraits::Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { int type; if (!ReadParam(m, iter, &type) || type != base::Value::TYPE_DICTIONARY) return false; return ReadDictionaryValue(m, iter, r, 0); } void ParamTraits::Log(const param_type& p, std::string* l) { std::string json; base::JSONWriter::Write(p, &json); l->append(json); } #if defined(OS_POSIX) void ParamTraits::GetSize(base::PickleSizer* sizer, const param_type& p) { GetParamSize(sizer, p.fd >= 0); if (p.fd >= 0) sizer->AddAttachment(); } void ParamTraits::Write(base::Pickle* m, const param_type& p) { const bool valid = p.fd >= 0; WriteParam(m, valid); if (!valid) return; if (p.auto_close) { if (!m->WriteAttachment( new internal::PlatformFileAttachment(base::ScopedFD(p.fd)))) NOTREACHED(); } else { if (!m->WriteAttachment(new internal::PlatformFileAttachment(p.fd))) NOTREACHED(); } } bool ParamTraits::Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { *r = base::FileDescriptor(); bool valid; if (!ReadParam(m, iter, &valid)) return false; // TODO(morrita): Seems like this should return false. if (!valid) return true; scoped_refptr attachment; if (!m->ReadAttachment(iter, &attachment)) return false; *r = base::FileDescriptor( static_cast(attachment.get())->TakePlatformFile(), true); return true; } void ParamTraits::Log(const param_type& p, std::string* l) { if (p.auto_close) { l->append(base::StringPrintf("FD(%d auto-close)", p.fd)); } else { l->append(base::StringPrintf("FD(%d)", p.fd)); } } #endif // defined(OS_POSIX) #if defined(OS_MACOSX) && !defined(OS_IOS) void ParamTraits::GetSize(base::PickleSizer* sizer, const param_type& p) { GetParamSize(sizer, p.GetMemoryObject()); uint32_t dummy = 0; GetParamSize(sizer, dummy); } void ParamTraits::Write(base::Pickle* m, const param_type& p) { MachPortMac mach_port_mac(p.GetMemoryObject()); ParamTraits::Write(m, mach_port_mac); size_t size = 0; bool result = p.GetSize(&size); DCHECK(result); ParamTraits::Write(m, static_cast(size)); // If the caller intended to pass ownership to the IPC stack, release a // reference. if (p.OwnershipPassesToIPC()) p.Close(); } bool ParamTraits::Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { MachPortMac mach_port_mac; if (!ParamTraits::Read(m, iter, &mach_port_mac)) return false; uint32_t size; if (!ParamTraits::Read(m, iter, &size)) return false; *r = base::SharedMemoryHandle(mach_port_mac.get_mach_port(), static_cast(size), base::GetCurrentProcId()); return true; } void ParamTraits::Log(const param_type& p, std::string* l) { l->append("Mach port: "); LogParam(p.GetMemoryObject(), l); } #elif defined(OS_WIN) void ParamTraits::GetSize(base::PickleSizer* s, const param_type& p) { GetParamSize(s, p.NeedsBrokering()); if (p.NeedsBrokering()) { GetParamSize(s, p.GetHandle()); } else { GetParamSize(s, HandleToLong(p.GetHandle())); } } void ParamTraits::Write(base::Pickle* m, const param_type& p) { m->WriteBool(p.NeedsBrokering()); if (p.NeedsBrokering()) { HandleWin handle_win(p.GetHandle(), HandleWin::DUPLICATE); ParamTraits::Write(m, handle_win); // If the caller intended to pass ownership to the IPC stack, release a // reference. if (p.OwnershipPassesToIPC() && p.BelongsToCurrentProcess()) p.Close(); } else { m->WriteInt(HandleToLong(p.GetHandle())); } } bool ParamTraits::Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { bool needs_brokering; if (!iter->ReadBool(&needs_brokering)) return false; if (needs_brokering) { HandleWin handle_win; if (!ParamTraits::Read(m, iter, &handle_win)) return false; *r = base::SharedMemoryHandle(handle_win.get_handle(), base::GetCurrentProcId()); return true; } int handle_int; if (!iter->ReadInt(&handle_int)) return false; HANDLE handle = LongToHandle(handle_int); *r = base::SharedMemoryHandle(handle, base::GetCurrentProcId()); return true; } void ParamTraits::Log(const param_type& p, std::string* l) { LogParam(p.GetHandle(), l); l->append(" needs brokering: "); LogParam(p.NeedsBrokering(), l); } #endif // defined(OS_MACOSX) && !defined(OS_IOS) void ParamTraits::GetSize(base::PickleSizer* sizer, const param_type& p) { p.GetSizeForPickle(sizer); } void ParamTraits::Write(base::Pickle* m, const param_type& p) { p.WriteToPickle(m); } bool ParamTraits::Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { return r->ReadFromPickle(iter); } void ParamTraits::Log(const param_type& p, std::string* l) { ParamTraits::Log(p.value(), l); } void ParamTraits::GetSize(base::PickleSizer* sizer, const param_type& p) { GetValueSize(sizer, &p, 0); } void ParamTraits::Write(base::Pickle* m, const param_type& p) { WriteValue(m, &p, 0); } bool ParamTraits::Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { int type; if (!ReadParam(m, iter, &type) || type != base::Value::TYPE_LIST) return false; return ReadListValue(m, iter, r, 0); } void ParamTraits::Log(const param_type& p, std::string* l) { std::string json; base::JSONWriter::Write(p, &json); l->append(json); } void ParamTraits::GetSize(base::PickleSizer* sizer, const param_type& p) { GetParamSize(sizer, p.string()); GetParamSize(sizer, p.is_null()); } void ParamTraits::Write(base::Pickle* m, const param_type& p) { WriteParam(m, p.string()); WriteParam(m, p.is_null()); } bool ParamTraits::Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { base::string16 string; if (!ReadParam(m, iter, &string)) return false; bool is_null; if (!ReadParam(m, iter, &is_null)) return false; *r = base::NullableString16(string, is_null); return true; } void ParamTraits::Log(const param_type& p, std::string* l) { l->append("("); LogParam(p.string(), l); l->append(", "); LogParam(p.is_null(), l); l->append(")"); } void ParamTraits::GetSize(base::PickleSizer* sizer, const param_type& p) { GetParamSize(sizer, p.size); GetParamSize(sizer, p.is_directory); GetParamSize(sizer, p.last_modified.ToDoubleT()); GetParamSize(sizer, p.last_accessed.ToDoubleT()); GetParamSize(sizer, p.creation_time.ToDoubleT()); } void ParamTraits::Write(base::Pickle* m, const param_type& p) { WriteParam(m, p.size); WriteParam(m, p.is_directory); WriteParam(m, p.last_modified.ToDoubleT()); WriteParam(m, p.last_accessed.ToDoubleT()); WriteParam(m, p.creation_time.ToDoubleT()); } bool ParamTraits::Read(const base::Pickle* m, base::PickleIterator* iter, param_type* p) { double last_modified, last_accessed, creation_time; if (!ReadParam(m, iter, &p->size) || !ReadParam(m, iter, &p->is_directory) || !ReadParam(m, iter, &last_modified) || !ReadParam(m, iter, &last_accessed) || !ReadParam(m, iter, &creation_time)) return false; p->last_modified = base::Time::FromDoubleT(last_modified); p->last_accessed = base::Time::FromDoubleT(last_accessed); p->creation_time = base::Time::FromDoubleT(creation_time); return true; } void ParamTraits::Log(const param_type& p, std::string* l) { l->append("("); LogParam(p.size, l); l->append(","); LogParam(p.is_directory, l); l->append(","); LogParam(p.last_modified.ToDoubleT(), l); l->append(","); LogParam(p.last_accessed.ToDoubleT(), l); l->append(","); LogParam(p.creation_time.ToDoubleT(), l); l->append(")"); } void ParamTraits::GetSize(base::PickleSizer* sizer, const param_type& p) { sizer->AddInt64(); } void ParamTraits::Write(base::Pickle* m, const param_type& p) { ParamTraits::Write(m, p.ToInternalValue()); } bool ParamTraits::Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { int64_t value; if (!ParamTraits::Read(m, iter, &value)) return false; *r = base::Time::FromInternalValue(value); return true; } void ParamTraits::Log(const param_type& p, std::string* l) { ParamTraits::Log(p.ToInternalValue(), l); } void ParamTraits::GetSize(base::PickleSizer* sizer, const param_type& p) { sizer->AddInt64(); } void ParamTraits::Write(base::Pickle* m, const param_type& p) { ParamTraits::Write(m, p.ToInternalValue()); } bool ParamTraits::Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { int64_t value; bool ret = ParamTraits::Read(m, iter, &value); if (ret) *r = base::TimeDelta::FromInternalValue(value); return ret; } void ParamTraits::Log(const param_type& p, std::string* l) { ParamTraits::Log(p.ToInternalValue(), l); } void ParamTraits::GetSize(base::PickleSizer* sizer, const param_type& p) { sizer->AddInt64(); } void ParamTraits::Write(base::Pickle* m, const param_type& p) { ParamTraits::Write(m, p.ToInternalValue()); } bool ParamTraits::Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { int64_t value; bool ret = ParamTraits::Read(m, iter, &value); if (ret) *r = base::TimeTicks::FromInternalValue(value); return ret; } void ParamTraits::Log(const param_type& p, std::string* l) { ParamTraits::Log(p.ToInternalValue(), l); } // If base::UnguessableToken is no longer 128 bits, the IPC serialization logic // below should be updated. static_assert(sizeof(base::UnguessableToken) == 2 * sizeof(uint64_t), "base::UnguessableToken should be of size 2 * sizeof(uint64_t)."); void ParamTraits::GetSize(base::PickleSizer* sizer, const param_type& p) { sizer->AddBytes(2 * sizeof(uint64_t)); } void ParamTraits::Write(base::Pickle* m, const param_type& p) { DCHECK(!p.is_empty()); ParamTraits::Write(m, p.GetHighForSerialization()); ParamTraits::Write(m, p.GetLowForSerialization()); } bool ParamTraits::Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { uint64_t high, low; if (!ParamTraits::Read(m, iter, &high) || !ParamTraits::Read(m, iter, &low)) return false; // Receiving a zeroed UnguessableToken is a security issue. if (high == 0 && low == 0) return false; *r = base::UnguessableToken::Deserialize(high, low); return true; } void ParamTraits::Log(const param_type& p, std::string* l) { l->append(p.ToString()); } void ParamTraits::GetSize(base::PickleSizer* sizer, const param_type& p) { GetParamSize(sizer, p.name); #if defined(OS_POSIX) GetParamSize(sizer, p.socket); #endif GetParamSize(sizer, p.mojo_handle); } void ParamTraits::Write(base::Pickle* m, const param_type& p) { #if defined(OS_WIN) // On Windows marshalling pipe handle is not supported. DCHECK(p.pipe.handle == NULL); #endif // defined (OS_WIN) WriteParam(m, p.name); #if defined(OS_POSIX) WriteParam(m, p.socket); #endif WriteParam(m, p.mojo_handle); } bool ParamTraits::Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { return ReadParam(m, iter, &r->name) #if defined(OS_POSIX) && ReadParam(m, iter, &r->socket) #endif && ReadParam(m, iter, &r->mojo_handle); } void ParamTraits::Log(const param_type& p, std::string* l) { l->append(base::StringPrintf("ChannelHandle(%s", p.name.c_str())); #if defined(OS_POSIX) l->append(", "); ParamTraits::Log(p.socket, l); #endif l->append(", "); LogParam(p.mojo_handle, l); l->append(")"); } void ParamTraits::GetSize(base::PickleSizer* sizer, const param_type& p) { GetParamSize(sizer, p.channel); GetParamSize(sizer, p.routing_id); GetParamSize(sizer, p.type); GetParamSize(sizer, p.flags); GetParamSize(sizer, p.sent); GetParamSize(sizer, p.receive); GetParamSize(sizer, p.dispatch); GetParamSize(sizer, p.message_name); GetParamSize(sizer, p.params); } void ParamTraits::Write(base::Pickle* m, const param_type& p) { WriteParam(m, p.channel); WriteParam(m, p.routing_id); WriteParam(m, p.type); WriteParam(m, p.flags); WriteParam(m, p.sent); WriteParam(m, p.receive); WriteParam(m, p.dispatch); WriteParam(m, p.message_name); WriteParam(m, p.params); } bool ParamTraits::Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { return ReadParam(m, iter, &r->channel) && ReadParam(m, iter, &r->routing_id) && ReadParam(m, iter, &r->type) && ReadParam(m, iter, &r->flags) && ReadParam(m, iter, &r->sent) && ReadParam(m, iter, &r->receive) && ReadParam(m, iter, &r->dispatch) && ReadParam(m, iter, &r->message_name) && ReadParam(m, iter, &r->params); } void ParamTraits::Log(const param_type& p, std::string* l) { // Doesn't make sense to implement this! } void ParamTraits::Write(base::Pickle* m, const Message& p) { #if defined(OS_POSIX) // We don't serialize the file descriptors in the nested message, so there // better not be any. DCHECK(!p.HasAttachments()); #endif // Don't just write out the message. This is used to send messages between // NaCl (Posix environment) and the browser (could be on Windows). The message // header formats differ between these systems (so does handle sharing, but // we already asserted we don't have any handles). So just write out the // parts of the header we use. // // Be careful also to use only explicitly-sized types. The NaCl environment // could be 64-bit and the host browser could be 32-bits. The nested message // may or may not be safe to send between 32-bit and 64-bit systems, but we // leave that up to the code sending the message to ensure. m->WriteUInt32(static_cast(p.routing_id())); m->WriteUInt32(p.type()); m->WriteUInt32(p.flags()); m->WriteData(p.payload(), static_cast(p.payload_size())); } bool ParamTraits::Read(const base::Pickle* m, base::PickleIterator* iter, Message* r) { uint32_t routing_id, type, flags; if (!iter->ReadUInt32(&routing_id) || !iter->ReadUInt32(&type) || !iter->ReadUInt32(&flags)) return false; int payload_size; const char* payload; if (!iter->ReadData(&payload, &payload_size)) return false; r->SetHeaderValues(static_cast(routing_id), type, flags); return r->WriteBytes(payload, payload_size); } void ParamTraits::Log(const Message& p, std::string* l) { l->append(""); } #if defined(OS_WIN) void ParamTraits::GetSize(base::PickleSizer* sizer, const param_type& p) { sizer->AddInt(); } // Note that HWNDs/HANDLE/HCURSOR/HACCEL etc are always 32 bits, even on 64 // bit systems. That's why we use the Windows macros to convert to 32 bits. void ParamTraits::Write(base::Pickle* m, const param_type& p) { m->WriteInt(HandleToLong(p)); } bool ParamTraits::Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { int32_t temp; if (!iter->ReadInt(&temp)) return false; *r = LongToHandle(temp); return true; } void ParamTraits::Log(const param_type& p, std::string* l) { l->append(base::StringPrintf("0x%p", p)); } void ParamTraits::GetSize(base::PickleSizer* sizer, const param_type& p) { sizer->AddData(sizeof(LOGFONT)); } void ParamTraits::Write(base::Pickle* m, const param_type& p) { m->WriteData(reinterpret_cast(&p), sizeof(LOGFONT)); } bool ParamTraits::Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { const char *data; int data_size = 0; if (iter->ReadData(&data, &data_size) && data_size == sizeof(LOGFONT)) { const LOGFONT *font = reinterpret_cast(const_cast(data)); if (_tcsnlen(font->lfFaceName, LF_FACESIZE) < LF_FACESIZE) { memcpy(r, data, sizeof(LOGFONT)); return true; } } NOTREACHED(); return false; } void ParamTraits::Log(const param_type& p, std::string* l) { l->append(base::StringPrintf("")); } void ParamTraits::GetSize(base::PickleSizer* sizer, const param_type& p) { sizer->AddData(sizeof(MSG)); } void ParamTraits::Write(base::Pickle* m, const param_type& p) { m->WriteData(reinterpret_cast(&p), sizeof(MSG)); } bool ParamTraits::Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { const char *data; int data_size = 0; bool result = iter->ReadData(&data, &data_size); if (result && data_size == sizeof(MSG)) { memcpy(r, data, sizeof(MSG)); } else { result = false; NOTREACHED(); } return result; } void ParamTraits::Log(const param_type& p, std::string* l) { l->append(""); } #endif // OS_WIN } // namespace IPC