diff options
Diffstat (limited to 'mojo/system/shared_buffer_dispatcher.cc')
-rw-r--r-- | mojo/system/shared_buffer_dispatcher.cc | 276 |
1 files changed, 276 insertions, 0 deletions
diff --git a/mojo/system/shared_buffer_dispatcher.cc b/mojo/system/shared_buffer_dispatcher.cc new file mode 100644 index 0000000..6229f08 --- /dev/null +++ b/mojo/system/shared_buffer_dispatcher.cc @@ -0,0 +1,276 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mojo/system/shared_buffer_dispatcher.h" + +#include <limits> + +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" +#include "mojo/embedder/platform_support.h" +#include "mojo/public/c/system/macros.h" +#include "mojo/system/channel.h" +#include "mojo/system/constants.h" +#include "mojo/system/memory.h" +#include "mojo/system/options_validation.h" + +namespace mojo { +namespace system { + +namespace { + +struct SerializedSharedBufferDispatcher { + size_t num_bytes; + size_t platform_handle_index; +}; + +} // namespace + +// static +const MojoCreateSharedBufferOptions + SharedBufferDispatcher::kDefaultCreateOptions = { + static_cast<uint32_t>(sizeof(MojoCreateSharedBufferOptions)), + MOJO_CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE}; + +// static +MojoResult SharedBufferDispatcher::ValidateCreateOptions( + UserPointer<const MojoCreateSharedBufferOptions> in_options, + MojoCreateSharedBufferOptions* out_options) { + const MojoCreateSharedBufferOptionsFlags kKnownFlags = + MOJO_CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE; + + *out_options = kDefaultCreateOptions; + if (in_options.IsNull()) + return MOJO_RESULT_OK; + + UserOptionsReader<MojoCreateSharedBufferOptions> reader(in_options); + if (!reader.is_valid()) + return MOJO_RESULT_INVALID_ARGUMENT; + + if (!OPTIONS_STRUCT_HAS_MEMBER(MojoCreateSharedBufferOptions, flags, reader)) + return MOJO_RESULT_OK; + if ((reader.options().flags & ~kKnownFlags)) + return MOJO_RESULT_UNIMPLEMENTED; + out_options->flags = reader.options().flags; + + // Checks for fields beyond |flags|: + + // (Nothing here yet.) + + return MOJO_RESULT_OK; +} + +// static +MojoResult SharedBufferDispatcher::Create( + embedder::PlatformSupport* platform_support, + const MojoCreateSharedBufferOptions& /*validated_options*/, + uint64_t num_bytes, + scoped_refptr<SharedBufferDispatcher>* result) { + if (!num_bytes) + return MOJO_RESULT_INVALID_ARGUMENT; + if (num_bytes > kMaxSharedMemoryNumBytes) + return MOJO_RESULT_RESOURCE_EXHAUSTED; + + scoped_refptr<embedder::PlatformSharedBuffer> shared_buffer( + platform_support->CreateSharedBuffer(static_cast<size_t>(num_bytes))); + if (!shared_buffer.get()) + return MOJO_RESULT_RESOURCE_EXHAUSTED; + + *result = new SharedBufferDispatcher(shared_buffer); + return MOJO_RESULT_OK; +} + +Dispatcher::Type SharedBufferDispatcher::GetType() const { + return kTypeSharedBuffer; +} + +// static +scoped_refptr<SharedBufferDispatcher> SharedBufferDispatcher::Deserialize( + Channel* channel, + const void* source, + size_t size, + embedder::PlatformHandleVector* platform_handles) { + DCHECK(channel); + + if (size != sizeof(SerializedSharedBufferDispatcher)) { + LOG(ERROR) << "Invalid serialized shared buffer dispatcher (bad size)"; + return scoped_refptr<SharedBufferDispatcher>(); + } + + const SerializedSharedBufferDispatcher* serialization = + static_cast<const SerializedSharedBufferDispatcher*>(source); + size_t num_bytes = serialization->num_bytes; + size_t platform_handle_index = serialization->platform_handle_index; + + if (!num_bytes) { + LOG(ERROR) + << "Invalid serialized shared buffer dispatcher (invalid num_bytes)"; + return scoped_refptr<SharedBufferDispatcher>(); + } + + if (!platform_handles || platform_handle_index >= platform_handles->size()) { + LOG(ERROR) + << "Invalid serialized shared buffer dispatcher (missing handles)"; + return scoped_refptr<SharedBufferDispatcher>(); + } + + // Starts off invalid, which is what we want. + embedder::PlatformHandle platform_handle; + // We take ownership of the handle, so we have to invalidate the one in + // |platform_handles|. + std::swap(platform_handle, (*platform_handles)[platform_handle_index]); + + // Wrapping |platform_handle| in a |ScopedPlatformHandle| means that it'll be + // closed even if creation fails. + scoped_refptr<embedder::PlatformSharedBuffer> shared_buffer( + channel->platform_support()->CreateSharedBufferFromHandle( + num_bytes, embedder::ScopedPlatformHandle(platform_handle))); + if (!shared_buffer.get()) { + LOG(ERROR) + << "Invalid serialized shared buffer dispatcher (invalid num_bytes?)"; + return scoped_refptr<SharedBufferDispatcher>(); + } + + return scoped_refptr<SharedBufferDispatcher>( + new SharedBufferDispatcher(shared_buffer)); +} + +SharedBufferDispatcher::SharedBufferDispatcher( + scoped_refptr<embedder::PlatformSharedBuffer> shared_buffer) + : shared_buffer_(shared_buffer) { + DCHECK(shared_buffer_.get()); +} + +SharedBufferDispatcher::~SharedBufferDispatcher() { +} + +// static +MojoResult SharedBufferDispatcher::ValidateDuplicateOptions( + UserPointer<const MojoDuplicateBufferHandleOptions> in_options, + MojoDuplicateBufferHandleOptions* out_options) { + const MojoDuplicateBufferHandleOptionsFlags kKnownFlags = + MOJO_DUPLICATE_BUFFER_HANDLE_OPTIONS_FLAG_NONE; + static const MojoDuplicateBufferHandleOptions kDefaultOptions = { + static_cast<uint32_t>(sizeof(MojoDuplicateBufferHandleOptions)), + MOJO_DUPLICATE_BUFFER_HANDLE_OPTIONS_FLAG_NONE}; + + *out_options = kDefaultOptions; + if (in_options.IsNull()) + return MOJO_RESULT_OK; + + UserOptionsReader<MojoDuplicateBufferHandleOptions> reader(in_options); + if (!reader.is_valid()) + return MOJO_RESULT_INVALID_ARGUMENT; + + if (!OPTIONS_STRUCT_HAS_MEMBER( + MojoDuplicateBufferHandleOptions, flags, reader)) + return MOJO_RESULT_OK; + if ((reader.options().flags & ~kKnownFlags)) + return MOJO_RESULT_UNIMPLEMENTED; + out_options->flags = reader.options().flags; + + // Checks for fields beyond |flags|: + + // (Nothing here yet.) + + return MOJO_RESULT_OK; +} + +void SharedBufferDispatcher::CloseImplNoLock() { + lock().AssertAcquired(); + DCHECK(shared_buffer_.get()); + shared_buffer_ = nullptr; +} + +scoped_refptr<Dispatcher> +SharedBufferDispatcher::CreateEquivalentDispatcherAndCloseImplNoLock() { + lock().AssertAcquired(); + DCHECK(shared_buffer_.get()); + scoped_refptr<embedder::PlatformSharedBuffer> shared_buffer; + shared_buffer.swap(shared_buffer_); + return scoped_refptr<Dispatcher>(new SharedBufferDispatcher(shared_buffer)); +} + +MojoResult SharedBufferDispatcher::DuplicateBufferHandleImplNoLock( + UserPointer<const MojoDuplicateBufferHandleOptions> options, + scoped_refptr<Dispatcher>* new_dispatcher) { + lock().AssertAcquired(); + + MojoDuplicateBufferHandleOptions validated_options; + MojoResult result = ValidateDuplicateOptions(options, &validated_options); + if (result != MOJO_RESULT_OK) + return result; + + *new_dispatcher = new SharedBufferDispatcher(shared_buffer_); + return MOJO_RESULT_OK; +} + +MojoResult SharedBufferDispatcher::MapBufferImplNoLock( + uint64_t offset, + uint64_t num_bytes, + MojoMapBufferFlags flags, + scoped_ptr<embedder::PlatformSharedBufferMapping>* mapping) { + lock().AssertAcquired(); + DCHECK(shared_buffer_.get()); + + if (offset > static_cast<uint64_t>(std::numeric_limits<size_t>::max())) + return MOJO_RESULT_INVALID_ARGUMENT; + if (num_bytes > static_cast<uint64_t>(std::numeric_limits<size_t>::max())) + return MOJO_RESULT_INVALID_ARGUMENT; + + if (!shared_buffer_->IsValidMap(static_cast<size_t>(offset), + static_cast<size_t>(num_bytes))) + return MOJO_RESULT_INVALID_ARGUMENT; + + DCHECK(mapping); + *mapping = shared_buffer_->MapNoCheck(static_cast<size_t>(offset), + static_cast<size_t>(num_bytes)); + if (!*mapping) + return MOJO_RESULT_RESOURCE_EXHAUSTED; + + return MOJO_RESULT_OK; +} + +void SharedBufferDispatcher::StartSerializeImplNoLock( + Channel* /*channel*/, + size_t* max_size, + size_t* max_platform_handles) { + DCHECK(HasOneRef()); // Only one ref => no need to take the lock. + *max_size = sizeof(SerializedSharedBufferDispatcher); + *max_platform_handles = 1; +} + +bool SharedBufferDispatcher::EndSerializeAndCloseImplNoLock( + Channel* /*channel*/, + void* destination, + size_t* actual_size, + embedder::PlatformHandleVector* platform_handles) { + DCHECK(HasOneRef()); // Only one ref => no need to take the lock. + DCHECK(shared_buffer_.get()); + + SerializedSharedBufferDispatcher* serialization = + static_cast<SerializedSharedBufferDispatcher*>(destination); + // If there's only one reference to |shared_buffer_|, then it's ours (and no + // one else can make any more references to it), so we can just take its + // handle. + embedder::ScopedPlatformHandle platform_handle( + shared_buffer_->HasOneRef() ? shared_buffer_->PassPlatformHandle() + : shared_buffer_->DuplicatePlatformHandle()); + if (!platform_handle.is_valid()) { + shared_buffer_ = nullptr; + return false; + } + + serialization->num_bytes = shared_buffer_->GetNumBytes(); + serialization->platform_handle_index = platform_handles->size(); + platform_handles->push_back(platform_handle.release()); + *actual_size = sizeof(SerializedSharedBufferDispatcher); + + shared_buffer_ = nullptr; + + return true; +} + +} // namespace system +} // namespace mojo |