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