// Copyright 2013 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/core/core.h" #include <string.h> #include <algorithm> #include <utility> #include "base/bind.h" #include "base/containers/stack_container.h" #include "base/location.h" #include "base/logging.h" #include "base/macros.h" #include "base/memory/ptr_util.h" #include "base/memory/writable_shared_memory_region.h" #include "base/rand_util.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_piece.h" #include "base/threading/thread_task_runner_handle.h" #include "base/time/time.h" // #include "base/trace_event/memory_dump_manager.h" #include "build/build_config.h" #include "mojo/core/channel.h" #include "mojo/core/configuration.h" #include "mojo/core/data_pipe_consumer_dispatcher.h" #include "mojo/core/data_pipe_producer_dispatcher.h" #include "mojo/core/embedder/process_error_callback.h" #include "mojo/core/handle_signals_state.h" #include "mojo/core/invitation_dispatcher.h" #include "mojo/core/message_pipe_dispatcher.h" #include "mojo/core/platform_handle_dispatcher.h" #include "mojo/core/platform_handle_utils.h" #include "mojo/core/platform_shared_memory_mapping.h" #include "mojo/core/ports/event.h" #include "mojo/core/ports/name.h" #include "mojo/core/ports/node.h" #include "mojo/core/request_context.h" #include "mojo/core/shared_buffer_dispatcher.h" #include "mojo/core/user_message_impl.h" #include "mojo/core/watcher_dispatcher.h" namespace mojo { namespace core { namespace { // This is an unnecessarily large limit that is relatively easy to enforce. const uint32_t kMaxHandlesPerMessage = 1024 * 1024; // TODO(rockot): Maybe we could negotiate a debugging pipe ID for cross-process // pipes too; for now we just use a constant. This only affects bootstrap pipes. const uint64_t kUnknownPipeIdForDebug = 0x7f7f7f7f7f7f7f7fUL; // The pipe name which must be used for the sole pipe attachment on any isolated // invitation. constexpr base::StringPiece kIsolatedInvitationPipeName = {"\0\0\0\0", 4}; void InvokeProcessErrorCallbackOnTaskRunner( scoped_refptr<base::TaskRunner> task_runner, MojoProcessErrorHandler handler, uintptr_t context, const std::string& error, MojoProcessErrorFlags flags) { // We always run the handler asynchronously to ensure no Mojo core reentrancy. task_runner->PostTask( FROM_HERE, base::BindOnce( [](MojoProcessErrorHandler handler, uintptr_t context, const std::string& error, MojoProcessErrorFlags flags) { MojoProcessErrorDetails details; details.struct_size = sizeof(details); DCHECK(base::IsValueInRangeForNumericType<uint32_t>(error.size())); details.error_message_length = static_cast<uint32_t>(error.size()); if (!error.empty()) details.error_message = error.data(); else details.error_message = nullptr; details.flags = flags; handler(context, &details); }, handler, context, error, flags)); } // Helper class which is bound to the lifetime of a // ProcessErrorCallback generated by the |MojoSendInvitation()| // API. When the last reference to the error callback is lost within the EDK, // which will happen shortly after a connection to the process is lost, that // obviously guarantees that no more invocations of the callback will occur. At // that point, the corresponding instance of this object (owned by the callback // -- see Core::SendInvitation) will be destroyed. class ProcessDisconnectHandler { public: ProcessDisconnectHandler(scoped_refptr<base::TaskRunner> task_runner, MojoProcessErrorHandler handler, uintptr_t context) : task_runner_(std::move(task_runner)), handler_(handler), context_(context) {} ~ProcessDisconnectHandler() { InvokeProcessErrorCallbackOnTaskRunner( task_runner_, handler_, context_, std::string(), MOJO_PROCESS_ERROR_FLAG_DISCONNECTED); } private: const scoped_refptr<base::TaskRunner> task_runner_; const MojoProcessErrorHandler handler_; const uintptr_t context_; DISALLOW_COPY_AND_ASSIGN(ProcessDisconnectHandler); }; void RunMojoProcessErrorHandler(ProcessDisconnectHandler* disconnect_handler, scoped_refptr<base::TaskRunner> task_runner, MojoProcessErrorHandler handler, uintptr_t context, const std::string& error) { InvokeProcessErrorCallbackOnTaskRunner(task_runner, handler, context, error, MOJO_PROCESS_ERROR_FLAG_NONE); } } // namespace Core::Core() { handles_.reset(new HandleTable); // base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider( // handles_.get(), "MojoHandleTable", nullptr); } Core::~Core() { if (node_controller_ && node_controller_->io_task_runner()) { // If this races with IO thread shutdown the callback will be dropped and // the NodeController will be shutdown on this thread anyway, which is also // just fine. scoped_refptr<base::TaskRunner> io_task_runner = node_controller_->io_task_runner(); io_task_runner->PostTask(FROM_HERE, base::BindOnce(&Core::PassNodeControllerToIOThread, base::Passed(&node_controller_))); } // base::trace_event::MemoryDumpManager::GetInstance() // ->UnregisterAndDeleteDumpProviderSoon(std::move(handles_)); } void Core::SetIOTaskRunner(scoped_refptr<base::TaskRunner> io_task_runner) { GetNodeController()->SetIOTaskRunner(io_task_runner); } NodeController* Core::GetNodeController() { base::AutoLock lock(node_controller_lock_); if (!node_controller_) node_controller_.reset(new NodeController(this)); return node_controller_.get(); } scoped_refptr<Dispatcher> Core::GetDispatcher(MojoHandle handle) { base::AutoLock lock(handles_->GetLock()); return handles_->GetDispatcher(handle); } scoped_refptr<Dispatcher> Core::GetAndRemoveDispatcher(MojoHandle handle) { scoped_refptr<Dispatcher> dispatcher; base::AutoLock lock(handles_->GetLock()); handles_->GetAndRemoveDispatcher(handle, &dispatcher); return dispatcher; } void Core::SetDefaultProcessErrorCallback( const ProcessErrorCallback& callback) { default_process_error_callback_ = callback; } MojoHandle Core::CreatePartialMessagePipe(ports::PortRef* peer) { RequestContext request_context; ports::PortRef local_port; GetNodeController()->node()->CreatePortPair(&local_port, peer); return AddDispatcher(new MessagePipeDispatcher( GetNodeController(), local_port, kUnknownPipeIdForDebug, 0)); } MojoHandle Core::CreatePartialMessagePipe(const ports::PortRef& port) { RequestContext request_context; return AddDispatcher(new MessagePipeDispatcher(GetNodeController(), port, kUnknownPipeIdForDebug, 1)); } void Core::SendBrokerClientInvitation( base::ProcessHandle target_process, ConnectionParams connection_params, const std::vector<std::pair<std::string, ports::PortRef>>& attached_ports, const ProcessErrorCallback& process_error_callback) { RequestContext request_context; GetNodeController()->SendBrokerClientInvitation( target_process, std::move(connection_params), attached_ports, process_error_callback); } void Core::AcceptBrokerClientInvitation(ConnectionParams connection_params) { RequestContext request_context; GetNodeController()->AcceptBrokerClientInvitation( std::move(connection_params)); } void Core::ConnectIsolated(ConnectionParams connection_params, const ports::PortRef& port, base::StringPiece connection_name) { RequestContext request_context; GetNodeController()->ConnectIsolated(std::move(connection_params), port, connection_name); } void Core::SetMachPortProvider(base::PortProvider* port_provider) { #if defined(OS_MACOSX) && !defined(OS_IOS) GetNodeController()->CreateMachPortRelay(port_provider); #endif } #if defined(OS_MACOSX) && !defined(OS_IOS) MachPortRelay* Core::GetMachPortRelay() { return GetNodeController()->GetMachPortRelay(); } #endif MojoHandle Core::AddDispatcher(scoped_refptr<Dispatcher> dispatcher) { base::AutoLock lock(handles_->GetLock()); return handles_->AddDispatcher(dispatcher); } bool Core::AddDispatchersFromTransit( const std::vector<Dispatcher::DispatcherInTransit>& dispatchers, MojoHandle* handles) { bool failed = false; { base::AutoLock lock(handles_->GetLock()); if (!handles_->AddDispatchersFromTransit(dispatchers, handles)) failed = true; } if (failed) { for (auto d : dispatchers) { if (d.dispatcher) d.dispatcher->Close(); } return false; } return true; } MojoResult Core::AcquireDispatchersForTransit( const MojoHandle* handles, size_t num_handles, std::vector<Dispatcher::DispatcherInTransit>* dispatchers) { base::AutoLock lock(handles_->GetLock()); MojoResult rv = handles_->BeginTransit(handles, num_handles, dispatchers); if (rv != MOJO_RESULT_OK) handles_->CancelTransit(*dispatchers); return rv; } void Core::ReleaseDispatchersForTransit( const std::vector<Dispatcher::DispatcherInTransit>& dispatchers, bool in_transit) { base::AutoLock lock(handles_->GetLock()); if (in_transit) handles_->CompleteTransitAndClose(dispatchers); else handles_->CancelTransit(dispatchers); } void Core::RequestShutdown(const base::Closure& callback) { GetNodeController()->RequestShutdown(callback); } MojoHandle Core::ExtractMessagePipeFromInvitation(const std::string& name) { RequestContext request_context; ports::PortRef port0, port1; GetNodeController()->node()->CreatePortPair(&port0, &port1); MojoHandle handle = AddDispatcher(new MessagePipeDispatcher( GetNodeController(), port0, kUnknownPipeIdForDebug, 1)); GetNodeController()->MergePortIntoInviter(name, port1); return handle; } MojoTimeTicks Core::GetTimeTicksNow() { return base::TimeTicks::Now().ToInternalValue(); } MojoResult Core::Close(MojoHandle handle) { RequestContext request_context; scoped_refptr<Dispatcher> dispatcher; { base::AutoLock lock(handles_->GetLock()); MojoResult rv = handles_->GetAndRemoveDispatcher(handle, &dispatcher); if (rv != MOJO_RESULT_OK) return rv; } dispatcher->Close(); return MOJO_RESULT_OK; } MojoResult Core::QueryHandleSignalsState( MojoHandle handle, MojoHandleSignalsState* signals_state) { RequestContext request_context; scoped_refptr<Dispatcher> dispatcher = GetDispatcher(handle); if (!dispatcher || !signals_state) return MOJO_RESULT_INVALID_ARGUMENT; *signals_state = dispatcher->GetHandleSignalsState(); return MOJO_RESULT_OK; } MojoResult Core::CreateTrap(MojoTrapEventHandler handler, const MojoCreateTrapOptions* options, MojoHandle* trap_handle) { if (options && options->struct_size < sizeof(*options)) return MOJO_RESULT_INVALID_ARGUMENT; RequestContext request_context; if (!trap_handle) return MOJO_RESULT_INVALID_ARGUMENT; *trap_handle = AddDispatcher(new WatcherDispatcher(handler)); if (*trap_handle == MOJO_HANDLE_INVALID) return MOJO_RESULT_RESOURCE_EXHAUSTED; return MOJO_RESULT_OK; } MojoResult Core::AddTrigger(MojoHandle trap_handle, MojoHandle handle, MojoHandleSignals signals, MojoTriggerCondition condition, uintptr_t context, const MojoAddTriggerOptions* options) { if (options && options->struct_size < sizeof(*options)) return MOJO_RESULT_INVALID_ARGUMENT; RequestContext request_context; scoped_refptr<Dispatcher> watcher = GetDispatcher(trap_handle); if (!watcher || watcher->GetType() != Dispatcher::Type::WATCHER) return MOJO_RESULT_INVALID_ARGUMENT; scoped_refptr<Dispatcher> dispatcher = GetDispatcher(handle); if (!dispatcher) return MOJO_RESULT_INVALID_ARGUMENT; return watcher->WatchDispatcher(std::move(dispatcher), signals, condition, context); } MojoResult Core::RemoveTrigger(MojoHandle trap_handle, uintptr_t context, const MojoRemoveTriggerOptions* options) { if (options && options->struct_size < sizeof(*options)) return MOJO_RESULT_INVALID_ARGUMENT; RequestContext request_context; scoped_refptr<Dispatcher> watcher = GetDispatcher(trap_handle); if (!watcher || watcher->GetType() != Dispatcher::Type::WATCHER) return MOJO_RESULT_INVALID_ARGUMENT; return watcher->CancelWatch(context); } MojoResult Core::ArmTrap(MojoHandle trap_handle, const MojoArmTrapOptions* options, uint32_t* num_blocking_events, MojoTrapEvent* blocking_events) { if (options && options->struct_size < sizeof(*options)) return MOJO_RESULT_INVALID_ARGUMENT; RequestContext request_context; scoped_refptr<Dispatcher> watcher = GetDispatcher(trap_handle); if (!watcher || watcher->GetType() != Dispatcher::Type::WATCHER) return MOJO_RESULT_INVALID_ARGUMENT; return watcher->Arm(num_blocking_events, blocking_events); } MojoResult Core::CreateMessage(const MojoCreateMessageOptions* options, MojoMessageHandle* message_handle) { if (!message_handle) return MOJO_RESULT_INVALID_ARGUMENT; if (options && options->struct_size < sizeof(*options)) return MOJO_RESULT_INVALID_ARGUMENT; *message_handle = reinterpret_cast<MojoMessageHandle>( UserMessageImpl::CreateEventForNewMessage().release()); return MOJO_RESULT_OK; } MojoResult Core::DestroyMessage(MojoMessageHandle message_handle) { if (!message_handle) return MOJO_RESULT_INVALID_ARGUMENT; RequestContext request_context; delete reinterpret_cast<ports::UserMessageEvent*>(message_handle); return MOJO_RESULT_OK; } MojoResult Core::SerializeMessage(MojoMessageHandle message_handle, const MojoSerializeMessageOptions* options) { if (!message_handle) return MOJO_RESULT_INVALID_ARGUMENT; if (options && options->struct_size < sizeof(*options)) return MOJO_RESULT_INVALID_ARGUMENT; RequestContext request_context; return reinterpret_cast<ports::UserMessageEvent*>(message_handle) ->GetMessage<UserMessageImpl>() ->SerializeIfNecessary(); } MojoResult Core::AppendMessageData(MojoMessageHandle message_handle, uint32_t additional_payload_size, const MojoHandle* handles, uint32_t num_handles, const MojoAppendMessageDataOptions* options, void** buffer, uint32_t* buffer_size) { if (!message_handle || (num_handles && !handles)) return MOJO_RESULT_INVALID_ARGUMENT; if (options && options->struct_size < sizeof(*options)) return MOJO_RESULT_INVALID_ARGUMENT; RequestContext request_context; auto* message = reinterpret_cast<ports::UserMessageEvent*>(message_handle) ->GetMessage<UserMessageImpl>(); MojoResult rv = message->AppendData(additional_payload_size, handles, num_handles); if (rv != MOJO_RESULT_OK) return rv; if (options && (options->flags & MOJO_APPEND_MESSAGE_DATA_FLAG_COMMIT_SIZE)) { RequestContext request_context; message->CommitSize(); } if (buffer) *buffer = message->user_payload(); if (buffer_size) { *buffer_size = base::checked_cast<uint32_t>(message->user_payload_capacity()); } return MOJO_RESULT_OK; } MojoResult Core::GetMessageData(MojoMessageHandle message_handle, const MojoGetMessageDataOptions* options, void** buffer, uint32_t* num_bytes, MojoHandle* handles, uint32_t* num_handles) { if (!message_handle || (num_handles && *num_handles && !handles)) return MOJO_RESULT_INVALID_ARGUMENT; if (options && options->struct_size < sizeof(*options)) return MOJO_RESULT_INVALID_ARGUMENT; auto* message = reinterpret_cast<ports::UserMessageEvent*>(message_handle) ->GetMessage<UserMessageImpl>(); if (!message->IsSerialized() || !message->IsTransmittable()) return MOJO_RESULT_FAILED_PRECONDITION; if (num_bytes) { base::CheckedNumeric<uint32_t> payload_size = message->user_payload_size(); *num_bytes = payload_size.ValueOrDie(); } if (message->user_payload_size() > 0) { if (!num_bytes || !buffer) return MOJO_RESULT_RESOURCE_EXHAUSTED; *buffer = message->user_payload(); } else if (buffer) { *buffer = nullptr; } if (options && (options->flags & MOJO_GET_MESSAGE_DATA_FLAG_IGNORE_HANDLES)) return MOJO_RESULT_OK; uint32_t max_num_handles = 0; if (num_handles) { max_num_handles = *num_handles; *num_handles = static_cast<uint32_t>(message->num_handles()); } if (message->num_handles() > max_num_handles || message->num_handles() > kMaxHandlesPerMessage) { return MOJO_RESULT_RESOURCE_EXHAUSTED; } RequestContext request_context; return message->ExtractSerializedHandles( UserMessageImpl::ExtractBadHandlePolicy::kAbort, handles); } MojoResult Core::SetMessageContext( MojoMessageHandle message_handle, uintptr_t context, MojoMessageContextSerializer serializer, MojoMessageContextDestructor destructor, const MojoSetMessageContextOptions* options) { if (!message_handle) return MOJO_RESULT_INVALID_ARGUMENT; if (options && options->struct_size < sizeof(*options)) return MOJO_RESULT_INVALID_ARGUMENT; auto* message = reinterpret_cast<ports::UserMessageEvent*>(message_handle) ->GetMessage<UserMessageImpl>(); return message->SetContext(context, serializer, destructor); } MojoResult Core::GetMessageContext(MojoMessageHandle message_handle, const MojoGetMessageContextOptions* options, uintptr_t* context) { if (!message_handle) return MOJO_RESULT_INVALID_ARGUMENT; if (options && options->struct_size < sizeof(*options)) return MOJO_RESULT_INVALID_ARGUMENT; auto* message = reinterpret_cast<ports::UserMessageEvent*>(message_handle) ->GetMessage<UserMessageImpl>(); if (!message->HasContext()) return MOJO_RESULT_NOT_FOUND; *context = message->context(); return MOJO_RESULT_OK; } MojoResult Core::CreateMessagePipe(const MojoCreateMessagePipeOptions* options, MojoHandle* message_pipe_handle0, MojoHandle* message_pipe_handle1) { RequestContext request_context; ports::PortRef port0, port1; GetNodeController()->node()->CreatePortPair(&port0, &port1); DCHECK(message_pipe_handle0); DCHECK(message_pipe_handle1); uint64_t pipe_id = base::RandUint64(); *message_pipe_handle0 = AddDispatcher( new MessagePipeDispatcher(GetNodeController(), port0, pipe_id, 0)); if (*message_pipe_handle0 == MOJO_HANDLE_INVALID) return MOJO_RESULT_RESOURCE_EXHAUSTED; *message_pipe_handle1 = AddDispatcher( new MessagePipeDispatcher(GetNodeController(), port1, pipe_id, 1)); if (*message_pipe_handle1 == MOJO_HANDLE_INVALID) { scoped_refptr<Dispatcher> dispatcher0; { base::AutoLock lock(handles_->GetLock()); handles_->GetAndRemoveDispatcher(*message_pipe_handle0, &dispatcher0); } dispatcher0->Close(); return MOJO_RESULT_RESOURCE_EXHAUSTED; } return MOJO_RESULT_OK; } MojoResult Core::WriteMessage(MojoHandle message_pipe_handle, MojoMessageHandle message_handle, const MojoWriteMessageOptions* options) { RequestContext request_context; if (!message_handle) return MOJO_RESULT_INVALID_ARGUMENT; auto message_event = base::WrapUnique( reinterpret_cast<ports::UserMessageEvent*>(message_handle)); auto* message = message_event->GetMessage<UserMessageImpl>(); if (!message || !message->IsTransmittable()) return MOJO_RESULT_INVALID_ARGUMENT; auto dispatcher = GetDispatcher(message_pipe_handle); if (!dispatcher) return MOJO_RESULT_INVALID_ARGUMENT; return dispatcher->WriteMessage(std::move(message_event)); } MojoResult Core::ReadMessage(MojoHandle message_pipe_handle, const MojoReadMessageOptions* options, MojoMessageHandle* message_handle) { RequestContext request_context; auto dispatcher = GetDispatcher(message_pipe_handle); if (!dispatcher || !message_handle) return MOJO_RESULT_INVALID_ARGUMENT; std::unique_ptr<ports::UserMessageEvent> message_event; MojoResult rv = dispatcher->ReadMessage(&message_event); if (rv != MOJO_RESULT_OK) return rv; *message_handle = reinterpret_cast<MojoMessageHandle>(message_event.release()); return MOJO_RESULT_OK; } MojoResult Core::FuseMessagePipes(MojoHandle handle0, MojoHandle handle1, const MojoFuseMessagePipesOptions* options) { RequestContext request_context; scoped_refptr<Dispatcher> dispatcher0; scoped_refptr<Dispatcher> dispatcher1; bool valid_handles = true; { base::AutoLock lock(handles_->GetLock()); MojoResult result0 = handles_->GetAndRemoveDispatcher(handle0, &dispatcher0); MojoResult result1 = handles_->GetAndRemoveDispatcher(handle1, &dispatcher1); if (result0 != MOJO_RESULT_OK || result1 != MOJO_RESULT_OK || dispatcher0->GetType() != Dispatcher::Type::MESSAGE_PIPE || dispatcher1->GetType() != Dispatcher::Type::MESSAGE_PIPE) valid_handles = false; } if (!valid_handles) { if (dispatcher0) dispatcher0->Close(); if (dispatcher1) dispatcher1->Close(); return MOJO_RESULT_INVALID_ARGUMENT; } MessagePipeDispatcher* mpd0 = static_cast<MessagePipeDispatcher*>(dispatcher0.get()); MessagePipeDispatcher* mpd1 = static_cast<MessagePipeDispatcher*>(dispatcher1.get()); if (!mpd0->Fuse(mpd1)) return MOJO_RESULT_FAILED_PRECONDITION; return MOJO_RESULT_OK; } MojoResult Core::NotifyBadMessage(MojoMessageHandle message_handle, const char* error, size_t error_num_bytes, const MojoNotifyBadMessageOptions* options) { if (!message_handle) return MOJO_RESULT_INVALID_ARGUMENT; auto* message_event = reinterpret_cast<ports::UserMessageEvent*>(message_handle); auto* message = message_event->GetMessage<UserMessageImpl>(); if (message->source_node() == ports::kInvalidNodeName) { DVLOG(1) << "Received invalid message from unknown node."; if (!default_process_error_callback_.is_null()) default_process_error_callback_.Run(std::string(error, error_num_bytes)); return MOJO_RESULT_OK; } GetNodeController()->NotifyBadMessageFrom( message->source_node(), std::string(error, error_num_bytes)); return MOJO_RESULT_OK; } MojoResult Core::CreateDataPipe(const MojoCreateDataPipeOptions* options, MojoHandle* data_pipe_producer_handle, MojoHandle* data_pipe_consumer_handle) { RequestContext request_context; if (options && options->struct_size < sizeof(MojoCreateDataPipeOptions)) return MOJO_RESULT_INVALID_ARGUMENT; MojoCreateDataPipeOptions create_options; create_options.struct_size = sizeof(MojoCreateDataPipeOptions); create_options.flags = options ? options->flags : 0; create_options.element_num_bytes = options ? options->element_num_bytes : 1; // TODO(rockot): Use Configuration to get default data pipe capacity. create_options.capacity_num_bytes = options && options->capacity_num_bytes ? options->capacity_num_bytes : 64 * 1024; if (!create_options.element_num_bytes || !create_options.capacity_num_bytes || create_options.capacity_num_bytes < create_options.element_num_bytes) { return MOJO_RESULT_INVALID_ARGUMENT; } base::subtle::PlatformSharedMemoryRegion ring_buffer_region = base::WritableSharedMemoryRegion::TakeHandleForSerialization( GetNodeController()->CreateSharedBuffer( create_options.capacity_num_bytes)); // NOTE: We demote the writable region to an unsafe region so that the // producer handle can be transferred freely. There is no compelling reason // to restrict access rights of consumers since they are the exclusive // consumer of this pipe, and it would be impossible to support such access // control on Android anyway. auto writable_region_handle = ring_buffer_region.PassPlatformHandle(); #if defined(OS_POSIX) && !defined(OS_ANDROID) && \ (!defined(OS_MACOSX) || defined(OS_IOS)) // This isn't strictly necessary, but it does make the handle configuration // consistent with regular UnsafeSharedMemoryRegions. writable_region_handle.readonly_fd.reset(); #endif base::UnsafeSharedMemoryRegion producer_region = base::UnsafeSharedMemoryRegion::Deserialize( base::subtle::PlatformSharedMemoryRegion::Take( std::move(writable_region_handle), base::subtle::PlatformSharedMemoryRegion::Mode::kUnsafe, create_options.capacity_num_bytes, ring_buffer_region.GetGUID())); if (!producer_region.IsValid()) return MOJO_RESULT_RESOURCE_EXHAUSTED; ports::PortRef port0, port1; GetNodeController()->node()->CreatePortPair(&port0, &port1); DCHECK(data_pipe_producer_handle); DCHECK(data_pipe_consumer_handle); base::UnsafeSharedMemoryRegion consumer_region = producer_region.Duplicate(); uint64_t pipe_id = base::RandUint64(); scoped_refptr<Dispatcher> producer = DataPipeProducerDispatcher::Create( GetNodeController(), port0, std::move(producer_region), create_options, pipe_id); if (!producer) return MOJO_RESULT_RESOURCE_EXHAUSTED; scoped_refptr<Dispatcher> consumer = DataPipeConsumerDispatcher::Create( GetNodeController(), port1, std::move(consumer_region), create_options, pipe_id); if (!consumer) { producer->Close(); return MOJO_RESULT_RESOURCE_EXHAUSTED; } *data_pipe_producer_handle = AddDispatcher(producer); *data_pipe_consumer_handle = AddDispatcher(consumer); if (*data_pipe_producer_handle == MOJO_HANDLE_INVALID || *data_pipe_consumer_handle == MOJO_HANDLE_INVALID) { if (*data_pipe_producer_handle != MOJO_HANDLE_INVALID) { scoped_refptr<Dispatcher> unused; base::AutoLock lock(handles_->GetLock()); handles_->GetAndRemoveDispatcher(*data_pipe_producer_handle, &unused); } producer->Close(); consumer->Close(); return MOJO_RESULT_RESOURCE_EXHAUSTED; } return MOJO_RESULT_OK; } MojoResult Core::WriteData(MojoHandle data_pipe_producer_handle, const void* elements, uint32_t* num_bytes, const MojoWriteDataOptions* options) { RequestContext request_context; scoped_refptr<Dispatcher> dispatcher( GetDispatcher(data_pipe_producer_handle)); if (!dispatcher) return MOJO_RESULT_INVALID_ARGUMENT; MojoWriteDataOptions validated_options; if (options) { if (options->struct_size < sizeof(*options)) return MOJO_RESULT_INVALID_ARGUMENT; constexpr MojoWriteDataFlags kSupportedFlags = MOJO_WRITE_DATA_FLAG_NONE | MOJO_WRITE_DATA_FLAG_ALL_OR_NONE; if (options->flags & ~kSupportedFlags) return MOJO_RESULT_UNIMPLEMENTED; validated_options.flags = options->flags; } else { validated_options.flags = MOJO_WRITE_DATA_FLAG_NONE; } return dispatcher->WriteData(elements, num_bytes, validated_options); } MojoResult Core::BeginWriteData(MojoHandle data_pipe_producer_handle, const MojoBeginWriteDataOptions* options, void** buffer, uint32_t* buffer_num_bytes) { RequestContext request_context; scoped_refptr<Dispatcher> dispatcher( GetDispatcher(data_pipe_producer_handle)); if (!dispatcher) return MOJO_RESULT_INVALID_ARGUMENT; if (options) { if (options->struct_size < sizeof(*options)) return MOJO_RESULT_INVALID_ARGUMENT; if (options->flags != MOJO_BEGIN_WRITE_DATA_FLAG_NONE) return MOJO_RESULT_UNIMPLEMENTED; } return dispatcher->BeginWriteData(buffer, buffer_num_bytes); } MojoResult Core::EndWriteData(MojoHandle data_pipe_producer_handle, uint32_t num_bytes_written, const MojoEndWriteDataOptions* options) { RequestContext request_context; scoped_refptr<Dispatcher> dispatcher( GetDispatcher(data_pipe_producer_handle)); if (!dispatcher) return MOJO_RESULT_INVALID_ARGUMENT; if (options) { if (options->struct_size < sizeof(*options)) return MOJO_RESULT_INVALID_ARGUMENT; if (options->flags != MOJO_END_WRITE_DATA_FLAG_NONE) return MOJO_RESULT_UNIMPLEMENTED; } return dispatcher->EndWriteData(num_bytes_written); } MojoResult Core::ReadData(MojoHandle data_pipe_consumer_handle, const MojoReadDataOptions* options, void* elements, uint32_t* num_bytes) { RequestContext request_context; scoped_refptr<Dispatcher> dispatcher( GetDispatcher(data_pipe_consumer_handle)); if (!dispatcher) return MOJO_RESULT_INVALID_ARGUMENT; MojoReadDataOptions validated_options; if (options) { if (options->struct_size < sizeof(*options)) return MOJO_RESULT_INVALID_ARGUMENT; constexpr MojoReadDataFlags kSupportedFlags = MOJO_READ_DATA_FLAG_NONE | MOJO_READ_DATA_FLAG_ALL_OR_NONE | MOJO_READ_DATA_FLAG_DISCARD | MOJO_READ_DATA_FLAG_QUERY | MOJO_READ_DATA_FLAG_PEEK; if (options->flags & ~kSupportedFlags) return MOJO_RESULT_UNIMPLEMENTED; validated_options.flags = options->flags; } else { validated_options.flags = MOJO_WRITE_DATA_FLAG_NONE; } return dispatcher->ReadData(validated_options, elements, num_bytes); } MojoResult Core::BeginReadData(MojoHandle data_pipe_consumer_handle, const MojoBeginReadDataOptions* options, const void** buffer, uint32_t* buffer_num_bytes) { RequestContext request_context; scoped_refptr<Dispatcher> dispatcher( GetDispatcher(data_pipe_consumer_handle)); if (!dispatcher) return MOJO_RESULT_INVALID_ARGUMENT; if (options) { if (options->struct_size < sizeof(*options)) return MOJO_RESULT_INVALID_ARGUMENT; if (options->flags != MOJO_BEGIN_READ_DATA_FLAG_NONE) return MOJO_RESULT_UNIMPLEMENTED; } return dispatcher->BeginReadData(buffer, buffer_num_bytes); } MojoResult Core::EndReadData(MojoHandle data_pipe_consumer_handle, uint32_t num_bytes_read, const MojoEndReadDataOptions* options) { RequestContext request_context; scoped_refptr<Dispatcher> dispatcher( GetDispatcher(data_pipe_consumer_handle)); if (!dispatcher) return MOJO_RESULT_INVALID_ARGUMENT; if (options) { if (options->struct_size < sizeof(*options)) return MOJO_RESULT_INVALID_ARGUMENT; if (options->flags != MOJO_END_READ_DATA_FLAG_NONE) return MOJO_RESULT_UNIMPLEMENTED; } return dispatcher->EndReadData(num_bytes_read); } MojoResult Core::CreateSharedBuffer( uint64_t num_bytes, const MojoCreateSharedBufferOptions* options, MojoHandle* shared_buffer_handle) { RequestContext request_context; MojoCreateSharedBufferOptions validated_options = {}; MojoResult result = SharedBufferDispatcher::ValidateCreateOptions( options, &validated_options); if (result != MOJO_RESULT_OK) return result; scoped_refptr<SharedBufferDispatcher> dispatcher; result = SharedBufferDispatcher::Create( validated_options, GetNodeController(), num_bytes, &dispatcher); if (result != MOJO_RESULT_OK) { DCHECK(!dispatcher); return result; } *shared_buffer_handle = AddDispatcher(dispatcher); if (*shared_buffer_handle == MOJO_HANDLE_INVALID) { LOG(ERROR) << "Handle table full"; dispatcher->Close(); return MOJO_RESULT_RESOURCE_EXHAUSTED; } return MOJO_RESULT_OK; } MojoResult Core::DuplicateBufferHandle( MojoHandle buffer_handle, const MojoDuplicateBufferHandleOptions* options, MojoHandle* new_buffer_handle) { RequestContext request_context; scoped_refptr<Dispatcher> dispatcher(GetDispatcher(buffer_handle)); if (!dispatcher) return MOJO_RESULT_INVALID_ARGUMENT; // Don't verify |options| here; that's the dispatcher's job. scoped_refptr<Dispatcher> new_dispatcher; MojoResult result = dispatcher->DuplicateBufferHandle(options, &new_dispatcher); if (result != MOJO_RESULT_OK) return result; *new_buffer_handle = AddDispatcher(new_dispatcher); if (*new_buffer_handle == MOJO_HANDLE_INVALID) { LOG(ERROR) << "Handle table full"; new_dispatcher->Close(); return MOJO_RESULT_RESOURCE_EXHAUSTED; } return MOJO_RESULT_OK; } MojoResult Core::MapBuffer(MojoHandle buffer_handle, uint64_t offset, uint64_t num_bytes, const MojoMapBufferOptions* options, void** buffer) { scoped_refptr<Dispatcher> dispatcher(GetDispatcher(buffer_handle)); if (!dispatcher) return MOJO_RESULT_INVALID_ARGUMENT; if (options) { if (options->struct_size < sizeof(*options)) return MOJO_RESULT_INVALID_ARGUMENT; if (options->flags != MOJO_MAP_BUFFER_FLAG_NONE) return MOJO_RESULT_UNIMPLEMENTED; } std::unique_ptr<PlatformSharedMemoryMapping> mapping; MojoResult result = dispatcher->MapBuffer(offset, num_bytes, &mapping); if (result != MOJO_RESULT_OK) return result; DCHECK(mapping); void* address = mapping->GetBase(); { base::AutoLock locker(mapping_table_lock_); if (mapping_table_.size() >= GetConfiguration().max_mapping_table_size) return MOJO_RESULT_RESOURCE_EXHAUSTED; auto emplace_result = mapping_table_.emplace(address, std::move(mapping)); DCHECK(emplace_result.second); } *buffer = address; return MOJO_RESULT_OK; } MojoResult Core::UnmapBuffer(void* buffer) { std::unique_ptr<PlatformSharedMemoryMapping> mapping; // Destroy |mapping| while not holding the lock. { base::AutoLock lock(mapping_table_lock_); auto iter = mapping_table_.find(buffer); if (iter == mapping_table_.end()) return MOJO_RESULT_INVALID_ARGUMENT; // Grab a reference so that it gets unmapped outside of this lock. mapping = std::move(iter->second); mapping_table_.erase(iter); } return MOJO_RESULT_OK; } MojoResult Core::GetBufferInfo(MojoHandle buffer_handle, const MojoGetBufferInfoOptions* options, MojoSharedBufferInfo* info) { if (options) { if (options->struct_size < sizeof(*options)) return MOJO_RESULT_INVALID_ARGUMENT; if (options->flags != MOJO_GET_BUFFER_INFO_FLAG_NONE) return MOJO_RESULT_UNIMPLEMENTED; } if (!info || info->struct_size < sizeof(MojoSharedBufferInfo)) return MOJO_RESULT_INVALID_ARGUMENT; scoped_refptr<Dispatcher> dispatcher(GetDispatcher(buffer_handle)); if (!dispatcher) return MOJO_RESULT_INVALID_ARGUMENT; return dispatcher->GetBufferInfo(info); } MojoResult Core::WrapPlatformHandle( const MojoPlatformHandle* platform_handle, const MojoWrapPlatformHandleOptions* options, MojoHandle* mojo_handle) { if (!platform_handle || platform_handle->struct_size < sizeof(*platform_handle)) { return MOJO_RESULT_INVALID_ARGUMENT; } auto handle = PlatformHandle::FromMojoPlatformHandle(platform_handle); MojoHandle h = AddDispatcher(PlatformHandleDispatcher::Create(std::move(handle))); if (h == MOJO_HANDLE_INVALID) return MOJO_RESULT_RESOURCE_EXHAUSTED; *mojo_handle = h; return MOJO_RESULT_OK; } MojoResult Core::UnwrapPlatformHandle( MojoHandle mojo_handle, const MojoUnwrapPlatformHandleOptions* options, MojoPlatformHandle* platform_handle) { if (!platform_handle || platform_handle->struct_size < sizeof(*platform_handle)) { return MOJO_RESULT_INVALID_ARGUMENT; } scoped_refptr<Dispatcher> dispatcher; { base::AutoLock lock(handles_->GetLock()); dispatcher = handles_->GetDispatcher(mojo_handle); if (dispatcher->GetType() != Dispatcher::Type::PLATFORM_HANDLE) return MOJO_RESULT_INVALID_ARGUMENT; MojoResult result = handles_->GetAndRemoveDispatcher(mojo_handle, &dispatcher); if (result != MOJO_RESULT_OK) return result; } PlatformHandleDispatcher* phd = static_cast<PlatformHandleDispatcher*>(dispatcher.get()); PlatformHandle handle = phd->TakePlatformHandle(); phd->Close(); PlatformHandle::ToMojoPlatformHandle(std::move(handle), platform_handle); return MOJO_RESULT_OK; } MojoResult Core::WrapPlatformSharedMemoryRegion( const MojoPlatformHandle* platform_handles, uint32_t num_platform_handles, uint64_t size, const MojoSharedBufferGuid* guid, MojoPlatformSharedMemoryRegionAccessMode access_mode, const MojoWrapPlatformSharedMemoryRegionOptions* options, MojoHandle* mojo_handle) { DCHECK(size); #if defined(OS_POSIX) && !defined(OS_ANDROID) && \ (!defined(OS_MACOSX) || defined(OS_IOS)) if (access_mode == MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_WRITABLE) { if (num_platform_handles != 2) return MOJO_RESULT_INVALID_ARGUMENT; } #else if (num_platform_handles != 1) return MOJO_RESULT_INVALID_ARGUMENT; #endif PlatformHandle handles[2]; bool handles_ok = true; for (size_t i = 0; i < num_platform_handles; ++i) { handles[i] = PlatformHandle::FromMojoPlatformHandle(&platform_handles[i]); if (!handles[i].is_valid()) handles_ok = false; } if (!handles_ok) return MOJO_RESULT_INVALID_ARGUMENT; base::UnguessableToken token = base::UnguessableToken::Deserialize(guid->high, guid->low); base::subtle::PlatformSharedMemoryRegion::Mode mode; switch (access_mode) { case MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_READ_ONLY: mode = base::subtle::PlatformSharedMemoryRegion::Mode::kReadOnly; break; case MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_WRITABLE: mode = base::subtle::PlatformSharedMemoryRegion::Mode::kWritable; break; case MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_UNSAFE: mode = base::subtle::PlatformSharedMemoryRegion::Mode::kUnsafe; break; default: return MOJO_RESULT_INVALID_ARGUMENT; } base::subtle::PlatformSharedMemoryRegion region = base::subtle::PlatformSharedMemoryRegion::Take( CreateSharedMemoryRegionHandleFromPlatformHandles( std::move(handles[0]), std::move(handles[1])), mode, size, token); if (!region.IsValid()) return MOJO_RESULT_UNKNOWN; scoped_refptr<SharedBufferDispatcher> dispatcher; MojoResult result = SharedBufferDispatcher::CreateFromPlatformSharedMemoryRegion( std::move(region), &dispatcher); if (result != MOJO_RESULT_OK) return result; MojoHandle h = AddDispatcher(dispatcher); if (h == MOJO_HANDLE_INVALID) { dispatcher->Close(); return MOJO_RESULT_RESOURCE_EXHAUSTED; } *mojo_handle = h; return MOJO_RESULT_OK; } MojoResult Core::UnwrapPlatformSharedMemoryRegion( MojoHandle mojo_handle, const MojoUnwrapPlatformSharedMemoryRegionOptions* options, MojoPlatformHandle* platform_handles, uint32_t* num_platform_handles, uint64_t* size, MojoSharedBufferGuid* guid, MojoPlatformSharedMemoryRegionAccessMode* access_mode) { scoped_refptr<Dispatcher> dispatcher; MojoResult result = MOJO_RESULT_OK; { base::AutoLock lock(handles_->GetLock()); result = handles_->GetAndRemoveDispatcher(mojo_handle, &dispatcher); if (result != MOJO_RESULT_OK) return result; } if (dispatcher->GetType() != Dispatcher::Type::SHARED_BUFFER) { dispatcher->Close(); return MOJO_RESULT_INVALID_ARGUMENT; } SharedBufferDispatcher* shm_dispatcher = static_cast<SharedBufferDispatcher*>(dispatcher.get()); base::subtle::PlatformSharedMemoryRegion region = shm_dispatcher->PassPlatformSharedMemoryRegion(); DCHECK(region.IsValid()); DCHECK(size); *size = region.GetSize(); base::UnguessableToken token = region.GetGUID(); guid->high = token.GetHighForSerialization(); guid->low = token.GetLowForSerialization(); DCHECK(access_mode); switch (region.GetMode()) { case base::subtle::PlatformSharedMemoryRegion::Mode::kReadOnly: *access_mode = MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_READ_ONLY; break; case base::subtle::PlatformSharedMemoryRegion::Mode::kWritable: *access_mode = MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_WRITABLE; break; case base::subtle::PlatformSharedMemoryRegion::Mode::kUnsafe: *access_mode = MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_UNSAFE; break; default: return MOJO_RESULT_INVALID_ARGUMENT; } PlatformHandle handle; PlatformHandle read_only_handle; ExtractPlatformHandlesFromSharedMemoryRegionHandle( region.PassPlatformHandle(), &handle, &read_only_handle); const uint32_t available_handle_storage_slots = *num_platform_handles; if (available_handle_storage_slots < 1) return MOJO_RESULT_RESOURCE_EXHAUSTED; *num_platform_handles = 1; #if defined(OS_POSIX) && !defined(OS_ANDROID) && \ (!defined(OS_MACOSX) || defined(OS_IOS)) if (region.GetMode() == base::subtle::PlatformSharedMemoryRegion::Mode::kWritable) { if (available_handle_storage_slots < 2) return MOJO_RESULT_INVALID_ARGUMENT; PlatformHandle::ToMojoPlatformHandle(std::move(read_only_handle), &platform_handles[1]); if (platform_handles[1].type == MOJO_PLATFORM_HANDLE_TYPE_INVALID) return MOJO_RESULT_INVALID_ARGUMENT; *num_platform_handles = 2; } #endif PlatformHandle::ToMojoPlatformHandle(std::move(handle), &platform_handles[0]); if (platform_handles[0].type == MOJO_PLATFORM_HANDLE_TYPE_INVALID) return MOJO_RESULT_INVALID_ARGUMENT; return MOJO_RESULT_OK; } MojoResult Core::CreateInvitation(const MojoCreateInvitationOptions* options, MojoHandle* invitation_handle) { if (options && options->struct_size < sizeof(*options)) return MOJO_RESULT_INVALID_ARGUMENT; if (!invitation_handle) return MOJO_RESULT_INVALID_ARGUMENT; *invitation_handle = AddDispatcher(new InvitationDispatcher); if (*invitation_handle == MOJO_HANDLE_INVALID) return MOJO_RESULT_RESOURCE_EXHAUSTED; return MOJO_RESULT_OK; } MojoResult Core::AttachMessagePipeToInvitation( MojoHandle invitation_handle, const void* name, uint32_t name_num_bytes, const MojoAttachMessagePipeToInvitationOptions* options, MojoHandle* message_pipe_handle) { if (options && options->struct_size < sizeof(*options)) return MOJO_RESULT_INVALID_ARGUMENT; if (!message_pipe_handle) return MOJO_RESULT_INVALID_ARGUMENT; if (name_num_bytes == 0) return MOJO_RESULT_INVALID_ARGUMENT; scoped_refptr<Dispatcher> dispatcher = GetDispatcher(invitation_handle); if (!dispatcher || dispatcher->GetType() != Dispatcher::Type::INVITATION) return MOJO_RESULT_INVALID_ARGUMENT; auto* invitation_dispatcher = static_cast<InvitationDispatcher*>(dispatcher.get()); RequestContext request_context; ports::PortRef remote_peer_port; MojoHandle local_handle = CreatePartialMessagePipe(&remote_peer_port); if (local_handle == MOJO_HANDLE_INVALID) return MOJO_RESULT_RESOURCE_EXHAUSTED; MojoResult result = invitation_dispatcher->AttachMessagePipe( base::StringPiece(static_cast<const char*>(name), name_num_bytes), std::move(remote_peer_port)); if (result != MOJO_RESULT_OK) { Close(local_handle); return result; } *message_pipe_handle = local_handle; return MOJO_RESULT_OK; } MojoResult Core::ExtractMessagePipeFromInvitation( MojoHandle invitation_handle, const void* name, uint32_t name_num_bytes, const MojoExtractMessagePipeFromInvitationOptions* options, MojoHandle* message_pipe_handle) { if (options && options->struct_size < sizeof(*options)) return MOJO_RESULT_INVALID_ARGUMENT; if (!message_pipe_handle) return MOJO_RESULT_INVALID_ARGUMENT; if (name_num_bytes == 0) return MOJO_RESULT_INVALID_ARGUMENT; RequestContext request_context; base::StringPiece name_string(static_cast<const char*>(name), name_num_bytes); scoped_refptr<Dispatcher> dispatcher = GetDispatcher(invitation_handle); if (!dispatcher || dispatcher->GetType() != Dispatcher::Type::INVITATION) return MOJO_RESULT_INVALID_ARGUMENT; auto* invitation_dispatcher = static_cast<InvitationDispatcher*>(dispatcher.get()); // First attempt to extract from the invitation object itself. This is for // cases where this invitation was created in-process or is an accepted // isolated invitation. MojoResult extract_result = invitation_dispatcher->ExtractMessagePipe( name_string, message_pipe_handle); if (extract_result == MOJO_RESULT_OK || extract_result == MOJO_RESULT_RESOURCE_EXHAUSTED) { return extract_result; } *message_pipe_handle = ExtractMessagePipeFromInvitation(name_string.as_string()); if (*message_pipe_handle == MOJO_HANDLE_INVALID) return MOJO_RESULT_RESOURCE_EXHAUSTED; return MOJO_RESULT_OK; } MojoResult Core::SendInvitation( MojoHandle invitation_handle, const MojoPlatformProcessHandle* process_handle, const MojoInvitationTransportEndpoint* transport_endpoint, MojoProcessErrorHandler error_handler, uintptr_t error_handler_context, const MojoSendInvitationOptions* options) { if (options && options->struct_size < sizeof(*options)) return MOJO_RESULT_INVALID_ARGUMENT; base::ProcessHandle target_process = base::kNullProcessHandle; if (process_handle) { if (process_handle->struct_size < sizeof(*process_handle)) return MOJO_RESULT_INVALID_ARGUMENT; #if defined(OS_WIN) target_process = reinterpret_cast<base::ProcessHandle>( static_cast<uintptr_t>(process_handle->value)); #else target_process = static_cast<base::ProcessHandle>(process_handle->value); #endif } ProcessErrorCallback process_error_callback; if (error_handler) { auto error_handler_task_runner = GetNodeController()->io_task_runner(); process_error_callback = base::BindRepeating( &RunMojoProcessErrorHandler, base::Owned(new ProcessDisconnectHandler( error_handler_task_runner, error_handler, error_handler_context)), error_handler_task_runner, error_handler, error_handler_context); } else if (default_process_error_callback_) { process_error_callback = default_process_error_callback_; } if (!transport_endpoint) return MOJO_RESULT_INVALID_ARGUMENT; if (transport_endpoint->struct_size < sizeof(*transport_endpoint)) return MOJO_RESULT_INVALID_ARGUMENT; if (transport_endpoint->num_platform_handles == 0) return MOJO_RESULT_INVALID_ARGUMENT; if (!transport_endpoint->platform_handles) return MOJO_RESULT_INVALID_ARGUMENT; if (transport_endpoint->type != MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL && transport_endpoint->type != MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL_SERVER) { return MOJO_RESULT_UNIMPLEMENTED; } scoped_refptr<Dispatcher> dispatcher = GetDispatcher(invitation_handle); if (!dispatcher || dispatcher->GetType() != Dispatcher::Type::INVITATION) return MOJO_RESULT_INVALID_ARGUMENT; auto* invitation_dispatcher = static_cast<InvitationDispatcher*>(dispatcher.get()); auto endpoint = PlatformHandle::FromMojoPlatformHandle( &transport_endpoint->platform_handles[0]); if (!endpoint.is_valid()) return MOJO_RESULT_INVALID_ARGUMENT; ConnectionParams connection_params; #if defined(OS_WIN) || defined(OS_POSIX) if (transport_endpoint->type == MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL_SERVER) { connection_params = ConnectionParams(PlatformChannelServerEndpoint(std::move(endpoint))); } #endif if (!connection_params.server_endpoint().is_valid()) { connection_params = ConnectionParams(PlatformChannelEndpoint(std::move(endpoint))); } // At this point everything else has been validated, so we can take ownership // of the dispatcher. { base::AutoLock lock(handles_->GetLock()); scoped_refptr<Dispatcher> removed_dispatcher; MojoResult result = handles_->GetAndRemoveDispatcher(invitation_handle, &removed_dispatcher); if (result != MOJO_RESULT_OK) { // Release ownership of the endpoint platform handle, per the API // contract. The caller retains ownership on failure. connection_params.TakeEndpoint().TakePlatformHandle().release(); connection_params.TakeServerEndpoint().TakePlatformHandle().release(); return result; } DCHECK_EQ(removed_dispatcher.get(), invitation_dispatcher); } std::vector<std::pair<std::string, ports::PortRef>> attached_ports; InvitationDispatcher::PortMapping attached_port_map = invitation_dispatcher->TakeAttachedPorts(); invitation_dispatcher->Close(); for (auto& entry : attached_port_map) attached_ports.emplace_back(entry.first, std::move(entry.second)); bool is_isolated = options && (options->flags & MOJO_SEND_INVITATION_FLAG_ISOLATED); RequestContext request_context; if (is_isolated) { DCHECK_EQ(attached_ports.size(), 1u); DCHECK_EQ(attached_ports[0].first, kIsolatedInvitationPipeName); base::StringPiece connection_name(options->isolated_connection_name, options->isolated_connection_name_length); GetNodeController()->ConnectIsolated(std::move(connection_params), attached_ports[0].second, connection_name); } else { GetNodeController()->SendBrokerClientInvitation( target_process, std::move(connection_params), attached_ports, process_error_callback); } return MOJO_RESULT_OK; } MojoResult Core::AcceptInvitation( const MojoInvitationTransportEndpoint* transport_endpoint, const MojoAcceptInvitationOptions* options, MojoHandle* invitation_handle) { if (options && options->struct_size < sizeof(*options)) return MOJO_RESULT_INVALID_ARGUMENT; if (!transport_endpoint) return MOJO_RESULT_INVALID_ARGUMENT; if (transport_endpoint->struct_size < sizeof(*transport_endpoint)) return MOJO_RESULT_INVALID_ARGUMENT; if (transport_endpoint->num_platform_handles == 0) return MOJO_RESULT_INVALID_ARGUMENT; if (!transport_endpoint->platform_handles) return MOJO_RESULT_INVALID_ARGUMENT; if (transport_endpoint->type != MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL && transport_endpoint->type != MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL_SERVER) { return MOJO_RESULT_UNIMPLEMENTED; } if (!invitation_handle) return MOJO_RESULT_INVALID_ARGUMENT; auto dispatcher = base::MakeRefCounted<InvitationDispatcher>(); *invitation_handle = AddDispatcher(dispatcher); if (*invitation_handle == MOJO_HANDLE_INVALID) return MOJO_RESULT_RESOURCE_EXHAUSTED; auto endpoint = PlatformHandle::FromMojoPlatformHandle( &transport_endpoint->platform_handles[0]); if (!endpoint.is_valid()) { Close(*invitation_handle); *invitation_handle = MOJO_HANDLE_INVALID; return MOJO_RESULT_INVALID_ARGUMENT; } ConnectionParams connection_params; #if defined(OS_WIN) || defined(OS_POSIX) if (transport_endpoint->type == MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL_SERVER) { connection_params = ConnectionParams(PlatformChannelServerEndpoint(std::move(endpoint))); } #endif if (!connection_params.server_endpoint().is_valid()) { connection_params = ConnectionParams(PlatformChannelEndpoint(std::move(endpoint))); } bool is_isolated = options && (options->flags & MOJO_ACCEPT_INVITATION_FLAG_ISOLATED); NodeController* const node_controller = GetNodeController(); RequestContext request_context; if (is_isolated) { // For an isolated invitation, we simply mint a new port pair here and send // one name to the remote endpoint while stashing the other in the accepted // invitation object for later extraction. ports::PortRef local_port; ports::PortRef remote_port; node_controller->node()->CreatePortPair(&local_port, &remote_port); node_controller->ConnectIsolated(std::move(connection_params), remote_port, base::StringPiece()); MojoResult result = dispatcher->AttachMessagePipe(kIsolatedInvitationPipeName, local_port); DCHECK_EQ(MOJO_RESULT_OK, result); } else { node_controller->AcceptBrokerClientInvitation(std::move(connection_params)); } return MOJO_RESULT_OK; } MojoResult Core::SetQuota(MojoHandle handle, MojoQuotaType type, uint64_t limit, const MojoSetQuotaOptions* options) { RequestContext request_context; if (options && options->struct_size < sizeof(*options)) return MOJO_RESULT_INVALID_ARGUMENT; auto dispatcher = GetDispatcher(handle); if (!dispatcher) return MOJO_RESULT_INVALID_ARGUMENT; return dispatcher->SetQuota(type, limit); } MojoResult Core::QueryQuota(MojoHandle handle, MojoQuotaType type, const MojoQueryQuotaOptions* options, uint64_t* limit, uint64_t* usage) { RequestContext request_context; if (options && options->struct_size < sizeof(*options)) return MOJO_RESULT_INVALID_ARGUMENT; auto dispatcher = GetDispatcher(handle); if (!dispatcher) return MOJO_RESULT_INVALID_ARGUMENT; return dispatcher->QueryQuota(type, limit, usage); } void Core::GetActiveHandlesForTest(std::vector<MojoHandle>* handles) { base::AutoLock lock(handles_->GetLock()); handles_->GetActiveHandlesForTest(handles); } // static void Core::PassNodeControllerToIOThread( std::unique_ptr<NodeController> node_controller) { // It's OK to leak this reference. At this point we know the IO loop is still // running, and we know the NodeController will observe its eventual // destruction. This tells the NodeController to delete itself when that // happens. node_controller.release()->DestroyOnIOThreadShutdown(); } } // namespace core } // namespace mojo