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 } // namespace
22
~MessageForTransit()23 MessageForTransit::~MessageForTransit() {}
24
25 // static
Create(std::unique_ptr<MessageForTransit> * message,uint32_t num_bytes,const Dispatcher::DispatcherInTransit * dispatchers,uint32_t num_dispatchers)26 MojoResult MessageForTransit::Create(
27 std::unique_ptr<MessageForTransit>* message,
28 uint32_t num_bytes,
29 const Dispatcher::DispatcherInTransit* dispatchers,
30 uint32_t num_dispatchers) {
31 // A structure for retaining information about every Dispatcher that will be
32 // sent with this message.
33 struct DispatcherInfo {
34 uint32_t num_bytes;
35 uint32_t num_ports;
36 uint32_t num_handles;
37 };
38
39 // This is only the base header size. It will grow as we accumulate the
40 // size of serialized state for each dispatcher.
41 size_t header_size = sizeof(MessageHeader) +
42 num_dispatchers * sizeof(DispatcherHeader);
43 size_t num_ports = 0;
44 size_t num_handles = 0;
45
46 std::vector<DispatcherInfo> dispatcher_info(num_dispatchers);
47 for (size_t i = 0; i < num_dispatchers; ++i) {
48 Dispatcher* d = dispatchers[i].dispatcher.get();
49 d->StartSerialize(&dispatcher_info[i].num_bytes,
50 &dispatcher_info[i].num_ports,
51 &dispatcher_info[i].num_handles);
52 header_size += dispatcher_info[i].num_bytes;
53 num_ports += dispatcher_info[i].num_ports;
54 num_handles += dispatcher_info[i].num_handles;
55 }
56
57 // We now have enough information to fully allocate the message storage.
58 std::unique_ptr<PortsMessage> msg = PortsMessage::NewUserMessage(
59 header_size + num_bytes, num_ports, num_handles);
60 if (!msg)
61 return MOJO_RESULT_RESOURCE_EXHAUSTED;
62
63 // Populate the message header with information about serialized dispatchers.
64 //
65 // The front of the message is always a MessageHeader followed by a
66 // DispatcherHeader for each dispatcher to be sent.
67 MessageHeader* header =
68 static_cast<MessageHeader*>(msg->mutable_payload_bytes());
69 DispatcherHeader* dispatcher_headers =
70 reinterpret_cast<DispatcherHeader*>(header + 1);
71
72 // Serialized dispatcher state immediately follows the series of
73 // DispatcherHeaders.
74 char* dispatcher_data =
75 reinterpret_cast<char*>(dispatcher_headers + num_dispatchers);
76
77 header->num_dispatchers = num_dispatchers;
78
79 // |header_size| is the total number of bytes preceding the message payload,
80 // including all dispatcher headers and serialized dispatcher state.
81 DCHECK_LE(header_size, std::numeric_limits<uint32_t>::max());
82 header->header_size = static_cast<uint32_t>(header_size);
83
84 if (num_dispatchers > 0) {
85 ScopedPlatformHandleVectorPtr handles(
86 new PlatformHandleVector(num_handles));
87 size_t port_index = 0;
88 size_t handle_index = 0;
89 bool fail = false;
90 for (size_t i = 0; i < num_dispatchers; ++i) {
91 Dispatcher* d = dispatchers[i].dispatcher.get();
92 DispatcherHeader* dh = &dispatcher_headers[i];
93 const DispatcherInfo& info = dispatcher_info[i];
94
95 // Fill in the header for this dispatcher.
96 dh->type = static_cast<int32_t>(d->GetType());
97 dh->num_bytes = info.num_bytes;
98 dh->num_ports = info.num_ports;
99 dh->num_platform_handles = info.num_handles;
100
101 // Fill in serialized state, ports, and platform handles. We'll cancel
102 // the send if the dispatcher implementation rejects for some reason.
103 if (!d->EndSerialize(static_cast<void*>(dispatcher_data),
104 msg->mutable_ports() + port_index,
105 handles->data() + handle_index)) {
106 fail = true;
107 break;
108 }
109
110 dispatcher_data += info.num_bytes;
111 port_index += info.num_ports;
112 handle_index += info.num_handles;
113 }
114
115 if (fail) {
116 // Release any platform handles we've accumulated. Their dispatchers
117 // retain ownership when message creation fails, so these are not actually
118 // leaking.
119 handles->clear();
120 return MOJO_RESULT_INVALID_ARGUMENT;
121 }
122
123 // Take ownership of all the handles and move them into message storage.
124 msg->SetHandles(std::move(handles));
125 }
126
127 message->reset(new MessageForTransit(std::move(msg)));
128 return MOJO_RESULT_OK;
129 }
130
MessageForTransit(std::unique_ptr<PortsMessage> message)131 MessageForTransit::MessageForTransit(std::unique_ptr<PortsMessage> message)
132 : message_(std::move(message)) {
133 }
134
135 } // namespace edk
136 } // namespace mojo
137