• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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