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