blob: 0f2ff5e6e69a4de8e721b5db6ec39ca7c7267d18 [file] [log] [blame]
James Robinson646469d2014-10-03 15:33:28 -07001// Copyright 2013 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_in_transit.h"
6
7#include <string.h>
8
9#include "base/compiler_specific.h"
10#include "base/logging.h"
Hajime Morrita1117c582014-11-11 16:40:19 -080011#include "mojo/edk/system/configuration.h"
James Robinson646469d2014-10-03 15:33:28 -070012#include "mojo/edk/system/transport_data.h"
13
14namespace mojo {
15namespace system {
16
17STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Type
18 MessageInTransit::kTypeMessagePipeEndpoint;
19STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Type
20 MessageInTransit::kTypeMessagePipe;
21STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Type
22 MessageInTransit::kTypeChannel;
23STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Type
24 MessageInTransit::kTypeRawChannel;
25STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Subtype
26 MessageInTransit::kSubtypeMessagePipeEndpointData;
27STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Subtype
James Robinsond4531882014-10-17 16:14:32 -070028 MessageInTransit::kSubtypeChannelAttachAndRunEndpoint;
James Robinson646469d2014-10-03 15:33:28 -070029STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Subtype
30 MessageInTransit::kSubtypeChannelRemoveMessagePipeEndpoint;
31STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Subtype
32 MessageInTransit::kSubtypeChannelRemoveMessagePipeEndpointAck;
33STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Subtype
34 MessageInTransit::kSubtypeRawChannelPosixExtraPlatformHandles;
James Robinson646469d2014-10-03 15:33:28 -070035STATIC_CONST_MEMBER_DEFINITION const size_t MessageInTransit::kMessageAlignment;
36
37struct MessageInTransit::PrivateStructForCompileAsserts {
38 // The size of |Header| must be a multiple of the alignment.
39 static_assert(sizeof(Header) % kMessageAlignment == 0,
40 "sizeof(MessageInTransit::Header) invalid");
James Robinson646469d2014-10-03 15:33:28 -070041};
42
43MessageInTransit::View::View(size_t message_size, const void* buffer)
44 : buffer_(buffer) {
45 size_t next_message_size = 0;
Viet-Trung Luu6dd61fa2014-11-12 13:40:01 -080046 DCHECK(MessageInTransit::GetNextMessageSize(buffer_, message_size,
47 &next_message_size));
James Robinson646469d2014-10-03 15:33:28 -070048 DCHECK_EQ(message_size, next_message_size);
49 // This should be equivalent.
50 DCHECK_EQ(message_size, total_size());
51}
52
53bool MessageInTransit::View::IsValid(size_t serialized_platform_handle_size,
54 const char** error_message) const {
Hajime Morrita1117c582014-11-11 16:40:19 -080055 size_t max_message_num_bytes = GetConfiguration().max_message_num_bytes;
56 // Avoid dangerous situations, but making sure that the size of the "header" +
57 // the size of the data fits into a 31-bit number.
58 DCHECK_LE(static_cast<uint64_t>(sizeof(Header)) + max_message_num_bytes,
59 0x7fffffffULL)
60 << "GetConfiguration().max_message_num_bytes too big";
61
62 // We assume (to avoid extra rounding code) that the maximum message (data)
63 // size is a multiple of the alignment.
64 DCHECK_EQ(max_message_num_bytes % kMessageAlignment, 0U)
65 << "GetConfiguration().max_message_num_bytes not a multiple of alignment";
66
James Robinson646469d2014-10-03 15:33:28 -070067 // Note: This also implies a check on the |main_buffer_size()|, which is just
68 // |RoundUpMessageAlignment(sizeof(Header) + num_bytes())|.
Hajime Morrita1117c582014-11-11 16:40:19 -080069 if (num_bytes() > max_message_num_bytes) {
James Robinson646469d2014-10-03 15:33:28 -070070 *error_message = "Message data payload too large";
71 return false;
72 }
73
74 if (transport_data_buffer_size() > 0) {
Viet-Trung Luu6dd61fa2014-11-12 13:40:01 -080075 const char* e = TransportData::ValidateBuffer(
76 serialized_platform_handle_size, transport_data_buffer(),
77 transport_data_buffer_size());
James Robinson646469d2014-10-03 15:33:28 -070078 if (e) {
79 *error_message = e;
80 return false;
81 }
82 }
83
84 return true;
85}
86
87MessageInTransit::MessageInTransit(Type type,
88 Subtype subtype,
89 uint32_t num_bytes,
90 const void* bytes)
91 : main_buffer_size_(RoundUpMessageAlignment(sizeof(Header) + num_bytes)),
92 main_buffer_(static_cast<char*>(
93 base::AlignedAlloc(main_buffer_size_, kMessageAlignment))) {
94 ConstructorHelper(type, subtype, num_bytes);
95 if (bytes) {
96 memcpy(MessageInTransit::bytes(), bytes, num_bytes);
Viet-Trung Luu6dd61fa2014-11-12 13:40:01 -080097 memset(static_cast<char*>(MessageInTransit::bytes()) + num_bytes, 0,
James Robinson646469d2014-10-03 15:33:28 -070098 main_buffer_size_ - sizeof(Header) - num_bytes);
99 } else {
100 memset(MessageInTransit::bytes(), 0, main_buffer_size_ - sizeof(Header));
101 }
102}
103
104MessageInTransit::MessageInTransit(Type type,
105 Subtype subtype,
106 uint32_t num_bytes,
107 UserPointer<const void> bytes)
108 : main_buffer_size_(RoundUpMessageAlignment(sizeof(Header) + num_bytes)),
109 main_buffer_(static_cast<char*>(
110 base::AlignedAlloc(main_buffer_size_, kMessageAlignment))) {
111 ConstructorHelper(type, subtype, num_bytes);
112 bytes.GetArray(MessageInTransit::bytes(), num_bytes);
113}
114
115MessageInTransit::MessageInTransit(const View& message_view)
116 : main_buffer_size_(message_view.main_buffer_size()),
117 main_buffer_(static_cast<char*>(
118 base::AlignedAlloc(main_buffer_size_, kMessageAlignment))) {
119 DCHECK_GE(main_buffer_size_, sizeof(Header));
120 DCHECK_EQ(main_buffer_size_ % kMessageAlignment, 0u);
121
122 memcpy(main_buffer_.get(), message_view.main_buffer(), main_buffer_size_);
123 DCHECK_EQ(main_buffer_size_,
124 RoundUpMessageAlignment(sizeof(Header) + num_bytes()));
125}
126
127MessageInTransit::~MessageInTransit() {
128 if (dispatchers_) {
129 for (size_t i = 0; i < dispatchers_->size(); i++) {
130 if (!(*dispatchers_)[i].get())
131 continue;
132
133 DCHECK((*dispatchers_)[i]->HasOneRef());
134 (*dispatchers_)[i]->Close();
135 }
136 }
137}
138
139// static
140bool MessageInTransit::GetNextMessageSize(const void* buffer,
141 size_t buffer_size,
142 size_t* next_message_size) {
143 DCHECK(next_message_size);
144 if (!buffer_size)
145 return false;
146 DCHECK(buffer);
147 DCHECK_EQ(
148 reinterpret_cast<uintptr_t>(buffer) % MessageInTransit::kMessageAlignment,
149 0u);
150
151 if (buffer_size < sizeof(Header))
152 return false;
153
154 const Header* header = static_cast<const Header*>(buffer);
155 *next_message_size = header->total_size;
156 DCHECK_EQ(*next_message_size % kMessageAlignment, 0u);
157 return true;
158}
159
160void MessageInTransit::SetDispatchers(
161 scoped_ptr<DispatcherVector> dispatchers) {
162 DCHECK(dispatchers);
163 DCHECK(!dispatchers_);
164 DCHECK(!transport_data_);
165
166 dispatchers_ = dispatchers.Pass();
167#ifndef NDEBUG
168 for (size_t i = 0; i < dispatchers_->size(); i++)
169 DCHECK(!(*dispatchers_)[i].get() || (*dispatchers_)[i]->HasOneRef());
170#endif
171}
172
173void MessageInTransit::SetTransportData(
174 scoped_ptr<TransportData> transport_data) {
175 DCHECK(transport_data);
176 DCHECK(!transport_data_);
177 DCHECK(!dispatchers_);
178
179 transport_data_ = transport_data.Pass();
180}
181
182void MessageInTransit::SerializeAndCloseDispatchers(Channel* channel) {
183 DCHECK(channel);
184 DCHECK(!transport_data_);
185
186 if (!dispatchers_ || !dispatchers_->size())
187 return;
188
189 transport_data_.reset(new TransportData(dispatchers_.Pass(), channel));
190
191 // Update the sizes in the message header.
192 UpdateTotalSize();
193}
194
195void MessageInTransit::ConstructorHelper(Type type,
196 Subtype subtype,
197 uint32_t num_bytes) {
Hajime Morrita1117c582014-11-11 16:40:19 -0800198 DCHECK_LE(num_bytes, GetConfiguration().max_message_num_bytes);
James Robinson646469d2014-10-03 15:33:28 -0700199
200 // |total_size| is updated below, from the other values.
201 header()->type = type;
202 header()->subtype = subtype;
James Robinsonbaf71d32014-10-08 13:00:20 -0700203 header()->source_id = ChannelEndpointId();
204 header()->destination_id = ChannelEndpointId();
James Robinson646469d2014-10-03 15:33:28 -0700205 header()->num_bytes = num_bytes;
206 header()->unused = 0;
207 // Note: If dispatchers are subsequently attached, then |total_size| will have
208 // to be adjusted.
209 UpdateTotalSize();
210}
211
212void MessageInTransit::UpdateTotalSize() {
213 DCHECK_EQ(main_buffer_size_ % kMessageAlignment, 0u);
214 header()->total_size = static_cast<uint32_t>(main_buffer_size_);
215 if (transport_data_) {
216 header()->total_size +=
217 static_cast<uint32_t>(transport_data_->buffer_size());
218 }
219}
220
221} // namespace system
222} // namespace mojo