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