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