Index: mojo/system/message_in_transit.cc |
diff --git a/mojo/system/message_in_transit.cc b/mojo/system/message_in_transit.cc |
index a38ac1ce7a62888e8e32b40f9321b0d097a7b87d..79f1184d9f686bd42f27cff78c34116d5de7c2c2 100644 |
--- a/mojo/system/message_in_transit.cc |
+++ b/mojo/system/message_in_transit.cc |
@@ -6,11 +6,10 @@ |
#include <string.h> |
-#include <new> |
- |
#include "base/compiler_specific.h" |
#include "base/logging.h" |
#include "mojo/system/constants.h" |
+#include "mojo/system/transport_data.h" |
namespace mojo { |
namespace system { |
@@ -32,10 +31,6 @@ STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Subtype |
STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::EndpointId |
MessageInTransit::kInvalidEndpointId; |
STATIC_CONST_MEMBER_DEFINITION const size_t MessageInTransit::kMessageAlignment; |
-STATIC_CONST_MEMBER_DEFINITION const size_t |
- MessageInTransit::kMaxSerializedDispatcherSize; |
-STATIC_CONST_MEMBER_DEFINITION const size_t |
- MessageInTransit::kMaxSerializedDispatcherPlatformHandles; |
struct MessageInTransit::PrivateStructForCompileAsserts { |
// The size of |Header| must be a multiple of the alignment. |
@@ -51,26 +46,8 @@ struct MessageInTransit::PrivateStructForCompileAsserts { |
// size is a multiple of the alignment. |
COMPILE_ASSERT(kMaxMessageNumBytes % kMessageAlignment == 0, |
kMessageAlignment_not_a_multiple_of_alignment); |
- |
- // The maximum serialized dispatcher size must be a multiple of the alignment. |
- COMPILE_ASSERT(kMaxSerializedDispatcherSize % kMessageAlignment == 0, |
- kMaxSerializedDispatcherSize_not_a_multiple_of_alignment); |
- |
- // The size of |HandleTableEntry| must be a multiple of the alignment. |
- COMPILE_ASSERT(sizeof(HandleTableEntry) % kMessageAlignment == 0, |
- sizeof_MessageInTransit_HandleTableEntry_invalid); |
}; |
-// For each attached (Mojo) handle, there'll be a handle table entry and |
-// serialized dispatcher data. |
-// static |
-const size_t MessageInTransit::kMaxSecondaryBufferSize = kMaxMessageNumHandles * |
- (sizeof(HandleTableEntry) + kMaxSerializedDispatcherSize); |
- |
-// static |
-const size_t MessageInTransit::kMaxPlatformHandles = |
- kMaxMessageNumHandles * kMaxSerializedDispatcherPlatformHandles; |
- |
MessageInTransit::View::View(size_t message_size, const void* buffer) |
: buffer_(buffer) { |
size_t next_message_size = 0; |
@@ -89,11 +66,13 @@ bool MessageInTransit::View::IsValid(const char** error_message) const { |
return false; |
} |
- if (const char* secondary_buffer_error_message = |
- ValidateSecondaryBuffer(num_handles(), secondary_buffer(), |
- secondary_buffer_size())) { |
- *error_message = secondary_buffer_error_message; |
- return false; |
+ if (transport_data_buffer_size() > 0) { |
+ const char* e = TransportData::ValidateBuffer(transport_data_buffer(), |
+ transport_data_buffer_size()); |
+ if (e) { |
+ *error_message = e; |
+ return false; |
+ } |
} |
return true; |
@@ -102,14 +81,11 @@ bool MessageInTransit::View::IsValid(const char** error_message) const { |
MessageInTransit::MessageInTransit(Type type, |
Subtype subtype, |
uint32_t num_bytes, |
- uint32_t num_handles, |
const void* bytes) |
: main_buffer_size_(RoundUpMessageAlignment(sizeof(Header) + num_bytes)), |
main_buffer_(static_cast<char*>(base::AlignedAlloc(main_buffer_size_, |
- kMessageAlignment))), |
- secondary_buffer_size_(0) { |
+ kMessageAlignment))) { |
DCHECK_LE(num_bytes, kMaxMessageNumBytes); |
- DCHECK_LE(num_handles, kMaxMessageNumHandles); |
// |total_size| is updated below, from the other values. |
header()->type = type; |
@@ -117,9 +93,8 @@ MessageInTransit::MessageInTransit(Type type, |
header()->source_id = kInvalidEndpointId; |
header()->destination_id = kInvalidEndpointId; |
header()->num_bytes = num_bytes; |
- header()->num_handles = num_handles; |
- // Note: If dispatchers are subsequently attached (in particular, if |
- // |num_handles| is nonzero), then |total_size| will have to be adjusted. |
+ // Note: If dispatchers are subsequently attached, then |total_size| will have |
+ // to be adjusted. |
UpdateTotalSize(); |
if (bytes) { |
@@ -131,24 +106,14 @@ MessageInTransit::MessageInTransit(Type type, |
} |
} |
-// TODO(vtl): Do I really want/need to copy the secondary buffer here, or should |
-// I just create (deserialize) the dispatchers right away? |
MessageInTransit::MessageInTransit(const View& message_view) |
: main_buffer_size_(message_view.main_buffer_size()), |
main_buffer_(static_cast<char*>(base::AlignedAlloc(main_buffer_size_, |
- kMessageAlignment))), |
- secondary_buffer_size_(message_view.secondary_buffer_size()), |
- secondary_buffer_(secondary_buffer_size_ ? |
- static_cast<char*>( |
- base::AlignedAlloc(secondary_buffer_size_, |
- kMessageAlignment)) : NULL) { |
+ kMessageAlignment))) { |
DCHECK_GE(main_buffer_size_, sizeof(Header)); |
DCHECK_EQ(main_buffer_size_ % kMessageAlignment, 0u); |
memcpy(main_buffer_.get(), message_view.main_buffer(), main_buffer_size_); |
- memcpy(secondary_buffer_.get(), message_view.secondary_buffer(), |
- secondary_buffer_size_); |
- |
DCHECK_EQ(main_buffer_size_, |
RoundUpMessageAlignment(sizeof(Header) + num_bytes())); |
} |
@@ -163,17 +128,6 @@ MessageInTransit::~MessageInTransit() { |
(*dispatchers_)[i]->Close(); |
} |
} |
- |
- if (platform_handles_) { |
- for (size_t i = 0; i < platform_handles_->size(); i++) |
- (*platform_handles_)[i].CloseIfNecessary(); |
- } |
- |
-#ifndef NDEBUG |
- secondary_buffer_size_ = 0; |
- dispatchers_.reset(); |
- platform_handles_.reset(); |
-#endif |
} |
// static |
@@ -210,206 +164,24 @@ void MessageInTransit::SetDispatchers( |
void MessageInTransit::SerializeAndCloseDispatchers(Channel* channel) { |
DCHECK(channel); |
- DCHECK(!secondary_buffer_); |
+ DCHECK(!transport_data_); |
- const size_t num_handles = dispatchers_ ? dispatchers_->size() : 0; |
- if (!num_handles) |
+ if (!dispatchers_ || !dispatchers_->size()) |
return; |
- // The offset to the start of the (Mojo) handle table. |
- // TODO(vtl): Add a header to the secondary buffer. |
- const size_t handle_table_start_offset = 0; |
- // The offset to the start of the serialized dispatcher data. |
- const size_t serialized_dispatcher_start_offset = |
- handle_table_start_offset + num_handles * sizeof(HandleTableEntry); |
- // The estimated size of the secondary buffer. We compute this estimate below. |
- // It must be at least as big as the (eventual) actual size. |
- size_t estimated_size = serialized_dispatcher_start_offset; |
- size_t num_platform_handles = 0; |
-#if DCHECK_IS_ON |
- std::vector<size_t> all_max_sizes(num_handles); |
- std::vector<size_t> all_max_platform_handles(num_handles); |
-#endif |
- for (size_t i = 0; i < num_handles; i++) { |
- if (Dispatcher* dispatcher = (*dispatchers_)[i].get()) { |
- size_t max_size = 0; |
- size_t max_platform_handles = 0; |
- Dispatcher::MessageInTransitAccess::StartSerialize( |
- dispatcher, channel, &max_size, &max_platform_handles); |
- |
- DCHECK_LE(max_size, kMaxSerializedDispatcherSize); |
- estimated_size += RoundUpMessageAlignment(max_size); |
- DCHECK_LE(estimated_size, kMaxSecondaryBufferSize); |
- |
- DCHECK_LE(max_platform_handles, |
- kMaxSerializedDispatcherPlatformHandles); |
- num_platform_handles += max_platform_handles; |
- DCHECK_LE(num_platform_handles, kMaxPlatformHandles); |
- |
-#if DCHECK_IS_ON |
- all_max_sizes[i] = max_size; |
- all_max_platform_handles[i] = max_platform_handles; |
-#endif |
- } |
- } |
- |
- secondary_buffer_.reset(static_cast<char*>( |
- base::AlignedAlloc(estimated_size, kMessageAlignment))); |
- // Entirely clear out the secondary buffer, since then we won't have to worry |
- // about clearing padding or unused space (e.g., if a dispatcher fails to |
- // serialize). |
- memset(secondary_buffer_.get(), 0, estimated_size); |
- |
- if (num_platform_handles > 0) { |
- DCHECK(!platform_handles_); |
- platform_handles_.reset(new std::vector<embedder::PlatformHandle>()); |
- } |
- |
- HandleTableEntry* handle_table = reinterpret_cast<HandleTableEntry*>( |
- secondary_buffer_.get() + handle_table_start_offset); |
- size_t current_offset = serialized_dispatcher_start_offset; |
- for (size_t i = 0; i < num_handles; i++) { |
- Dispatcher* dispatcher = (*dispatchers_)[i].get(); |
- if (!dispatcher) { |
- COMPILE_ASSERT(Dispatcher::kTypeUnknown == 0, |
- value_of_Dispatcher_kTypeUnknown_must_be_zero); |
- continue; |
- } |
- |
-#if DCHECK_IS_ON |
- size_t old_platform_handles_size = |
- platform_handles_ ? platform_handles_->size() : 0; |
-#endif |
- |
- void* destination = secondary_buffer_.get() + current_offset; |
- size_t actual_size = 0; |
- if (Dispatcher::MessageInTransitAccess::EndSerializeAndClose( |
- dispatcher, channel, destination, &actual_size, |
- platform_handles_.get())) { |
- handle_table[i].type = static_cast<int32_t>(dispatcher->GetType()); |
- handle_table[i].offset = static_cast<uint32_t>(current_offset); |
- handle_table[i].size = static_cast<uint32_t>(actual_size); |
- |
-#if DCHECK_IS_ON |
- DCHECK_LE(actual_size, all_max_sizes[i]); |
- DCHECK_LE(platform_handles_ ? (platform_handles_->size() - |
- old_platform_handles_size) : 0, |
- all_max_platform_handles[i]); |
-#endif |
- } else { |
- // Nothing to do on failure, since |secondary_buffer_| was cleared, and |
- // |kTypeUnknown| is zero. The handle was simply closed. |
- LOG(ERROR) << "Failed to serialize handle to remote message pipe"; |
- } |
- |
- current_offset += RoundUpMessageAlignment(actual_size); |
- DCHECK_LE(current_offset, estimated_size); |
- DCHECK_LE(platform_handles_ ? platform_handles_->size() : 0, |
- num_platform_handles); |
- } |
- |
- // There's no aligned realloc, so it's no good way to release unused space (if |
- // we overshot our estimated space requirements). |
- secondary_buffer_size_ = current_offset; |
- |
- // The dispatchers (which we "owned") were closed. We can dispose of them now. |
- dispatchers_.reset(); |
+ transport_data_.reset(new TransportData(dispatchers_.Pass(), channel)); |
// Update the sizes in the message header. |
UpdateTotalSize(); |
} |
-// Note: The message's secondary buffer should have been checked by calling |
-// |View::IsValid()| (on the |View|) first. |
-void MessageInTransit::DeserializeDispatchers(Channel* channel) { |
- DCHECK(!dispatchers_); |
- |
- // Already checked by |View::IsValid()|: |
- DCHECK_LE(num_handles(), kMaxMessageNumHandles); |
- |
- if (!num_handles()) |
- return; |
- |
- dispatchers_.reset( |
- new std::vector<scoped_refptr<Dispatcher> >(num_handles())); |
- |
- size_t handle_table_size = num_handles() * sizeof(HandleTableEntry); |
- // Already checked by |View::IsValid()|: |
- DCHECK_LE(handle_table_size, secondary_buffer_size_); |
- |
- const HandleTableEntry* handle_table = |
- reinterpret_cast<const HandleTableEntry*>(secondary_buffer_.get()); |
- for (size_t i = 0; i < num_handles(); i++) { |
- size_t offset = handle_table[i].offset; |
- size_t size = handle_table[i].size; |
- // Already checked by |View::IsValid()|: |
- DCHECK_EQ(offset % kMessageAlignment, 0u); |
- DCHECK_LE(offset, secondary_buffer_size_); |
- DCHECK_LE(offset + size, secondary_buffer_size_); |
- |
- const void* source = secondary_buffer_.get() + offset; |
- (*dispatchers_)[i] = Dispatcher::MessageInTransitAccess::Deserialize( |
- channel, handle_table[i].type, source, size); |
- } |
-} |
- |
-// Validates the secondary buffer. Returns null on success, or a human-readable |
-// error message on error. |
-// static |
-const char* MessageInTransit::ValidateSecondaryBuffer( |
- size_t num_handles, |
- const void* secondary_buffer, |
- size_t secondary_buffer_size) { |
- // Always make sure that the secondary buffer size is sane (even if we have no |
- // handles); if it's not, someone's messing with us. |
- if (secondary_buffer_size > kMaxSecondaryBufferSize) |
- return "Message secondary buffer too large"; |
- |
- // Fast-path for the common case (no handles => no secondary buffer). |
- if (num_handles == 0) { |
- // We shouldn't have a secondary buffer in this case. |
- if (secondary_buffer_size > 0) |
- return "Message has no handles attached, but secondary buffer present"; |
- return NULL; |
- } |
- |
- // Sanity-check |num_handles| (before multiplying it against anything). |
- if (num_handles > kMaxMessageNumHandles) |
- return "Message handle payload too large"; |
- |
- if (secondary_buffer_size < num_handles * sizeof(HandleTableEntry)) |
- return "Message secondary buffer too small"; |
- |
- DCHECK(secondary_buffer); |
- const HandleTableEntry* handle_table = |
- static_cast<const HandleTableEntry*>(secondary_buffer); |
- |
- static const char kInvalidSerializedDispatcher[] = |
- "Message contains invalid serialized dispatcher"; |
- for (size_t i = 0; i < num_handles; i++) { |
- size_t offset = handle_table[i].offset; |
- if (offset % kMessageAlignment != 0) |
- return kInvalidSerializedDispatcher; |
- |
- size_t size = handle_table[i].size; |
- if (size > kMaxSerializedDispatcherSize || size > secondary_buffer_size) |
- return kInvalidSerializedDispatcher; |
- |
- // Note: This is an overflow-safe check for |offset + size > |
- // secondary_buffer_size()| (we know that |size <= secondary_buffer_size()| |
- // from the previous check). |
- if (offset > secondary_buffer_size - size) |
- return kInvalidSerializedDispatcher; |
- } |
- |
- return NULL; |
-} |
- |
void MessageInTransit::UpdateTotalSize() { |
DCHECK_EQ(main_buffer_size_ % kMessageAlignment, 0u); |
- DCHECK_EQ(secondary_buffer_size_ % kMessageAlignment, 0u); |
- header()->total_size = |
- static_cast<uint32_t>(main_buffer_size_ + secondary_buffer_size_); |
+ header()->total_size = static_cast<uint32_t>(main_buffer_size_); |
+ if (transport_data_) { |
+ header()->total_size += |
+ static_cast<uint32_t>(transport_data_->buffer_size()); |
+ } |
} |
} // namespace system |