OLD | NEW |
| (Empty) |
1 // 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 <stddef.h> | |
8 #include <stdint.h> | |
9 #include <string.h> | |
10 #include <ostream> | |
11 #include <utility> | |
12 | |
13 #include "base/logging.h" | |
14 #include "mojo/edk/system/configuration.h" | |
15 #include "mojo/edk/system/transport_data.h" | |
16 | |
17 namespace mojo { | |
18 namespace edk { | |
19 | |
20 MOJO_STATIC_CONST_MEMBER_DEFINITION const size_t | |
21 MessageInTransit::kMessageAlignment; | |
22 | |
23 struct MessageInTransit::PrivateStructForCompileAsserts { | |
24 // The size of |Header| must be a multiple of the alignment. | |
25 static_assert(sizeof(Header) % kMessageAlignment == 0, | |
26 "sizeof(MessageInTransit::Header) invalid"); | |
27 }; | |
28 | |
29 MessageInTransit::View::View(size_t message_size, const void* buffer) | |
30 : buffer_(buffer) { | |
31 size_t next_message_size = 0; | |
32 DCHECK(MessageInTransit::GetNextMessageSize(buffer_, message_size, | |
33 &next_message_size)); | |
34 DCHECK_EQ(message_size, next_message_size); | |
35 // This should be equivalent. | |
36 DCHECK_EQ(message_size, total_size()); | |
37 } | |
38 | |
39 bool MessageInTransit::View::IsValid(size_t serialized_platform_handle_size, | |
40 const char** error_message) const { | |
41 size_t max_message_num_bytes = GetConfiguration().max_message_num_bytes; | |
42 // Avoid dangerous situations, but making sure that the size of the "header" + | |
43 // the size of the data fits into a 31-bit number. | |
44 DCHECK_LE(static_cast<uint64_t>(sizeof(Header)) + max_message_num_bytes, | |
45 0x7fffffffULL) | |
46 << "GetConfiguration().max_message_num_bytes too big"; | |
47 | |
48 // We assume (to avoid extra rounding code) that the maximum message (data) | |
49 // size is a multiple of the alignment. | |
50 DCHECK_EQ(max_message_num_bytes % kMessageAlignment, 0U) | |
51 << "GetConfiguration().max_message_num_bytes not a multiple of alignment"; | |
52 | |
53 // Note: This also implies a check on the |main_buffer_size()|, which is just | |
54 // |RoundUpMessageAlignment(sizeof(Header) + num_bytes())|. | |
55 if (num_bytes() > max_message_num_bytes) { | |
56 *error_message = "Message data payload too large"; | |
57 return false; | |
58 } | |
59 | |
60 if (transport_data_buffer_size() > 0) { | |
61 const char* e = TransportData::ValidateBuffer( | |
62 serialized_platform_handle_size, transport_data_buffer(), | |
63 transport_data_buffer_size()); | |
64 if (e) { | |
65 *error_message = e; | |
66 return false; | |
67 } | |
68 } | |
69 | |
70 return true; | |
71 } | |
72 | |
73 MessageInTransit::MessageInTransit(Type type, | |
74 uint32_t num_bytes, | |
75 const void* bytes) | |
76 : main_buffer_size_(RoundUpMessageAlignment(sizeof(Header) + num_bytes)), | |
77 main_buffer_(static_cast<char*>( | |
78 base::AlignedAlloc(main_buffer_size_, kMessageAlignment))) { | |
79 ConstructorHelper(type, num_bytes); | |
80 if (bytes) { | |
81 memcpy(MessageInTransit::bytes(), bytes, num_bytes); | |
82 memset(static_cast<char*>(MessageInTransit::bytes()) + num_bytes, 0, | |
83 main_buffer_size_ - sizeof(Header) - num_bytes); | |
84 } else { | |
85 memset(MessageInTransit::bytes(), 0, main_buffer_size_ - sizeof(Header)); | |
86 } | |
87 } | |
88 | |
89 MessageInTransit::MessageInTransit(const View& message_view) | |
90 : main_buffer_size_(message_view.main_buffer_size()), | |
91 main_buffer_(static_cast<char*>( | |
92 base::AlignedAlloc(main_buffer_size_, kMessageAlignment))) { | |
93 DCHECK_GE(main_buffer_size_, sizeof(Header)); | |
94 DCHECK_EQ(main_buffer_size_ % kMessageAlignment, 0u); | |
95 | |
96 memcpy(main_buffer_.get(), message_view.main_buffer(), main_buffer_size_); | |
97 DCHECK_EQ(main_buffer_size_, | |
98 RoundUpMessageAlignment(sizeof(Header) + num_bytes())); | |
99 } | |
100 | |
101 MessageInTransit::~MessageInTransit() { | |
102 if (dispatchers_) { | |
103 for (size_t i = 0; i < dispatchers_->size(); i++) { | |
104 if (!(*dispatchers_)[i]) | |
105 continue; | |
106 (*dispatchers_)[i]->Close(); | |
107 } | |
108 } | |
109 } | |
110 | |
111 // static | |
112 bool MessageInTransit::GetNextMessageSize(const void* buffer, | |
113 size_t buffer_size, | |
114 size_t* next_message_size) { | |
115 DCHECK(next_message_size); | |
116 if (!buffer_size) | |
117 return false; | |
118 DCHECK(buffer); | |
119 DCHECK_EQ( | |
120 reinterpret_cast<uintptr_t>(buffer) % MessageInTransit::kMessageAlignment, | |
121 0u); | |
122 | |
123 if (buffer_size < sizeof(Header)) | |
124 return false; | |
125 | |
126 const Header* header = static_cast<const Header*>(buffer); | |
127 *next_message_size = header->total_size; | |
128 DCHECK_EQ(*next_message_size % kMessageAlignment, 0u); | |
129 return true; | |
130 } | |
131 | |
132 void MessageInTransit::SetDispatchers( | |
133 scoped_ptr<DispatcherVector> dispatchers) { | |
134 DCHECK(dispatchers); | |
135 DCHECK(!dispatchers_); | |
136 DCHECK(!transport_data_); | |
137 | |
138 dispatchers_ = std::move(dispatchers); | |
139 } | |
140 | |
141 void MessageInTransit::SetTransportData( | |
142 scoped_ptr<TransportData> transport_data) { | |
143 DCHECK(transport_data); | |
144 DCHECK(!transport_data_); | |
145 DCHECK(!dispatchers_); | |
146 | |
147 transport_data_ = std::move(transport_data); | |
148 UpdateTotalSize(); | |
149 } | |
150 | |
151 void MessageInTransit::SerializeAndCloseDispatchers() { | |
152 DCHECK(!transport_data_); | |
153 | |
154 if (!dispatchers_ || !dispatchers_->size()) | |
155 return; | |
156 | |
157 transport_data_.reset(new TransportData(std::move(dispatchers_))); | |
158 | |
159 // Update the sizes in the message header. | |
160 UpdateTotalSize(); | |
161 } | |
162 | |
163 void MessageInTransit::ConstructorHelper(Type type, | |
164 uint32_t num_bytes) { | |
165 DCHECK_LE(num_bytes, GetConfiguration().max_message_num_bytes); | |
166 | |
167 // |total_size| is updated below, from the other values. | |
168 header()->type = type; | |
169 header()->unusedforalignment = 0; | |
170 header()->num_bytes = num_bytes; | |
171 header()->unused = 0; | |
172 header()->route_id = 0; | |
173 // Note: If dispatchers are subsequently attached, then |total_size| will have | |
174 // to be adjusted. | |
175 UpdateTotalSize(); | |
176 } | |
177 | |
178 void MessageInTransit::UpdateTotalSize() { | |
179 DCHECK_EQ(main_buffer_size_ % kMessageAlignment, 0u); | |
180 header()->total_size = static_cast<uint32_t>(main_buffer_size_); | |
181 if (transport_data_) { | |
182 header()->total_size += | |
183 static_cast<uint32_t>(transport_data_->buffer_size()); | |
184 } | |
185 } | |
186 | |
187 } // namespace edk | |
188 } // namespace mojo | |
OLD | NEW |