diff options
Diffstat (limited to 'chromium/mojo/system/message_in_transit.cc')
-rw-r--r-- | chromium/mojo/system/message_in_transit.cc | 206 |
1 files changed, 206 insertions, 0 deletions
diff --git a/chromium/mojo/system/message_in_transit.cc b/chromium/mojo/system/message_in_transit.cc new file mode 100644 index 00000000000..944e12b19ae --- /dev/null +++ b/chromium/mojo/system/message_in_transit.cc @@ -0,0 +1,206 @@ +// Copyright 2013 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 "mojo/system/message_in_transit.h" + +#include <string.h> + +#include "base/compiler_specific.h" +#include "base/logging.h" +#include "mojo/system/constants.h" +#include "mojo/system/transport_data.h" + +namespace mojo { +namespace system { + +STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Type + MessageInTransit::kTypeMessagePipeEndpoint; +STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Type + MessageInTransit::kTypeMessagePipe; +STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Type + MessageInTransit::kTypeChannel; +STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Type + MessageInTransit::kTypeRawChannel; +STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Subtype + MessageInTransit::kSubtypeMessagePipeEndpointData; +STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Subtype + MessageInTransit::kSubtypeChannelRunMessagePipeEndpoint; +STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Subtype + MessageInTransit::kSubtypeChannelRemoveMessagePipeEndpoint; +STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Subtype + MessageInTransit::kSubtypeChannelRemoveMessagePipeEndpointAck; +STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Subtype + MessageInTransit::kSubtypeRawChannelPosixExtraPlatformHandles; +STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::EndpointId + MessageInTransit::kInvalidEndpointId; +STATIC_CONST_MEMBER_DEFINITION const size_t MessageInTransit::kMessageAlignment; + +struct MessageInTransit::PrivateStructForCompileAsserts { + // The size of |Header| must be a multiple of the alignment. + COMPILE_ASSERT(sizeof(Header) % kMessageAlignment == 0, + sizeof_MessageInTransit_Header_invalid); + // Avoid dangerous situations, but making sure that the size of the "header" + + // the size of the data fits into a 31-bit number. + COMPILE_ASSERT(static_cast<uint64_t>(sizeof(Header)) + kMaxMessageNumBytes <= + 0x7fffffffULL, + kMaxMessageNumBytes_too_big); + + // We assume (to avoid extra rounding code) that the maximum message (data) + // size is a multiple of the alignment. + COMPILE_ASSERT(kMaxMessageNumBytes % kMessageAlignment == 0, + kMessageAlignment_not_a_multiple_of_alignment); +}; + +MessageInTransit::View::View(size_t message_size, const void* buffer) + : buffer_(buffer) { + size_t next_message_size = 0; + DCHECK(MessageInTransit::GetNextMessageSize(buffer_, message_size, + &next_message_size)); + DCHECK_EQ(message_size, next_message_size); + // This should be equivalent. + DCHECK_EQ(message_size, total_size()); +} + +bool MessageInTransit::View::IsValid(size_t serialized_platform_handle_size, + const char** error_message) const { + // Note: This also implies a check on the |main_buffer_size()|, which is just + // |RoundUpMessageAlignment(sizeof(Header) + num_bytes())|. + if (num_bytes() > kMaxMessageNumBytes) { + *error_message = "Message data payload too large"; + return false; + } + + if (transport_data_buffer_size() > 0) { + const char* e = + TransportData::ValidateBuffer(serialized_platform_handle_size, + transport_data_buffer(), + transport_data_buffer_size()); + if (e) { + *error_message = e; + return false; + } + } + + return true; +} + +MessageInTransit::MessageInTransit(Type type, + Subtype subtype, + uint32_t num_bytes, + const void* bytes) + : main_buffer_size_(RoundUpMessageAlignment(sizeof(Header) + num_bytes)), + main_buffer_(static_cast<char*>(base::AlignedAlloc(main_buffer_size_, + kMessageAlignment))) { + DCHECK_LE(num_bytes, kMaxMessageNumBytes); + + // |total_size| is updated below, from the other values. + header()->type = type; + header()->subtype = subtype; + header()->source_id = kInvalidEndpointId; + header()->destination_id = kInvalidEndpointId; + header()->num_bytes = num_bytes; + header()->unused = 0; + // Note: If dispatchers are subsequently attached, then |total_size| will have + // to be adjusted. + UpdateTotalSize(); + + if (bytes) { + memcpy(MessageInTransit::bytes(), bytes, num_bytes); + memset(static_cast<char*>(MessageInTransit::bytes()) + num_bytes, 0, + main_buffer_size_ - sizeof(Header) - num_bytes); + } else { + memset(MessageInTransit::bytes(), 0, main_buffer_size_ - sizeof(Header)); + } +} + +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))) { + 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_); + DCHECK_EQ(main_buffer_size_, + RoundUpMessageAlignment(sizeof(Header) + num_bytes())); +} + +MessageInTransit::~MessageInTransit() { + if (dispatchers_) { + for (size_t i = 0; i < dispatchers_->size(); i++) { + if (!(*dispatchers_)[i]) + continue; + + DCHECK((*dispatchers_)[i]->HasOneRef()); + (*dispatchers_)[i]->Close(); + } + } +} + +// static +bool MessageInTransit::GetNextMessageSize(const void* buffer, + size_t buffer_size, + size_t* next_message_size) { + DCHECK(next_message_size); + if (!buffer_size) + return false; + DCHECK(buffer); + DCHECK_EQ(reinterpret_cast<uintptr_t>(buffer) % + MessageInTransit::kMessageAlignment, 0u); + + if (buffer_size < sizeof(Header)) + return false; + + const Header* header = static_cast<const Header*>(buffer); + *next_message_size = header->total_size; + DCHECK_EQ(*next_message_size % kMessageAlignment, 0u); + return true; +} + +void MessageInTransit::SetDispatchers( + scoped_ptr<DispatcherVector> dispatchers) { + DCHECK(dispatchers); + DCHECK(!dispatchers_); + DCHECK(!transport_data_); + + dispatchers_ = dispatchers.Pass(); +#ifndef NDEBUG + for (size_t i = 0; i < dispatchers_->size(); i++) + DCHECK(!(*dispatchers_)[i] || (*dispatchers_)[i]->HasOneRef()); +#endif +} + +void MessageInTransit::SetTransportData( + scoped_ptr<TransportData> transport_data) { + DCHECK(transport_data); + DCHECK(!transport_data_); + DCHECK(!dispatchers_); + + transport_data_ = transport_data.Pass(); +} + +void MessageInTransit::SerializeAndCloseDispatchers(Channel* channel) { + DCHECK(channel); + DCHECK(!transport_data_); + + if (!dispatchers_ || !dispatchers_->size()) + return; + + transport_data_.reset(new TransportData(dispatchers_.Pass(), channel)); + + // Update the sizes in the message header. + UpdateTotalSize(); +} + +void MessageInTransit::UpdateTotalSize() { + DCHECK_EQ(main_buffer_size_ % kMessageAlignment, 0u); + 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 +} // namespace mojo |