| // Copyright 2015 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/edk/system/data_pipe.h" |
| |
| #include <string.h> |
| |
| #include "mojo/edk/system/configuration.h" |
| #include "mojo/edk/system/options_validation.h" |
| #include "mojo/edk/system/raw_channel.h" |
| #include "mojo/edk/system/transport_data.h" |
| |
| namespace mojo { |
| namespace edk { |
| |
| namespace { |
| |
| const size_t kInvalidDataPipeHandleIndex = static_cast<size_t>(-1); |
| |
| struct MOJO_ALIGNAS(8) SerializedDataPipeHandleDispatcher { |
| size_t platform_handle_index; // (Or |kInvalidDataPipeHandleIndex|.) |
| |
| // These are from MojoCreateDataPipeOptions |
| MojoCreateDataPipeOptionsFlags flags; |
| uint32_t element_num_bytes; |
| uint32_t capacity_num_bytes; |
| |
| size_t shared_memory_handle_index; // (Or |kInvalidDataPipeHandleIndex|.) |
| uint32_t shared_memory_size; |
| }; |
| |
| } // namespace |
| |
| MojoCreateDataPipeOptions DataPipe::GetDefaultCreateOptions() { |
| MojoCreateDataPipeOptions result = { |
| static_cast<uint32_t>(sizeof(MojoCreateDataPipeOptions)), |
| MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, |
| 1u, |
| static_cast<uint32_t>( |
| GetConfiguration().default_data_pipe_capacity_bytes)}; |
| return result; |
| } |
| |
| MojoResult DataPipe::ValidateCreateOptions( |
| const MojoCreateDataPipeOptions* in_options, |
| MojoCreateDataPipeOptions* out_options) { |
| const MojoCreateDataPipeOptionsFlags kKnownFlags = |
| MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE; |
| |
| *out_options = GetDefaultCreateOptions(); |
| if (!in_options) |
| return MOJO_RESULT_OK; |
| |
| UserOptionsReader<MojoCreateDataPipeOptions> reader(in_options); |
| if (!reader.is_valid()) |
| return MOJO_RESULT_INVALID_ARGUMENT; |
| |
| if (!OPTIONS_STRUCT_HAS_MEMBER(MojoCreateDataPipeOptions, 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|: |
| |
| if (!OPTIONS_STRUCT_HAS_MEMBER(MojoCreateDataPipeOptions, element_num_bytes, |
| reader)) |
| return MOJO_RESULT_OK; |
| if (reader.options().element_num_bytes == 0) |
| return MOJO_RESULT_INVALID_ARGUMENT; |
| out_options->element_num_bytes = reader.options().element_num_bytes; |
| |
| if (!OPTIONS_STRUCT_HAS_MEMBER(MojoCreateDataPipeOptions, capacity_num_bytes, |
| reader) || |
| reader.options().capacity_num_bytes == 0) { |
| // Round the default capacity down to a multiple of the element size (but at |
| // least one element). |
| size_t default_data_pipe_capacity_bytes = |
| GetConfiguration().default_data_pipe_capacity_bytes; |
| out_options->capacity_num_bytes = |
| std::max(static_cast<uint32_t>(default_data_pipe_capacity_bytes - |
| (default_data_pipe_capacity_bytes % |
| out_options->element_num_bytes)), |
| out_options->element_num_bytes); |
| return MOJO_RESULT_OK; |
| } |
| if (reader.options().capacity_num_bytes % out_options->element_num_bytes != 0) |
| return MOJO_RESULT_INVALID_ARGUMENT; |
| if (reader.options().capacity_num_bytes > |
| GetConfiguration().max_data_pipe_capacity_bytes) |
| return MOJO_RESULT_RESOURCE_EXHAUSTED; |
| out_options->capacity_num_bytes = reader.options().capacity_num_bytes; |
| |
| return MOJO_RESULT_OK; |
| } |
| |
| void DataPipe::StartSerialize(bool have_channel_handle, |
| bool have_shared_memory, |
| size_t* max_size, |
| size_t* max_platform_handles) { |
| *max_size = sizeof(SerializedDataPipeHandleDispatcher); |
| *max_platform_handles = 0; |
| if (have_channel_handle) |
| (*max_platform_handles)++; |
| if (have_shared_memory) |
| (*max_platform_handles)++; |
| } |
| |
| void DataPipe::EndSerialize(const MojoCreateDataPipeOptions& options, |
| ScopedPlatformHandle channel_handle, |
| ScopedPlatformHandle shared_memory_handle, |
| size_t shared_memory_size, |
| void* destination, |
| size_t* actual_size, |
| PlatformHandleVector* platform_handles) { |
| SerializedDataPipeHandleDispatcher* serialization = |
| static_cast<SerializedDataPipeHandleDispatcher*>(destination); |
| if (channel_handle.is_valid()) { |
| serialization->platform_handle_index = platform_handles->size(); |
| platform_handles->push_back(channel_handle.release()); |
| } else { |
| serialization->platform_handle_index = kInvalidDataPipeHandleIndex; |
| } |
| |
| serialization->flags = options.flags; |
| serialization->element_num_bytes = options.element_num_bytes; |
| serialization->capacity_num_bytes = options.capacity_num_bytes; |
| |
| serialization->shared_memory_size = static_cast<uint32_t>(shared_memory_size); |
| if (serialization->shared_memory_size) { |
| serialization->shared_memory_handle_index = platform_handles->size(); |
| platform_handles->push_back(shared_memory_handle.release()); |
| } else { |
| serialization->shared_memory_handle_index = kInvalidDataPipeHandleIndex; |
| } |
| |
| *actual_size = sizeof(SerializedDataPipeHandleDispatcher); |
| } |
| |
| ScopedPlatformHandle DataPipe::Deserialize( |
| const void* source, |
| size_t size, |
| PlatformHandleVector* platform_handles, |
| MojoCreateDataPipeOptions* options, |
| ScopedPlatformHandle* shared_memory_handle, |
| size_t* shared_memory_size) { |
| if (size != sizeof(SerializedDataPipeHandleDispatcher)) { |
| LOG(ERROR) << "Invalid serialized data pipe dispatcher (bad size)"; |
| return ScopedPlatformHandle(); |
| } |
| |
| const SerializedDataPipeHandleDispatcher* serialization = |
| static_cast<const SerializedDataPipeHandleDispatcher*>(source); |
| size_t platform_handle_index = serialization->platform_handle_index; |
| |
| // Starts off invalid, which is what we want. |
| PlatformHandle platform_handle; |
| if (platform_handle_index != kInvalidDataPipeHandleIndex) { |
| if (!platform_handles || |
| platform_handle_index >= platform_handles->size()) { |
| LOG(ERROR) |
| << "Invalid serialized data pipe dispatcher (missing handles)"; |
| return ScopedPlatformHandle(); |
| } |
| |
| // 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]); |
| } |
| |
| options->struct_size = sizeof(MojoCreateDataPipeOptions); |
| options->flags = serialization->flags; |
| options->element_num_bytes = serialization->element_num_bytes; |
| options->capacity_num_bytes = serialization->capacity_num_bytes; |
| |
| if (shared_memory_size) { |
| *shared_memory_size = serialization->shared_memory_size; |
| if (*shared_memory_size) { |
| DCHECK(serialization->shared_memory_handle_index != |
| kInvalidDataPipeHandleIndex); |
| if (!platform_handles || |
| serialization->shared_memory_handle_index >= |
| platform_handles->size()) { |
| LOG(ERROR) << "Invalid serialized data pipe dispatcher " |
| << "(missing handles)"; |
| return ScopedPlatformHandle(); |
| } |
| |
| PlatformHandle temp_shared_memory_handle; |
| std::swap(temp_shared_memory_handle, |
| (*platform_handles)[serialization->shared_memory_handle_index]); |
| *shared_memory_handle = |
| ScopedPlatformHandle(temp_shared_memory_handle); |
| } |
| } |
| |
| size -= sizeof(SerializedDataPipeHandleDispatcher); |
| |
| return ScopedPlatformHandle(platform_handle); |
| } |
| |
| } // namespace edk |
| } // namespace mojo |