Home | History | Annotate | Download | only in system
      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
     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
     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 
     79 Dispatcher::Type SharedBufferDispatcher::GetType() const {
     80   return kTypeSharedBuffer;
     81 }
     82 
     83 // static
     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 
    132 SharedBufferDispatcher::SharedBufferDispatcher(
    133     scoped_refptr<RawSharedBuffer> shared_buffer)
    134     : shared_buffer_(shared_buffer) {
    135   DCHECK(shared_buffer_);
    136 }
    137 
    138 SharedBufferDispatcher::~SharedBufferDispatcher() {
    139 }
    140 
    141 // static
    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 
    170 void SharedBufferDispatcher::CloseImplNoLock() {
    171   lock().AssertAcquired();
    172   DCHECK(shared_buffer_);
    173   shared_buffer_ = NULL;
    174 }
    175 
    176 scoped_refptr<Dispatcher>
    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 
    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 
    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 
    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 
    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 
    266 HandleSignalsState SharedBufferDispatcher::GetHandleSignalsStateNoLock() const {
    267   // TODO(vtl): Add transferrable flag.
    268   return HandleSignalsState();
    269 }
    270 
    271 }  // namespace system
    272 }  // namespace mojo
    273