summaryrefslogtreecommitdiffstats
path: root/chromium/mojo/system/message_in_transit.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/mojo/system/message_in_transit.cc')
-rw-r--r--chromium/mojo/system/message_in_transit.cc206
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