| 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/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/embedder/platform_support.h" | |
| 12 #include "mojo/public/c/system/macros.h" | |
| 13 #include "mojo/system/channel.h" | |
| 14 #include "mojo/system/constants.h" | |
| 15 #include "mojo/system/memory.h" | |
| 16 #include "mojo/system/options_validation.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 > kMaxSharedMemoryNumBytes) | |
| 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.get()) | |
| 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 scoped_refptr<SharedBufferDispatcher>(); | |
| 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 scoped_refptr<SharedBufferDispatcher>(); | |
| 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 scoped_refptr<SharedBufferDispatcher>(); | |
| 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.get()) { | |
| 130 LOG(ERROR) | |
| 131 << "Invalid serialized shared buffer dispatcher (invalid num_bytes?)"; | |
| 132 return scoped_refptr<SharedBufferDispatcher>(); | |
| 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_.get()); | |
| 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( | |
| 167 MojoDuplicateBufferHandleOptions, flags, 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_.get()); | |
| 183 shared_buffer_ = nullptr; | |
| 184 } | |
| 185 | |
| 186 scoped_refptr<Dispatcher> | |
| 187 SharedBufferDispatcher::CreateEquivalentDispatcherAndCloseImplNoLock() { | |
| 188 lock().AssertAcquired(); | |
| 189 DCHECK(shared_buffer_.get()); | |
| 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_.get()); | |
| 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_.get()); | |
| 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 |