OLD | NEW |
(Empty) | |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "mojo/edk/system/message_for_transit.h" |
| 6 |
| 7 #include <vector> |
| 8 |
| 9 #include "base/memory/ptr_util.h" |
| 10 #include "mojo/edk/embedder/platform_handle_vector.h" |
| 11 |
| 12 namespace mojo { |
| 13 namespace edk { |
| 14 |
| 15 namespace { |
| 16 |
| 17 static_assert(sizeof(MessageForTransit::MessageHeader) % 8 == 0, |
| 18 "Invalid MessageHeader size."); |
| 19 static_assert(sizeof(MessageForTransit::DispatcherHeader) % 8 == 0, |
| 20 "Invalid DispatcherHeader size."); |
| 21 |
| 22 const MessageForTransit::MessageHeader* GetHeader(const PortsMessage& message) { |
| 23 return static_cast<const MessageForTransit::MessageHeader*>( |
| 24 message.payload_bytes()); |
| 25 } |
| 26 |
| 27 } // namespace |
| 28 |
| 29 MessageForTransit::~MessageForTransit() {} |
| 30 |
| 31 // static |
| 32 MojoResult MessageForTransit::Create( |
| 33 std::unique_ptr<MessageForTransit>* message, |
| 34 uint32_t num_bytes, |
| 35 const Dispatcher::DispatcherInTransit* dispatchers, |
| 36 uint32_t num_dispatchers) { |
| 37 // A structure for retaining information about every Dispatcher that will be |
| 38 // sent with this message. |
| 39 struct DispatcherInfo { |
| 40 uint32_t num_bytes; |
| 41 uint32_t num_ports; |
| 42 uint32_t num_handles; |
| 43 }; |
| 44 |
| 45 // This is only the base header size. It will grow as we accumulate the |
| 46 // size of serialized state for each dispatcher. |
| 47 size_t header_size = sizeof(MessageHeader) + |
| 48 num_dispatchers * sizeof(DispatcherHeader); |
| 49 size_t num_ports = 0; |
| 50 size_t num_handles = 0; |
| 51 |
| 52 std::vector<DispatcherInfo> dispatcher_info(num_dispatchers); |
| 53 for (size_t i = 0; i < num_dispatchers; ++i) { |
| 54 Dispatcher* d = dispatchers[i].dispatcher.get(); |
| 55 d->StartSerialize(&dispatcher_info[i].num_bytes, |
| 56 &dispatcher_info[i].num_ports, |
| 57 &dispatcher_info[i].num_handles); |
| 58 header_size += dispatcher_info[i].num_bytes; |
| 59 num_ports += dispatcher_info[i].num_ports; |
| 60 num_handles += dispatcher_info[i].num_handles; |
| 61 } |
| 62 |
| 63 // We now have enough information to fully allocate the message storage. |
| 64 std::unique_ptr<PortsMessage> msg = PortsMessage::NewUserMessage( |
| 65 header_size + num_bytes, num_ports, num_handles); |
| 66 if (!msg) |
| 67 return MOJO_RESULT_RESOURCE_EXHAUSTED; |
| 68 |
| 69 // Populate the message header with information about serialized dispatchers. |
| 70 // |
| 71 // The front of the message is always a MessageHeader followed by a |
| 72 // DispatcherHeader for each dispatcher to be sent. |
| 73 MessageHeader* header = |
| 74 static_cast<MessageHeader*>(msg->mutable_payload_bytes()); |
| 75 DispatcherHeader* dispatcher_headers = |
| 76 reinterpret_cast<DispatcherHeader*>(header + 1); |
| 77 |
| 78 // Serialized dispatcher state immediately follows the series of |
| 79 // DispatcherHeaders. |
| 80 char* dispatcher_data = |
| 81 reinterpret_cast<char*>(dispatcher_headers + num_dispatchers); |
| 82 |
| 83 header->num_dispatchers = num_dispatchers; |
| 84 |
| 85 // |header_size| is the total number of bytes preceding the message payload, |
| 86 // including all dispatcher headers and serialized dispatcher state. |
| 87 DCHECK_LE(header_size, std::numeric_limits<uint32_t>::max()); |
| 88 header->header_size = static_cast<uint32_t>(header_size); |
| 89 |
| 90 if (num_dispatchers > 0) { |
| 91 ScopedPlatformHandleVectorPtr handles( |
| 92 new PlatformHandleVector(num_handles)); |
| 93 size_t port_index = 0; |
| 94 size_t handle_index = 0; |
| 95 bool fail = false; |
| 96 for (size_t i = 0; i < num_dispatchers; ++i) { |
| 97 Dispatcher* d = dispatchers[i].dispatcher.get(); |
| 98 DispatcherHeader* dh = &dispatcher_headers[i]; |
| 99 const DispatcherInfo& info = dispatcher_info[i]; |
| 100 |
| 101 // Fill in the header for this dispatcher. |
| 102 dh->type = static_cast<int32_t>(d->GetType()); |
| 103 dh->num_bytes = info.num_bytes; |
| 104 dh->num_ports = info.num_ports; |
| 105 dh->num_platform_handles = info.num_handles; |
| 106 |
| 107 // Fill in serialized state, ports, and platform handles. We'll cancel |
| 108 // the send if the dispatcher implementation rejects for some reason. |
| 109 if (!d->EndSerialize(static_cast<void*>(dispatcher_data), |
| 110 msg->mutable_ports() + port_index, |
| 111 handles->data() + handle_index)) { |
| 112 fail = true; |
| 113 break; |
| 114 } |
| 115 |
| 116 dispatcher_data += info.num_bytes; |
| 117 port_index += info.num_ports; |
| 118 handle_index += info.num_handles; |
| 119 } |
| 120 |
| 121 if (fail) { |
| 122 // Release any platform handles we've accumulated. Their dispatchers |
| 123 // retain ownership when message creation fails, so these are not actually |
| 124 // leaking. |
| 125 handles->clear(); |
| 126 return MOJO_RESULT_INVALID_ARGUMENT; |
| 127 } |
| 128 |
| 129 // Take ownership of all the handles and move them into message storage. |
| 130 msg->SetHandles(std::move(handles)); |
| 131 } |
| 132 |
| 133 message->reset(new MessageForTransit(std::move(msg))); |
| 134 return MOJO_RESULT_OK; |
| 135 } |
| 136 |
| 137 // static |
| 138 std::unique_ptr<MessageForTransit> MessageForTransit::WrapPortsMessage( |
| 139 std::unique_ptr<PortsMessage> message) { |
| 140 return base::WrapUnique(new MessageForTransit(std::move(message))); |
| 141 } |
| 142 |
| 143 const void* MessageForTransit::bytes() const { |
| 144 DCHECK(message_); |
| 145 return static_cast<const void*>( |
| 146 static_cast<const char*>(message_->payload_bytes()) + |
| 147 GetHeader(*message_)->header_size); |
| 148 } |
| 149 |
| 150 void* MessageForTransit::mutable_bytes() { |
| 151 DCHECK(message_); |
| 152 return static_cast<void*>( |
| 153 static_cast<char*>(message_->mutable_payload_bytes()) + |
| 154 GetHeader(*message_)->header_size); |
| 155 } |
| 156 |
| 157 size_t MessageForTransit::num_bytes() const { |
| 158 DCHECK(message_); |
| 159 size_t header_size = GetHeader(*message_)->header_size; |
| 160 DCHECK_GE(message_->num_payload_bytes(), header_size); |
| 161 return message_->num_payload_bytes() - header_size; |
| 162 } |
| 163 |
| 164 size_t MessageForTransit::num_handles() const { |
| 165 DCHECK(message_); |
| 166 return GetHeader(*message_)->num_dispatchers; |
| 167 } |
| 168 |
| 169 std::unique_ptr<PortsMessage> MessageForTransit::TakePortsMessage() { |
| 170 return std::move(message_); |
| 171 } |
| 172 |
| 173 MessageForTransit::MessageForTransit(std::unique_ptr<PortsMessage> message) |
| 174 : message_(std::move(message)) { |
| 175 } |
| 176 |
| 177 } // namespace edk |
| 178 } // namespace mojo |
OLD | NEW |