diff options
author | brettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-06-29 00:05:04 +0000 |
---|---|---|
committer | brettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-06-29 00:05:04 +0000 |
commit | 34d4861069f6528aac208a3268f8c4946d301a16 (patch) | |
tree | 0efd4735b9912a93b220f9e312d7ca14cf281360 /ipc | |
parent | b9ef2965a07ca50fd94f1ab1d22ffcfdf62a2b6d (diff) | |
download | chromium_src-34d4861069f6528aac208a3268f8c4946d301a16.zip chromium_src-34d4861069f6528aac208a3268f8c4946d301a16.tar.gz chromium_src-34d4861069f6528aac208a3268f8c4946d301a16.tar.bz2 |
Make the serialization of IPC::Messages inside other IPC::Messages independent
of the platform.
This is necessary for sending nested messages between nacl (which the IPC
system thinks is posix and so has extra header goo) and a Windows client app
(which doesn't have this stuff).
BUG=
Review URL: https://chromiumcodereview.appspot.com/10667002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@144840 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ipc')
-rw-r--r-- | ipc/ipc.gyp | 1 | ||||
-rw-r--r-- | ipc/ipc_message.cc | 13 | ||||
-rw-r--r-- | ipc/ipc_message.h | 10 | ||||
-rw-r--r-- | ipc/ipc_message_utils.cc | 41 | ||||
-rw-r--r-- | ipc/ipc_message_utils_unittest.cc | 53 |
5 files changed, 107 insertions, 11 deletions
diff --git a/ipc/ipc.gyp b/ipc/ipc.gyp index 5f1762e..3c62aaa 100644 --- a/ipc/ipc.gyp +++ b/ipc/ipc.gyp @@ -48,6 +48,7 @@ 'ipc_channel_posix_unittest.cc', 'ipc_fuzzing_tests.cc', 'ipc_message_unittest.cc', + 'ipc_message_utils_unittest.cc', 'ipc_send_fds_test.cc', 'ipc_sync_channel_unittest.cc', 'ipc_sync_message_unittest.cc', diff --git a/ipc/ipc_message.cc b/ipc/ipc_message.cc index feec91a..9908bc7 100644 --- a/ipc/ipc_message.cc +++ b/ipc/ipc_message.cc @@ -67,6 +67,15 @@ Message& Message::operator=(const Message& other) { return *this; } +void Message::SetHeaderValues(int32 routing, uint32 type, uint32 flags) { + // This should only be called when the message is already empty. + DCHECK(payload_size() == 0); + + header()->routing = routing; + header()->type = type; + header()->flags = flags; +} + #ifdef IPC_MESSAGE_LOG_ENABLED void Message::set_sent_time(int64 time) { DCHECK((header()->flags & HAS_SENT_TIME_BIT) == 0); @@ -116,6 +125,10 @@ bool Message::ReadFileDescriptor(PickleIterator* iter, return descriptor->fd >= 0; } +bool Message::HasFileDescriptors() const { + return file_descriptor_set_.get() && !file_descriptor_set_->empty(); +} + void Message::EnsureFileDescriptorSet() { if (file_descriptor_set_.get() == NULL) file_descriptor_set_ = new FileDescriptorSet; diff --git a/ipc/ipc_message.h b/ipc/ipc_message.h index c3d4296..098a010 100644 --- a/ipc/ipc_message.h +++ b/ipc/ipc_message.h @@ -149,6 +149,10 @@ class IPC_EXPORT Message : public Pickle { return header()->flags; } + // Sets all the given header values. The message should be empty at this + // call. + void SetHeaderValues(int32 routing, uint32 type, uint32 flags); + template<class T, class S> static bool Dispatch(const Message* msg, T* obj, S* sender, void (T::*func)()) { @@ -191,12 +195,16 @@ class IPC_EXPORT Message : public Pickle { // On POSIX, a message supports reading / writing FileDescriptor objects. // This is used to pass a file descriptor to the peer of an IPC channel. - // Add a descriptor to the end of the set. Returns false iff the set is full. + // Add a descriptor to the end of the set. Returns false if the set is full. bool WriteFileDescriptor(const base::FileDescriptor& descriptor); + // Get a file descriptor from the message. Returns false on error. // iter: a Pickle iterator to the current location in the message. bool ReadFileDescriptor(PickleIterator* iter, base::FileDescriptor* descriptor) const; + + // Returns true if there are any file descriptors in this message. + bool HasFileDescriptors() const; #endif #ifdef IPC_MESSAGE_LOG_ENABLED diff --git a/ipc/ipc_message_utils.cc b/ipc/ipc_message_utils.cc index a8392cf..66a6877 100644 --- a/ipc/ipc_message_utils.cc +++ b/ipc/ipc_message_utils.cc @@ -730,22 +730,43 @@ void ParamTraits<LogData>::Log(const param_type& p, std::string* l) { } void ParamTraits<Message>::Write(Message* m, const Message& p) { - DCHECK(p.size() <= INT_MAX); - int message_size = static_cast<int>(p.size()); - m->WriteInt(message_size); - m->WriteData(reinterpret_cast<const char*>(p.data()), message_size); +#if defined(OS_POSIX) + // We don't serialize the file descriptors in the nested message, so there + // better not be any. + DCHECK(!p.HasFileDescriptors()); +#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<uint32>(p.routing_id())); + m->WriteUInt32(p.type()); + m->WriteUInt32(p.flags()); + m->WriteData(p.payload(), static_cast<uint32>(p.payload_size())); } bool ParamTraits<Message>::Read(const Message* m, PickleIterator* iter, Message* r) { - int size; - if (!m->ReadInt(iter, &size)) + uint32 routing_id, type, flags; + if (!m->ReadUInt32(iter, &routing_id) || + !m->ReadUInt32(iter, &type) || + !m->ReadUInt32(iter, &flags)) return false; - const char* data; - if (!m->ReadData(iter, &data, &size)) + + int payload_size; + const char* payload; + if (!m->ReadData(iter, &payload, &payload_size)) return false; - *r = Message(data, size); - return true; + + r->SetHeaderValues(static_cast<int32>(routing_id), type, flags); + return r->WriteBytes(payload, payload_size); } void ParamTraits<Message>::Log(const Message& p, std::string* l) { diff --git a/ipc/ipc_message_utils_unittest.cc b/ipc/ipc_message_utils_unittest.cc new file mode 100644 index 0000000..19726a0 --- /dev/null +++ b/ipc/ipc_message_utils_unittest.cc @@ -0,0 +1,53 @@ +// 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.h" +#include "ipc/ipc_message_utils.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace IPC { + +// Tests nesting of messages as parameters to other messages. +TEST(IPCMessageUtilsTest, NestedMessages) { + int32 nested_routing = 12; + uint32 nested_type = 78; + int nested_content = 456789; + Message::PriorityValue nested_priority = Message::PRIORITY_HIGH; + Message nested_msg(nested_routing, nested_type, nested_priority); + nested_msg.set_sync(); + ParamTraits<int>::Write(&nested_msg, nested_content); + + // Outer message contains the nested one as its parameter. + int32 outer_routing = 91; + uint32 outer_type = 88; + Message::PriorityValue outer_priority = Message::PRIORITY_NORMAL; + Message outer_msg(outer_routing, outer_type, outer_priority); + ParamTraits<Message>::Write(&outer_msg, nested_msg); + + // Read back the nested message. + PickleIterator iter(outer_msg); + IPC::Message result_msg; + ASSERT_TRUE(ParamTraits<Message>::Read(&outer_msg, &iter, &result_msg)); + + // Verify nested message headers. + EXPECT_EQ(nested_msg.routing_id(), result_msg.routing_id()); + EXPECT_EQ(nested_msg.type(), result_msg.type()); + EXPECT_EQ(nested_msg.priority(), result_msg.priority()); + EXPECT_EQ(nested_msg.flags(), result_msg.flags()); + + // Verify nested message content + PickleIterator nested_iter(nested_msg); + int result_content = 0; + ASSERT_TRUE(ParamTraits<int>::Read(&nested_msg, &nested_iter, + &result_content)); + EXPECT_EQ(nested_content, result_content); + + // Try reading past the ends for both messages and make sure it fails. + IPC::Message dummy; + ASSERT_FALSE(ParamTraits<Message>::Read(&outer_msg, &iter, &dummy)); + ASSERT_FALSE(ParamTraits<int>::Read(&nested_msg, &nested_iter, + &result_content)); +} + +} // namespace IPC |