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. | |
Anand Mistry (off Chromium)
2016/04/21 12:19:42
I don't believe this logic is correct. Actually, t
Ken Rockot(use gerrit already)
2016/04/21 16:47:40
Yes, this was all broken and confusing because I w
| |
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::TakePortsMessage() { | |
180 return std::move(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 |