OLD | NEW |
| (Empty) |
1 // Copyright 2014 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/shared_buffer_dispatcher.h" | |
6 | |
7 #include <limits> | |
8 | |
9 #include "base/logging.h" | |
10 #include "base/memory/scoped_ptr.h" | |
11 #include "mojo/edk/embedder/platform_support.h" | |
12 #include "mojo/edk/system/channel.h" | |
13 #include "mojo/edk/system/configuration.h" | |
14 #include "mojo/edk/system/memory.h" | |
15 #include "mojo/edk/system/options_validation.h" | |
16 #include "mojo/public/c/system/macros.h" | |
17 | |
18 namespace mojo { | |
19 namespace system { | |
20 | |
21 namespace { | |
22 | |
23 struct SerializedSharedBufferDispatcher { | |
24 size_t num_bytes; | |
25 size_t platform_handle_index; | |
26 }; | |
27 | |
28 } // namespace | |
29 | |
30 // static | |
31 const MojoCreateSharedBufferOptions | |
32 SharedBufferDispatcher::kDefaultCreateOptions = { | |
33 static_cast<uint32_t>(sizeof(MojoCreateSharedBufferOptions)), | |
34 MOJO_CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE}; | |
35 | |
36 // static | |
37 MojoResult SharedBufferDispatcher::ValidateCreateOptions( | |
38 UserPointer<const MojoCreateSharedBufferOptions> in_options, | |
39 MojoCreateSharedBufferOptions* out_options) { | |
40 const MojoCreateSharedBufferOptionsFlags kKnownFlags = | |
41 MOJO_CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE; | |
42 | |
43 *out_options = kDefaultCreateOptions; | |
44 if (in_options.IsNull()) | |
45 return MOJO_RESULT_OK; | |
46 | |
47 UserOptionsReader<MojoCreateSharedBufferOptions> reader(in_options); | |
48 if (!reader.is_valid()) | |
49 return MOJO_RESULT_INVALID_ARGUMENT; | |
50 | |
51 if (!OPTIONS_STRUCT_HAS_MEMBER(MojoCreateSharedBufferOptions, flags, reader)) | |
52 return MOJO_RESULT_OK; | |
53 if ((reader.options().flags & ~kKnownFlags)) | |
54 return MOJO_RESULT_UNIMPLEMENTED; | |
55 out_options->flags = reader.options().flags; | |
56 | |
57 // Checks for fields beyond |flags|: | |
58 | |
59 // (Nothing here yet.) | |
60 | |
61 return MOJO_RESULT_OK; | |
62 } | |
63 | |
64 // static | |
65 MojoResult SharedBufferDispatcher::Create( | |
66 embedder::PlatformSupport* platform_support, | |
67 const MojoCreateSharedBufferOptions& /*validated_options*/, | |
68 uint64_t num_bytes, | |
69 scoped_refptr<SharedBufferDispatcher>* result) { | |
70 if (!num_bytes) | |
71 return MOJO_RESULT_INVALID_ARGUMENT; | |
72 if (num_bytes > GetConfiguration().max_shared_memory_num_bytes) | |
73 return MOJO_RESULT_RESOURCE_EXHAUSTED; | |
74 | |
75 scoped_refptr<embedder::PlatformSharedBuffer> shared_buffer( | |
76 platform_support->CreateSharedBuffer(static_cast<size_t>(num_bytes))); | |
77 if (!shared_buffer) | |
78 return MOJO_RESULT_RESOURCE_EXHAUSTED; | |
79 | |
80 *result = new SharedBufferDispatcher(shared_buffer); | |
81 return MOJO_RESULT_OK; | |
82 } | |
83 | |
84 Dispatcher::Type SharedBufferDispatcher::GetType() const { | |
85 return kTypeSharedBuffer; | |
86 } | |
87 | |
88 // static | |
89 scoped_refptr<SharedBufferDispatcher> SharedBufferDispatcher::Deserialize( | |
90 Channel* channel, | |
91 const void* source, | |
92 size_t size, | |
93 embedder::PlatformHandleVector* platform_handles) { | |
94 DCHECK(channel); | |
95 | |
96 if (size != sizeof(SerializedSharedBufferDispatcher)) { | |
97 LOG(ERROR) << "Invalid serialized shared buffer dispatcher (bad size)"; | |
98 return nullptr; | |
99 } | |
100 | |
101 const SerializedSharedBufferDispatcher* serialization = | |
102 static_cast<const SerializedSharedBufferDispatcher*>(source); | |
103 size_t num_bytes = serialization->num_bytes; | |
104 size_t platform_handle_index = serialization->platform_handle_index; | |
105 | |
106 if (!num_bytes) { | |
107 LOG(ERROR) | |
108 << "Invalid serialized shared buffer dispatcher (invalid num_bytes)"; | |
109 return nullptr; | |
110 } | |
111 | |
112 if (!platform_handles || platform_handle_index >= platform_handles->size()) { | |
113 LOG(ERROR) | |
114 << "Invalid serialized shared buffer dispatcher (missing handles)"; | |
115 return nullptr; | |
116 } | |
117 | |
118 // Starts off invalid, which is what we want. | |
119 embedder::PlatformHandle platform_handle; | |
120 // We take ownership of the handle, so we have to invalidate the one in | |
121 // |platform_handles|. | |
122 std::swap(platform_handle, (*platform_handles)[platform_handle_index]); | |
123 | |
124 // Wrapping |platform_handle| in a |ScopedPlatformHandle| means that it'll be | |
125 // closed even if creation fails. | |
126 scoped_refptr<embedder::PlatformSharedBuffer> shared_buffer( | |
127 channel->platform_support()->CreateSharedBufferFromHandle( | |
128 num_bytes, embedder::ScopedPlatformHandle(platform_handle))); | |
129 if (!shared_buffer) { | |
130 LOG(ERROR) | |
131 << "Invalid serialized shared buffer dispatcher (invalid num_bytes?)"; | |
132 return nullptr; | |
133 } | |
134 | |
135 return scoped_refptr<SharedBufferDispatcher>( | |
136 new SharedBufferDispatcher(shared_buffer)); | |
137 } | |
138 | |
139 SharedBufferDispatcher::SharedBufferDispatcher( | |
140 scoped_refptr<embedder::PlatformSharedBuffer> shared_buffer) | |
141 : shared_buffer_(shared_buffer) { | |
142 DCHECK(shared_buffer_); | |
143 } | |
144 | |
145 SharedBufferDispatcher::~SharedBufferDispatcher() { | |
146 } | |
147 | |
148 // static | |
149 MojoResult SharedBufferDispatcher::ValidateDuplicateOptions( | |
150 UserPointer<const MojoDuplicateBufferHandleOptions> in_options, | |
151 MojoDuplicateBufferHandleOptions* out_options) { | |
152 const MojoDuplicateBufferHandleOptionsFlags kKnownFlags = | |
153 MOJO_DUPLICATE_BUFFER_HANDLE_OPTIONS_FLAG_NONE; | |
154 static const MojoDuplicateBufferHandleOptions kDefaultOptions = { | |
155 static_cast<uint32_t>(sizeof(MojoDuplicateBufferHandleOptions)), | |
156 MOJO_DUPLICATE_BUFFER_HANDLE_OPTIONS_FLAG_NONE}; | |
157 | |
158 *out_options = kDefaultOptions; | |
159 if (in_options.IsNull()) | |
160 return MOJO_RESULT_OK; | |
161 | |
162 UserOptionsReader<MojoDuplicateBufferHandleOptions> reader(in_options); | |
163 if (!reader.is_valid()) | |
164 return MOJO_RESULT_INVALID_ARGUMENT; | |
165 | |
166 if (!OPTIONS_STRUCT_HAS_MEMBER(MojoDuplicateBufferHandleOptions, flags, | |
167 reader)) | |
168 return MOJO_RESULT_OK; | |
169 if ((reader.options().flags & ~kKnownFlags)) | |
170 return MOJO_RESULT_UNIMPLEMENTED; | |
171 out_options->flags = reader.options().flags; | |
172 | |
173 // Checks for fields beyond |flags|: | |
174 | |
175 // (Nothing here yet.) | |
176 | |
177 return MOJO_RESULT_OK; | |
178 } | |
179 | |
180 void SharedBufferDispatcher::CloseImplNoLock() { | |
181 lock().AssertAcquired(); | |
182 DCHECK(shared_buffer_); | |
183 shared_buffer_ = nullptr; | |
184 } | |
185 | |
186 scoped_refptr<Dispatcher> | |
187 SharedBufferDispatcher::CreateEquivalentDispatcherAndCloseImplNoLock() { | |
188 lock().AssertAcquired(); | |
189 DCHECK(shared_buffer_); | |
190 scoped_refptr<embedder::PlatformSharedBuffer> shared_buffer; | |
191 shared_buffer.swap(shared_buffer_); | |
192 return scoped_refptr<Dispatcher>(new SharedBufferDispatcher(shared_buffer)); | |
193 } | |
194 | |
195 MojoResult SharedBufferDispatcher::DuplicateBufferHandleImplNoLock( | |
196 UserPointer<const MojoDuplicateBufferHandleOptions> options, | |
197 scoped_refptr<Dispatcher>* new_dispatcher) { | |
198 lock().AssertAcquired(); | |
199 | |
200 MojoDuplicateBufferHandleOptions validated_options; | |
201 MojoResult result = ValidateDuplicateOptions(options, &validated_options); | |
202 if (result != MOJO_RESULT_OK) | |
203 return result; | |
204 | |
205 *new_dispatcher = new SharedBufferDispatcher(shared_buffer_); | |
206 return MOJO_RESULT_OK; | |
207 } | |
208 | |
209 MojoResult SharedBufferDispatcher::MapBufferImplNoLock( | |
210 uint64_t offset, | |
211 uint64_t num_bytes, | |
212 MojoMapBufferFlags flags, | |
213 scoped_ptr<embedder::PlatformSharedBufferMapping>* mapping) { | |
214 lock().AssertAcquired(); | |
215 DCHECK(shared_buffer_); | |
216 | |
217 if (offset > static_cast<uint64_t>(std::numeric_limits<size_t>::max())) | |
218 return MOJO_RESULT_INVALID_ARGUMENT; | |
219 if (num_bytes > static_cast<uint64_t>(std::numeric_limits<size_t>::max())) | |
220 return MOJO_RESULT_INVALID_ARGUMENT; | |
221 | |
222 if (!shared_buffer_->IsValidMap(static_cast<size_t>(offset), | |
223 static_cast<size_t>(num_bytes))) | |
224 return MOJO_RESULT_INVALID_ARGUMENT; | |
225 | |
226 DCHECK(mapping); | |
227 *mapping = shared_buffer_->MapNoCheck(static_cast<size_t>(offset), | |
228 static_cast<size_t>(num_bytes)); | |
229 if (!*mapping) | |
230 return MOJO_RESULT_RESOURCE_EXHAUSTED; | |
231 | |
232 return MOJO_RESULT_OK; | |
233 } | |
234 | |
235 void SharedBufferDispatcher::StartSerializeImplNoLock( | |
236 Channel* /*channel*/, | |
237 size_t* max_size, | |
238 size_t* max_platform_handles) { | |
239 DCHECK(HasOneRef()); // Only one ref => no need to take the lock. | |
240 *max_size = sizeof(SerializedSharedBufferDispatcher); | |
241 *max_platform_handles = 1; | |
242 } | |
243 | |
244 bool SharedBufferDispatcher::EndSerializeAndCloseImplNoLock( | |
245 Channel* /*channel*/, | |
246 void* destination, | |
247 size_t* actual_size, | |
248 embedder::PlatformHandleVector* platform_handles) { | |
249 DCHECK(HasOneRef()); // Only one ref => no need to take the lock. | |
250 DCHECK(shared_buffer_); | |
251 | |
252 SerializedSharedBufferDispatcher* serialization = | |
253 static_cast<SerializedSharedBufferDispatcher*>(destination); | |
254 // If there's only one reference to |shared_buffer_|, then it's ours (and no | |
255 // one else can make any more references to it), so we can just take its | |
256 // handle. | |
257 embedder::ScopedPlatformHandle platform_handle( | |
258 shared_buffer_->HasOneRef() ? shared_buffer_->PassPlatformHandle() | |
259 : shared_buffer_->DuplicatePlatformHandle()); | |
260 if (!platform_handle.is_valid()) { | |
261 shared_buffer_ = nullptr; | |
262 return false; | |
263 } | |
264 | |
265 serialization->num_bytes = shared_buffer_->GetNumBytes(); | |
266 serialization->platform_handle_index = platform_handles->size(); | |
267 platform_handles->push_back(platform_handle.release()); | |
268 *actual_size = sizeof(SerializedSharedBufferDispatcher); | |
269 | |
270 shared_buffer_ = nullptr; | |
271 | |
272 return true; | |
273 } | |
274 | |
275 } // namespace system | |
276 } // namespace mojo | |
OLD | NEW |