summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--base/pickle.h13
-rw-r--r--ipc/ipc.gyp1
-rw-r--r--ipc/ipc_message.cc13
-rw-r--r--ipc/ipc_message.h10
-rw-r--r--ipc/ipc_message_utils.cc41
-rw-r--r--ipc/ipc_message_utils_unittest.cc53
6 files changed, 120 insertions, 11 deletions
diff --git a/base/pickle.h b/base/pickle.h
index 2420f75..0eea490 100644
--- a/base/pickle.h
+++ b/base/pickle.h
@@ -168,9 +168,17 @@ class BASE_EXPORT Pickle {
bool ReadString16(PickleIterator* iter, string16* result) const {
return iter->ReadString16(result);
}
+ // A pointer to the data will be placed in *data, and the length will be
+ // placed in *length. This buffer will be into the message's buffer so will
+ // be scoped to the lifetime of the message (or until the message data is
+ // mutated).
bool ReadData(PickleIterator* iter, const char** data, int* length) const {
return iter->ReadData(data, length);
}
+ // A pointer to the data will be placed in *data. The caller specifies the
+ // number of bytes to read, and ReadBytes will validate this length. The
+ // returned buffer will be into the message's buffer so will be scoped to the
+ // lifetime of the message (or until the message data is mutated).
bool ReadBytes(PickleIterator* iter, const char** data, int length) const {
return iter->ReadBytes(data, length);
}
@@ -214,7 +222,12 @@ class BASE_EXPORT Pickle {
bool WriteString(const std::string& value);
bool WriteWString(const std::wstring& value);
bool WriteString16(const string16& value);
+ // "Data" is a blob with a length. When you read it out you will be given the
+ // length. See also WriteBytes.
bool WriteData(const char* data, int length);
+ // "Bytes" is a blob with no length. The caller must specify the lenght both
+ // when reading and writing. It is normally used to serialize PoD types of a
+ // known size. See also WriteData.
bool WriteBytes(const void* data, int data_len);
// Same as WriteData, but allows the caller to write directly into the
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