12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538 |
- // 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 <memory>
- #include <utility>
- #include "base/bind.h"
- #include "base/containers/stack_container.h"
- #include "base/location.h"
- #include "base/logging.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 "base/trace_event/trace_id_helper.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"
- #include "mojo/public/cpp/bindings/mojo_buildflags.h"
- #include "mojo/public/cpp/platform/platform_handle_internal.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};
- // Set according to the field trial "MojoAvoidRandomPipeId".
- bool g_avoid_random_pipe_id;
- void InvokeProcessErrorCallback(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);
- }
- // 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(MojoProcessErrorHandler handler, uintptr_t context)
- : handler_(handler), context_(context) {}
- ProcessDisconnectHandler(const ProcessDisconnectHandler&) = delete;
- ProcessDisconnectHandler& operator=(const ProcessDisconnectHandler&) = delete;
- ~ProcessDisconnectHandler() {
- InvokeProcessErrorCallback(handler_, context_, std::string(),
- MOJO_PROCESS_ERROR_FLAG_DISCONNECTED);
- }
- private:
- const MojoProcessErrorHandler handler_;
- const uintptr_t context_;
- };
- void RunMojoProcessErrorHandler(
- ProcessDisconnectHandler* disconnect_handler,
- MojoProcessErrorHandler handler,
- uintptr_t context,
- const std::string& error) {
- InvokeProcessErrorCallback(handler, context, error,
- MOJO_PROCESS_ERROR_FLAG_NONE);
- }
- uint64_t MakePipeId() {
- #if BUILDFLAG(MOJO_TRACE_ENABLED)
- return base::trace_event::GetNextGlobalTraceId();
- #else
- if (g_avoid_random_pipe_id)
- return 0;
- return base::RandUint64();
- #endif
- }
- } // namespace
- Core::Core() {
- handles_ = std::make_unique<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.
- auto io_task_runner = node_controller_->io_task_runner();
- io_task_runner->PostTask(FROM_HERE,
- base::BindOnce(&Core::PassNodeControllerToIOThread,
- std::move(node_controller_)));
- }
- base::trace_event::MemoryDumpManager::GetInstance()
- ->UnregisterAndDeleteDumpProviderSoon(std::move(handles_));
- }
- void Core::SetIOTaskRunner(
- scoped_refptr<base::SingleThreadTaskRunner> io_task_runner) {
- GetNodeController()->SetIOTaskRunner(std::move(io_task_runner));
- }
- NodeController* Core::GetNodeController() {
- base::AutoLock lock(node_controller_lock_);
- if (!node_controller_)
- node_controller_ = std::make_unique<NodeController>();
- 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;
- }
- 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::Process 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(
- std::move(target_process), std::move(connection_params), attached_ports,
- process_error_callback);
- }
- 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);
- }
- 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(base::OnceClosure callback) {
- GetNodeController()->RequestShutdown(std::move(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;
- const MojoCreateMessageFlags flags =
- options ? options->flags : MOJO_CREATE_MESSAGE_FLAG_NONE;
- *message_handle = reinterpret_cast<MojoMessageHandle>(
- UserMessageImpl::CreateEventForNewMessage(flags).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))
- 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;
- Dispatcher::SetExtractingHandlesFromMessage(true);
- MojoResult result = message->ExtractSerializedHandles(
- UserMessageImpl::ExtractBadHandlePolicy::kAbort, handles);
- Dispatcher::SetExtractingHandlesFromMessage(false);
- return result;
- }
- 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 = MakePipeId();
- *message_pipe_handle0 = AddDispatcher(new MessagePipeDispatcher(
- GetNodeController(), port0, pipe_id, /*endpoint=*/0));
- if (*message_pipe_handle0 == MOJO_HANDLE_INVALID)
- return MOJO_RESULT_RESOURCE_EXHAUSTED;
- *message_pipe_handle1 = AddDispatcher(new MessagePipeDispatcher(
- GetNodeController(), port1, pipe_id, /*endpoint=*/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>();
- NodeController* node_controller = GetNodeController();
- if (!node_controller->HasBadMessageHandler(message->source_node())) {
- 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;
- }
- node_controller->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 BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_APPLE)
- // 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 = MakePipeId();
- 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 ||
- 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 BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_MAC)
- 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 =
- mojo::internal::PlatformHandleInternal::UnmarshalUnguessableToken(guid);
- 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();
- *guid = mojo::internal::PlatformHandleInternal::MarshalUnguessableToken(
- region.GetGUID());
- 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 BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_MAC)
- 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(std::string(name_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::Process target_process;
- if (process_handle) {
- MojoResult result =
- UnwrapAndClonePlatformProcessHandle(process_handle, target_process);
- if (result != MOJO_RESULT_OK)
- return result;
- }
- ProcessErrorCallback process_error_callback;
- if (error_handler) {
- process_error_callback =
- base::BindRepeating(&RunMojoProcessErrorHandler,
- base::Owned(new ProcessDisconnectHandler(
- error_handler, error_handler_context)),
- 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 &&
- transport_endpoint->type !=
- MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL_ASYNC) {
- 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 BUILDFLAG(IS_WIN) || BUILDFLAG(IS_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));
- connection_params.set_is_untrusted_process(
- options &&
- (options->flags & MOJO_SEND_INVITATION_FLAG_UNTRUSTED_PROCESS));
- 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 {
- if (transport_endpoint->type ==
- MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL_ASYNC) {
- connection_params.set_is_async(true);
- }
- GetNodeController()->SendBrokerClientInvitation(
- std::move(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 &&
- transport_endpoint->type !=
- MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL_ASYNC) {
- 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 BUILDFLAG(IS_WIN) || BUILDFLAG(IS_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)));
- }
- if (options &&
- options->flags & MOJO_ACCEPT_INVITATION_FLAG_LEAK_TRANSPORT_ENDPOINT) {
- connection_params.set_leak_endpoint(true);
- }
- 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 {
- if (transport_endpoint->type ==
- MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL_ASYNC) {
- connection_params.set_is_async(true);
- }
- 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);
- }
- MojoResult Core::SetDefaultProcessErrorHandler(
- MojoDefaultProcessErrorHandler handler,
- const MojoSetDefaultProcessErrorHandlerOptions* options) {
- if (default_process_error_callback_ && handler)
- return MOJO_RESULT_ALREADY_EXISTS;
- if (!handler) {
- default_process_error_callback_.Reset();
- return MOJO_RESULT_OK;
- }
- default_process_error_callback_ = base::BindRepeating(
- [](MojoDefaultProcessErrorHandler handler, const std::string& error) {
- MojoProcessErrorDetails details = {0};
- details.struct_size = sizeof(details);
- details.error_message_length = static_cast<uint32_t>(error.size());
- details.error_message = error.c_str();
- handler(&details);
- },
- handler);
- return MOJO_RESULT_OK;
- }
- void Core::GetActiveHandlesForTest(std::vector<MojoHandle>* handles) {
- base::AutoLock lock(handles_->GetLock());
- handles_->GetActiveHandlesForTest(handles);
- }
- // static
- void Core::set_avoid_random_pipe_id(bool avoid_random_pipe_id) {
- g_avoid_random_pipe_id = avoid_random_pipe_id;
- }
- // 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
|