Home | History | Annotate | Download | only in core
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "mojo/core/core.h"
      6 
      7 #include <string.h>
      8 
      9 #include <algorithm>
     10 #include <utility>
     11 
     12 #include "base/bind.h"
     13 #include "base/containers/stack_container.h"
     14 #include "base/location.h"
     15 #include "base/logging.h"
     16 #include "base/macros.h"
     17 #include "base/memory/ptr_util.h"
     18 #include "base/memory/writable_shared_memory_region.h"
     19 #include "base/rand_util.h"
     20 #include "base/strings/string_number_conversions.h"
     21 #include "base/strings/string_piece.h"
     22 #include "base/threading/thread_task_runner_handle.h"
     23 #include "base/time/time.h"
     24 // #include "base/trace_event/memory_dump_manager.h"
     25 #include "build/build_config.h"
     26 #include "mojo/core/channel.h"
     27 #include "mojo/core/configuration.h"
     28 #include "mojo/core/data_pipe_consumer_dispatcher.h"
     29 #include "mojo/core/data_pipe_producer_dispatcher.h"
     30 #include "mojo/core/embedder/process_error_callback.h"
     31 #include "mojo/core/handle_signals_state.h"
     32 #include "mojo/core/invitation_dispatcher.h"
     33 #include "mojo/core/message_pipe_dispatcher.h"
     34 #include "mojo/core/platform_handle_dispatcher.h"
     35 #include "mojo/core/platform_handle_utils.h"
     36 #include "mojo/core/platform_shared_memory_mapping.h"
     37 #include "mojo/core/ports/event.h"
     38 #include "mojo/core/ports/name.h"
     39 #include "mojo/core/ports/node.h"
     40 #include "mojo/core/request_context.h"
     41 #include "mojo/core/shared_buffer_dispatcher.h"
     42 #include "mojo/core/user_message_impl.h"
     43 #include "mojo/core/watcher_dispatcher.h"
     44 
     45 namespace mojo {
     46 namespace core {
     47 
     48 namespace {
     49 
     50 // This is an unnecessarily large limit that is relatively easy to enforce.
     51 const uint32_t kMaxHandlesPerMessage = 1024 * 1024;
     52 
     53 // TODO(rockot): Maybe we could negotiate a debugging pipe ID for cross-process
     54 // pipes too; for now we just use a constant. This only affects bootstrap pipes.
     55 const uint64_t kUnknownPipeIdForDebug = 0x7f7f7f7f7f7f7f7fUL;
     56 
     57 // The pipe name which must be used for the sole pipe attachment on any isolated
     58 // invitation.
     59 constexpr base::StringPiece kIsolatedInvitationPipeName = {"\0\0\0\0", 4};
     60 
     61 void InvokeProcessErrorCallbackOnTaskRunner(
     62     scoped_refptr<base::TaskRunner> task_runner,
     63     MojoProcessErrorHandler handler,
     64     uintptr_t context,
     65     const std::string& error,
     66     MojoProcessErrorFlags flags) {
     67   // We always run the handler asynchronously to ensure no Mojo core reentrancy.
     68   task_runner->PostTask(
     69       FROM_HERE,
     70       base::BindOnce(
     71           [](MojoProcessErrorHandler handler, uintptr_t context,
     72              const std::string& error, MojoProcessErrorFlags flags) {
     73             MojoProcessErrorDetails details;
     74             details.struct_size = sizeof(details);
     75             DCHECK(base::IsValueInRangeForNumericType<uint32_t>(error.size()));
     76             details.error_message_length = static_cast<uint32_t>(error.size());
     77             if (!error.empty())
     78               details.error_message = error.data();
     79             else
     80               details.error_message = nullptr;
     81             details.flags = flags;
     82             handler(context, &details);
     83           },
     84           handler, context, error, flags));
     85 }
     86 
     87 // Helper class which is bound to the lifetime of a
     88 // ProcessErrorCallback generated by the |MojoSendInvitation()|
     89 // API. When the last reference to the error callback is lost within the EDK,
     90 // which will happen shortly after a connection to the process is lost, that
     91 // obviously guarantees that no more invocations of the callback will occur. At
     92 // that point, the corresponding instance of this object (owned by the callback
     93 // -- see Core::SendInvitation) will be destroyed.
     94 class ProcessDisconnectHandler {
     95  public:
     96   ProcessDisconnectHandler(scoped_refptr<base::TaskRunner> task_runner,
     97                            MojoProcessErrorHandler handler,
     98                            uintptr_t context)
     99       : task_runner_(std::move(task_runner)),
    100         handler_(handler),
    101         context_(context) {}
    102 
    103   ~ProcessDisconnectHandler() {
    104     InvokeProcessErrorCallbackOnTaskRunner(
    105         task_runner_, handler_, context_, std::string(),
    106         MOJO_PROCESS_ERROR_FLAG_DISCONNECTED);
    107   }
    108 
    109  private:
    110   const scoped_refptr<base::TaskRunner> task_runner_;
    111   const MojoProcessErrorHandler handler_;
    112   const uintptr_t context_;
    113 
    114   DISALLOW_COPY_AND_ASSIGN(ProcessDisconnectHandler);
    115 };
    116 
    117 void RunMojoProcessErrorHandler(ProcessDisconnectHandler* disconnect_handler,
    118                                 scoped_refptr<base::TaskRunner> task_runner,
    119                                 MojoProcessErrorHandler handler,
    120                                 uintptr_t context,
    121                                 const std::string& error) {
    122   InvokeProcessErrorCallbackOnTaskRunner(task_runner, handler, context, error,
    123                                          MOJO_PROCESS_ERROR_FLAG_NONE);
    124 }
    125 
    126 }  // namespace
    127 
    128 Core::Core() {
    129   handles_.reset(new HandleTable);
    130   // base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
    131   //     handles_.get(), "MojoHandleTable", nullptr);
    132 }
    133 
    134 Core::~Core() {
    135   if (node_controller_ && node_controller_->io_task_runner()) {
    136     // If this races with IO thread shutdown the callback will be dropped and
    137     // the NodeController will be shutdown on this thread anyway, which is also
    138     // just fine.
    139     scoped_refptr<base::TaskRunner> io_task_runner =
    140         node_controller_->io_task_runner();
    141     io_task_runner->PostTask(FROM_HERE,
    142                              base::BindOnce(&Core::PassNodeControllerToIOThread,
    143                                             base::Passed(&node_controller_)));
    144   }
    145   // base::trace_event::MemoryDumpManager::GetInstance()
    146   //     ->UnregisterAndDeleteDumpProviderSoon(std::move(handles_));
    147 }
    148 
    149 void Core::SetIOTaskRunner(scoped_refptr<base::TaskRunner> io_task_runner) {
    150   GetNodeController()->SetIOTaskRunner(io_task_runner);
    151 }
    152 
    153 NodeController* Core::GetNodeController() {
    154   base::AutoLock lock(node_controller_lock_);
    155   if (!node_controller_)
    156     node_controller_.reset(new NodeController(this));
    157   return node_controller_.get();
    158 }
    159 
    160 scoped_refptr<Dispatcher> Core::GetDispatcher(MojoHandle handle) {
    161   base::AutoLock lock(handles_->GetLock());
    162   return handles_->GetDispatcher(handle);
    163 }
    164 
    165 scoped_refptr<Dispatcher> Core::GetAndRemoveDispatcher(MojoHandle handle) {
    166   scoped_refptr<Dispatcher> dispatcher;
    167   base::AutoLock lock(handles_->GetLock());
    168   handles_->GetAndRemoveDispatcher(handle, &dispatcher);
    169   return dispatcher;
    170 }
    171 
    172 void Core::SetDefaultProcessErrorCallback(
    173     const ProcessErrorCallback& callback) {
    174   default_process_error_callback_ = callback;
    175 }
    176 
    177 MojoHandle Core::CreatePartialMessagePipe(ports::PortRef* peer) {
    178   RequestContext request_context;
    179   ports::PortRef local_port;
    180   GetNodeController()->node()->CreatePortPair(&local_port, peer);
    181   return AddDispatcher(new MessagePipeDispatcher(
    182       GetNodeController(), local_port, kUnknownPipeIdForDebug, 0));
    183 }
    184 
    185 MojoHandle Core::CreatePartialMessagePipe(const ports::PortRef& port) {
    186   RequestContext request_context;
    187   return AddDispatcher(new MessagePipeDispatcher(GetNodeController(), port,
    188                                                  kUnknownPipeIdForDebug, 1));
    189 }
    190 
    191 void Core::SendBrokerClientInvitation(
    192     base::ProcessHandle target_process,
    193     ConnectionParams connection_params,
    194     const std::vector<std::pair<std::string, ports::PortRef>>& attached_ports,
    195     const ProcessErrorCallback& process_error_callback) {
    196   RequestContext request_context;
    197   GetNodeController()->SendBrokerClientInvitation(
    198       target_process, std::move(connection_params), attached_ports,
    199       process_error_callback);
    200 }
    201 
    202 void Core::AcceptBrokerClientInvitation(ConnectionParams connection_params) {
    203   RequestContext request_context;
    204   GetNodeController()->AcceptBrokerClientInvitation(
    205       std::move(connection_params));
    206 }
    207 
    208 void Core::ConnectIsolated(ConnectionParams connection_params,
    209                            const ports::PortRef& port,
    210                            base::StringPiece connection_name) {
    211   RequestContext request_context;
    212   GetNodeController()->ConnectIsolated(std::move(connection_params), port,
    213                                        connection_name);
    214 }
    215 
    216 void Core::SetMachPortProvider(base::PortProvider* port_provider) {
    217 #if defined(OS_MACOSX) && !defined(OS_IOS)
    218   GetNodeController()->CreateMachPortRelay(port_provider);
    219 #endif
    220 }
    221 
    222 #if defined(OS_MACOSX) && !defined(OS_IOS)
    223 MachPortRelay* Core::GetMachPortRelay() {
    224   return GetNodeController()->GetMachPortRelay();
    225 }
    226 #endif
    227 
    228 MojoHandle Core::AddDispatcher(scoped_refptr<Dispatcher> dispatcher) {
    229   base::AutoLock lock(handles_->GetLock());
    230   return handles_->AddDispatcher(dispatcher);
    231 }
    232 
    233 bool Core::AddDispatchersFromTransit(
    234     const std::vector<Dispatcher::DispatcherInTransit>& dispatchers,
    235     MojoHandle* handles) {
    236   bool failed = false;
    237   {
    238     base::AutoLock lock(handles_->GetLock());
    239     if (!handles_->AddDispatchersFromTransit(dispatchers, handles))
    240       failed = true;
    241   }
    242   if (failed) {
    243     for (auto d : dispatchers) {
    244       if (d.dispatcher)
    245         d.dispatcher->Close();
    246     }
    247     return false;
    248   }
    249   return true;
    250 }
    251 
    252 MojoResult Core::AcquireDispatchersForTransit(
    253     const MojoHandle* handles,
    254     size_t num_handles,
    255     std::vector<Dispatcher::DispatcherInTransit>* dispatchers) {
    256   base::AutoLock lock(handles_->GetLock());
    257   MojoResult rv = handles_->BeginTransit(handles, num_handles, dispatchers);
    258   if (rv != MOJO_RESULT_OK)
    259     handles_->CancelTransit(*dispatchers);
    260   return rv;
    261 }
    262 
    263 void Core::ReleaseDispatchersForTransit(
    264     const std::vector<Dispatcher::DispatcherInTransit>& dispatchers,
    265     bool in_transit) {
    266   base::AutoLock lock(handles_->GetLock());
    267   if (in_transit)
    268     handles_->CompleteTransitAndClose(dispatchers);
    269   else
    270     handles_->CancelTransit(dispatchers);
    271 }
    272 
    273 void Core::RequestShutdown(const base::Closure& callback) {
    274   GetNodeController()->RequestShutdown(callback);
    275 }
    276 
    277 MojoHandle Core::ExtractMessagePipeFromInvitation(const std::string& name) {
    278   RequestContext request_context;
    279   ports::PortRef port0, port1;
    280   GetNodeController()->node()->CreatePortPair(&port0, &port1);
    281   MojoHandle handle = AddDispatcher(new MessagePipeDispatcher(
    282       GetNodeController(), port0, kUnknownPipeIdForDebug, 1));
    283   GetNodeController()->MergePortIntoInviter(name, port1);
    284   return handle;
    285 }
    286 
    287 MojoTimeTicks Core::GetTimeTicksNow() {
    288   return base::TimeTicks::Now().ToInternalValue();
    289 }
    290 
    291 MojoResult Core::Close(MojoHandle handle) {
    292   RequestContext request_context;
    293   scoped_refptr<Dispatcher> dispatcher;
    294   {
    295     base::AutoLock lock(handles_->GetLock());
    296     MojoResult rv = handles_->GetAndRemoveDispatcher(handle, &dispatcher);
    297     if (rv != MOJO_RESULT_OK)
    298       return rv;
    299   }
    300   dispatcher->Close();
    301   return MOJO_RESULT_OK;
    302 }
    303 
    304 MojoResult Core::QueryHandleSignalsState(
    305     MojoHandle handle,
    306     MojoHandleSignalsState* signals_state) {
    307   RequestContext request_context;
    308   scoped_refptr<Dispatcher> dispatcher = GetDispatcher(handle);
    309   if (!dispatcher || !signals_state)
    310     return MOJO_RESULT_INVALID_ARGUMENT;
    311   *signals_state = dispatcher->GetHandleSignalsState();
    312   return MOJO_RESULT_OK;
    313 }
    314 
    315 MojoResult Core::CreateTrap(MojoTrapEventHandler handler,
    316                             const MojoCreateTrapOptions* options,
    317                             MojoHandle* trap_handle) {
    318   if (options && options->struct_size < sizeof(*options))
    319     return MOJO_RESULT_INVALID_ARGUMENT;
    320 
    321   RequestContext request_context;
    322   if (!trap_handle)
    323     return MOJO_RESULT_INVALID_ARGUMENT;
    324   *trap_handle = AddDispatcher(new WatcherDispatcher(handler));
    325   if (*trap_handle == MOJO_HANDLE_INVALID)
    326     return MOJO_RESULT_RESOURCE_EXHAUSTED;
    327   return MOJO_RESULT_OK;
    328 }
    329 
    330 MojoResult Core::AddTrigger(MojoHandle trap_handle,
    331                             MojoHandle handle,
    332                             MojoHandleSignals signals,
    333                             MojoTriggerCondition condition,
    334                             uintptr_t context,
    335                             const MojoAddTriggerOptions* options) {
    336   if (options && options->struct_size < sizeof(*options))
    337     return MOJO_RESULT_INVALID_ARGUMENT;
    338 
    339   RequestContext request_context;
    340   scoped_refptr<Dispatcher> watcher = GetDispatcher(trap_handle);
    341   if (!watcher || watcher->GetType() != Dispatcher::Type::WATCHER)
    342     return MOJO_RESULT_INVALID_ARGUMENT;
    343 
    344   scoped_refptr<Dispatcher> dispatcher = GetDispatcher(handle);
    345   if (!dispatcher)
    346     return MOJO_RESULT_INVALID_ARGUMENT;
    347 
    348   return watcher->WatchDispatcher(std::move(dispatcher), signals, condition,
    349                                   context);
    350 }
    351 
    352 MojoResult Core::RemoveTrigger(MojoHandle trap_handle,
    353                                uintptr_t context,
    354                                const MojoRemoveTriggerOptions* options) {
    355   if (options && options->struct_size < sizeof(*options))
    356     return MOJO_RESULT_INVALID_ARGUMENT;
    357 
    358   RequestContext request_context;
    359   scoped_refptr<Dispatcher> watcher = GetDispatcher(trap_handle);
    360   if (!watcher || watcher->GetType() != Dispatcher::Type::WATCHER)
    361     return MOJO_RESULT_INVALID_ARGUMENT;
    362   return watcher->CancelWatch(context);
    363 }
    364 
    365 MojoResult Core::ArmTrap(MojoHandle trap_handle,
    366                          const MojoArmTrapOptions* options,
    367                          uint32_t* num_blocking_events,
    368                          MojoTrapEvent* blocking_events) {
    369   if (options && options->struct_size < sizeof(*options))
    370     return MOJO_RESULT_INVALID_ARGUMENT;
    371 
    372   RequestContext request_context;
    373   scoped_refptr<Dispatcher> watcher = GetDispatcher(trap_handle);
    374   if (!watcher || watcher->GetType() != Dispatcher::Type::WATCHER)
    375     return MOJO_RESULT_INVALID_ARGUMENT;
    376   return watcher->Arm(num_blocking_events, blocking_events);
    377 }
    378 
    379 MojoResult Core::CreateMessage(const MojoCreateMessageOptions* options,
    380                                MojoMessageHandle* message_handle) {
    381   if (!message_handle)
    382     return MOJO_RESULT_INVALID_ARGUMENT;
    383   if (options && options->struct_size < sizeof(*options))
    384     return MOJO_RESULT_INVALID_ARGUMENT;
    385   *message_handle = reinterpret_cast<MojoMessageHandle>(
    386       UserMessageImpl::CreateEventForNewMessage().release());
    387   return MOJO_RESULT_OK;
    388 }
    389 
    390 MojoResult Core::DestroyMessage(MojoMessageHandle message_handle) {
    391   if (!message_handle)
    392     return MOJO_RESULT_INVALID_ARGUMENT;
    393 
    394   RequestContext request_context;
    395   delete reinterpret_cast<ports::UserMessageEvent*>(message_handle);
    396   return MOJO_RESULT_OK;
    397 }
    398 
    399 MojoResult Core::SerializeMessage(MojoMessageHandle message_handle,
    400                                   const MojoSerializeMessageOptions* options) {
    401   if (!message_handle)
    402     return MOJO_RESULT_INVALID_ARGUMENT;
    403   if (options && options->struct_size < sizeof(*options))
    404     return MOJO_RESULT_INVALID_ARGUMENT;
    405   RequestContext request_context;
    406   return reinterpret_cast<ports::UserMessageEvent*>(message_handle)
    407       ->GetMessage<UserMessageImpl>()
    408       ->SerializeIfNecessary();
    409 }
    410 
    411 MojoResult Core::AppendMessageData(MojoMessageHandle message_handle,
    412                                    uint32_t additional_payload_size,
    413                                    const MojoHandle* handles,
    414                                    uint32_t num_handles,
    415                                    const MojoAppendMessageDataOptions* options,
    416                                    void** buffer,
    417                                    uint32_t* buffer_size) {
    418   if (!message_handle || (num_handles && !handles))
    419     return MOJO_RESULT_INVALID_ARGUMENT;
    420   if (options && options->struct_size < sizeof(*options))
    421     return MOJO_RESULT_INVALID_ARGUMENT;
    422 
    423   RequestContext request_context;
    424   auto* message = reinterpret_cast<ports::UserMessageEvent*>(message_handle)
    425                       ->GetMessage<UserMessageImpl>();
    426   MojoResult rv =
    427       message->AppendData(additional_payload_size, handles, num_handles);
    428   if (rv != MOJO_RESULT_OK)
    429     return rv;
    430 
    431   if (options && (options->flags & MOJO_APPEND_MESSAGE_DATA_FLAG_COMMIT_SIZE)) {
    432     RequestContext request_context;
    433     message->CommitSize();
    434   }
    435 
    436   if (buffer)
    437     *buffer = message->user_payload();
    438   if (buffer_size) {
    439     *buffer_size =
    440         base::checked_cast<uint32_t>(message->user_payload_capacity());
    441   }
    442   return MOJO_RESULT_OK;
    443 }
    444 
    445 MojoResult Core::GetMessageData(MojoMessageHandle message_handle,
    446                                 const MojoGetMessageDataOptions* options,
    447                                 void** buffer,
    448                                 uint32_t* num_bytes,
    449                                 MojoHandle* handles,
    450                                 uint32_t* num_handles) {
    451   if (!message_handle || (num_handles && *num_handles && !handles))
    452     return MOJO_RESULT_INVALID_ARGUMENT;
    453   if (options && options->struct_size < sizeof(*options))
    454     return MOJO_RESULT_INVALID_ARGUMENT;
    455 
    456   auto* message = reinterpret_cast<ports::UserMessageEvent*>(message_handle)
    457                       ->GetMessage<UserMessageImpl>();
    458   if (!message->IsSerialized() || !message->IsTransmittable())
    459     return MOJO_RESULT_FAILED_PRECONDITION;
    460 
    461   if (num_bytes) {
    462     base::CheckedNumeric<uint32_t> payload_size = message->user_payload_size();
    463     *num_bytes = payload_size.ValueOrDie();
    464   }
    465 
    466   if (message->user_payload_size() > 0) {
    467     if (!num_bytes || !buffer)
    468       return MOJO_RESULT_RESOURCE_EXHAUSTED;
    469 
    470     *buffer = message->user_payload();
    471   } else if (buffer) {
    472     *buffer = nullptr;
    473   }
    474 
    475   if (options && (options->flags & MOJO_GET_MESSAGE_DATA_FLAG_IGNORE_HANDLES))
    476     return MOJO_RESULT_OK;
    477 
    478   uint32_t max_num_handles = 0;
    479   if (num_handles) {
    480     max_num_handles = *num_handles;
    481     *num_handles = static_cast<uint32_t>(message->num_handles());
    482   }
    483 
    484   if (message->num_handles() > max_num_handles ||
    485       message->num_handles() > kMaxHandlesPerMessage) {
    486     return MOJO_RESULT_RESOURCE_EXHAUSTED;
    487   }
    488 
    489   RequestContext request_context;
    490   return message->ExtractSerializedHandles(
    491       UserMessageImpl::ExtractBadHandlePolicy::kAbort, handles);
    492 }
    493 
    494 MojoResult Core::SetMessageContext(
    495     MojoMessageHandle message_handle,
    496     uintptr_t context,
    497     MojoMessageContextSerializer serializer,
    498     MojoMessageContextDestructor destructor,
    499     const MojoSetMessageContextOptions* options) {
    500   if (!message_handle)
    501     return MOJO_RESULT_INVALID_ARGUMENT;
    502   if (options && options->struct_size < sizeof(*options))
    503     return MOJO_RESULT_INVALID_ARGUMENT;
    504   auto* message = reinterpret_cast<ports::UserMessageEvent*>(message_handle)
    505                       ->GetMessage<UserMessageImpl>();
    506   return message->SetContext(context, serializer, destructor);
    507 }
    508 
    509 MojoResult Core::GetMessageContext(MojoMessageHandle message_handle,
    510                                    const MojoGetMessageContextOptions* options,
    511                                    uintptr_t* context) {
    512   if (!message_handle)
    513     return MOJO_RESULT_INVALID_ARGUMENT;
    514   if (options && options->struct_size < sizeof(*options))
    515     return MOJO_RESULT_INVALID_ARGUMENT;
    516 
    517   auto* message = reinterpret_cast<ports::UserMessageEvent*>(message_handle)
    518                       ->GetMessage<UserMessageImpl>();
    519   if (!message->HasContext())
    520     return MOJO_RESULT_NOT_FOUND;
    521 
    522   *context = message->context();
    523   return MOJO_RESULT_OK;
    524 }
    525 
    526 MojoResult Core::CreateMessagePipe(const MojoCreateMessagePipeOptions* options,
    527                                    MojoHandle* message_pipe_handle0,
    528                                    MojoHandle* message_pipe_handle1) {
    529   RequestContext request_context;
    530   ports::PortRef port0, port1;
    531   GetNodeController()->node()->CreatePortPair(&port0, &port1);
    532 
    533   DCHECK(message_pipe_handle0);
    534   DCHECK(message_pipe_handle1);
    535 
    536   uint64_t pipe_id = base::RandUint64();
    537 
    538   *message_pipe_handle0 = AddDispatcher(
    539       new MessagePipeDispatcher(GetNodeController(), port0, pipe_id, 0));
    540   if (*message_pipe_handle0 == MOJO_HANDLE_INVALID)
    541     return MOJO_RESULT_RESOURCE_EXHAUSTED;
    542 
    543   *message_pipe_handle1 = AddDispatcher(
    544       new MessagePipeDispatcher(GetNodeController(), port1, pipe_id, 1));
    545   if (*message_pipe_handle1 == MOJO_HANDLE_INVALID) {
    546     scoped_refptr<Dispatcher> dispatcher0;
    547     {
    548       base::AutoLock lock(handles_->GetLock());
    549       handles_->GetAndRemoveDispatcher(*message_pipe_handle0, &dispatcher0);
    550     }
    551     dispatcher0->Close();
    552     return MOJO_RESULT_RESOURCE_EXHAUSTED;
    553   }
    554 
    555   return MOJO_RESULT_OK;
    556 }
    557 
    558 MojoResult Core::WriteMessage(MojoHandle message_pipe_handle,
    559                               MojoMessageHandle message_handle,
    560                               const MojoWriteMessageOptions* options) {
    561   RequestContext request_context;
    562   if (!message_handle)
    563     return MOJO_RESULT_INVALID_ARGUMENT;
    564   auto message_event = base::WrapUnique(
    565       reinterpret_cast<ports::UserMessageEvent*>(message_handle));
    566   auto* message = message_event->GetMessage<UserMessageImpl>();
    567   if (!message || !message->IsTransmittable())
    568     return MOJO_RESULT_INVALID_ARGUMENT;
    569   auto dispatcher = GetDispatcher(message_pipe_handle);
    570   if (!dispatcher)
    571     return MOJO_RESULT_INVALID_ARGUMENT;
    572   return dispatcher->WriteMessage(std::move(message_event));
    573 }
    574 
    575 MojoResult Core::ReadMessage(MojoHandle message_pipe_handle,
    576                              const MojoReadMessageOptions* options,
    577                              MojoMessageHandle* message_handle) {
    578   RequestContext request_context;
    579   auto dispatcher = GetDispatcher(message_pipe_handle);
    580   if (!dispatcher || !message_handle)
    581     return MOJO_RESULT_INVALID_ARGUMENT;
    582 
    583   std::unique_ptr<ports::UserMessageEvent> message_event;
    584   MojoResult rv = dispatcher->ReadMessage(&message_event);
    585   if (rv != MOJO_RESULT_OK)
    586     return rv;
    587 
    588   *message_handle =
    589       reinterpret_cast<MojoMessageHandle>(message_event.release());
    590   return MOJO_RESULT_OK;
    591 }
    592 
    593 MojoResult Core::FuseMessagePipes(MojoHandle handle0,
    594                                   MojoHandle handle1,
    595                                   const MojoFuseMessagePipesOptions* options) {
    596   RequestContext request_context;
    597   scoped_refptr<Dispatcher> dispatcher0;
    598   scoped_refptr<Dispatcher> dispatcher1;
    599 
    600   bool valid_handles = true;
    601   {
    602     base::AutoLock lock(handles_->GetLock());
    603     MojoResult result0 =
    604         handles_->GetAndRemoveDispatcher(handle0, &dispatcher0);
    605     MojoResult result1 =
    606         handles_->GetAndRemoveDispatcher(handle1, &dispatcher1);
    607     if (result0 != MOJO_RESULT_OK || result1 != MOJO_RESULT_OK ||
    608         dispatcher0->GetType() != Dispatcher::Type::MESSAGE_PIPE ||
    609         dispatcher1->GetType() != Dispatcher::Type::MESSAGE_PIPE)
    610       valid_handles = false;
    611   }
    612 
    613   if (!valid_handles) {
    614     if (dispatcher0)
    615       dispatcher0->Close();
    616     if (dispatcher1)
    617       dispatcher1->Close();
    618     return MOJO_RESULT_INVALID_ARGUMENT;
    619   }
    620 
    621   MessagePipeDispatcher* mpd0 =
    622       static_cast<MessagePipeDispatcher*>(dispatcher0.get());
    623   MessagePipeDispatcher* mpd1 =
    624       static_cast<MessagePipeDispatcher*>(dispatcher1.get());
    625 
    626   if (!mpd0->Fuse(mpd1))
    627     return MOJO_RESULT_FAILED_PRECONDITION;
    628 
    629   return MOJO_RESULT_OK;
    630 }
    631 
    632 MojoResult Core::NotifyBadMessage(MojoMessageHandle message_handle,
    633                                   const char* error,
    634                                   size_t error_num_bytes,
    635                                   const MojoNotifyBadMessageOptions* options) {
    636   if (!message_handle)
    637     return MOJO_RESULT_INVALID_ARGUMENT;
    638 
    639   auto* message_event =
    640       reinterpret_cast<ports::UserMessageEvent*>(message_handle);
    641   auto* message = message_event->GetMessage<UserMessageImpl>();
    642   if (message->source_node() == ports::kInvalidNodeName) {
    643     DVLOG(1) << "Received invalid message from unknown node.";
    644     if (!default_process_error_callback_.is_null())
    645       default_process_error_callback_.Run(std::string(error, error_num_bytes));
    646     return MOJO_RESULT_OK;
    647   }
    648 
    649   GetNodeController()->NotifyBadMessageFrom(
    650       message->source_node(), std::string(error, error_num_bytes));
    651   return MOJO_RESULT_OK;
    652 }
    653 
    654 MojoResult Core::CreateDataPipe(const MojoCreateDataPipeOptions* options,
    655                                 MojoHandle* data_pipe_producer_handle,
    656                                 MojoHandle* data_pipe_consumer_handle) {
    657   RequestContext request_context;
    658   if (options && options->struct_size < sizeof(MojoCreateDataPipeOptions))
    659     return MOJO_RESULT_INVALID_ARGUMENT;
    660 
    661   MojoCreateDataPipeOptions create_options;
    662   create_options.struct_size = sizeof(MojoCreateDataPipeOptions);
    663   create_options.flags = options ? options->flags : 0;
    664   create_options.element_num_bytes = options ? options->element_num_bytes : 1;
    665   // TODO(rockot): Use Configuration to get default data pipe capacity.
    666   create_options.capacity_num_bytes = options && options->capacity_num_bytes
    667                                           ? options->capacity_num_bytes
    668                                           : 64 * 1024;
    669   if (!create_options.element_num_bytes || !create_options.capacity_num_bytes ||
    670       create_options.capacity_num_bytes < create_options.element_num_bytes) {
    671     return MOJO_RESULT_INVALID_ARGUMENT;
    672   }
    673 
    674   base::subtle::PlatformSharedMemoryRegion ring_buffer_region =
    675       base::WritableSharedMemoryRegion::TakeHandleForSerialization(
    676           GetNodeController()->CreateSharedBuffer(
    677               create_options.capacity_num_bytes));
    678 
    679   // NOTE: We demote the writable region to an unsafe region so that the
    680   // producer handle can be transferred freely. There is no compelling reason
    681   // to restrict access rights of consumers since they are the exclusive
    682   // consumer of this pipe, and it would be impossible to support such access
    683   // control on Android anyway.
    684   auto writable_region_handle = ring_buffer_region.PassPlatformHandle();
    685 #if defined(OS_POSIX) && !defined(OS_ANDROID) && \
    686     (!defined(OS_MACOSX) || defined(OS_IOS))
    687   // This isn't strictly necessary, but it does make the handle configuration
    688   // consistent with regular UnsafeSharedMemoryRegions.
    689   writable_region_handle.readonly_fd.reset();
    690 #endif
    691   base::UnsafeSharedMemoryRegion producer_region =
    692       base::UnsafeSharedMemoryRegion::Deserialize(
    693           base::subtle::PlatformSharedMemoryRegion::Take(
    694               std::move(writable_region_handle),
    695               base::subtle::PlatformSharedMemoryRegion::Mode::kUnsafe,
    696               create_options.capacity_num_bytes, ring_buffer_region.GetGUID()));
    697   if (!producer_region.IsValid())
    698     return MOJO_RESULT_RESOURCE_EXHAUSTED;
    699 
    700   ports::PortRef port0, port1;
    701   GetNodeController()->node()->CreatePortPair(&port0, &port1);
    702 
    703   DCHECK(data_pipe_producer_handle);
    704   DCHECK(data_pipe_consumer_handle);
    705 
    706   base::UnsafeSharedMemoryRegion consumer_region = producer_region.Duplicate();
    707   uint64_t pipe_id = base::RandUint64();
    708   scoped_refptr<Dispatcher> producer = DataPipeProducerDispatcher::Create(
    709       GetNodeController(), port0, std::move(producer_region), create_options,
    710       pipe_id);
    711   if (!producer)
    712     return MOJO_RESULT_RESOURCE_EXHAUSTED;
    713 
    714   scoped_refptr<Dispatcher> consumer = DataPipeConsumerDispatcher::Create(
    715       GetNodeController(), port1, std::move(consumer_region), create_options,
    716       pipe_id);
    717   if (!consumer) {
    718     producer->Close();
    719     return MOJO_RESULT_RESOURCE_EXHAUSTED;
    720   }
    721 
    722   *data_pipe_producer_handle = AddDispatcher(producer);
    723   *data_pipe_consumer_handle = AddDispatcher(consumer);
    724   if (*data_pipe_producer_handle == MOJO_HANDLE_INVALID ||
    725       *data_pipe_consumer_handle == MOJO_HANDLE_INVALID) {
    726     if (*data_pipe_producer_handle != MOJO_HANDLE_INVALID) {
    727       scoped_refptr<Dispatcher> unused;
    728       base::AutoLock lock(handles_->GetLock());
    729       handles_->GetAndRemoveDispatcher(*data_pipe_producer_handle, &unused);
    730     }
    731     producer->Close();
    732     consumer->Close();
    733     return MOJO_RESULT_RESOURCE_EXHAUSTED;
    734   }
    735 
    736   return MOJO_RESULT_OK;
    737 }
    738 
    739 MojoResult Core::WriteData(MojoHandle data_pipe_producer_handle,
    740                            const void* elements,
    741                            uint32_t* num_bytes,
    742                            const MojoWriteDataOptions* options) {
    743   RequestContext request_context;
    744   scoped_refptr<Dispatcher> dispatcher(
    745       GetDispatcher(data_pipe_producer_handle));
    746   if (!dispatcher)
    747     return MOJO_RESULT_INVALID_ARGUMENT;
    748 
    749   MojoWriteDataOptions validated_options;
    750   if (options) {
    751     if (options->struct_size < sizeof(*options))
    752       return MOJO_RESULT_INVALID_ARGUMENT;
    753 
    754     constexpr MojoWriteDataFlags kSupportedFlags =
    755         MOJO_WRITE_DATA_FLAG_NONE | MOJO_WRITE_DATA_FLAG_ALL_OR_NONE;
    756     if (options->flags & ~kSupportedFlags)
    757       return MOJO_RESULT_UNIMPLEMENTED;
    758     validated_options.flags = options->flags;
    759   } else {
    760     validated_options.flags = MOJO_WRITE_DATA_FLAG_NONE;
    761   }
    762   return dispatcher->WriteData(elements, num_bytes, validated_options);
    763 }
    764 
    765 MojoResult Core::BeginWriteData(MojoHandle data_pipe_producer_handle,
    766                                 const MojoBeginWriteDataOptions* options,
    767                                 void** buffer,
    768                                 uint32_t* buffer_num_bytes) {
    769   RequestContext request_context;
    770   scoped_refptr<Dispatcher> dispatcher(
    771       GetDispatcher(data_pipe_producer_handle));
    772   if (!dispatcher)
    773     return MOJO_RESULT_INVALID_ARGUMENT;
    774   if (options) {
    775     if (options->struct_size < sizeof(*options))
    776       return MOJO_RESULT_INVALID_ARGUMENT;
    777     if (options->flags != MOJO_BEGIN_WRITE_DATA_FLAG_NONE)
    778       return MOJO_RESULT_UNIMPLEMENTED;
    779   }
    780   return dispatcher->BeginWriteData(buffer, buffer_num_bytes);
    781 }
    782 
    783 MojoResult Core::EndWriteData(MojoHandle data_pipe_producer_handle,
    784                               uint32_t num_bytes_written,
    785                               const MojoEndWriteDataOptions* options) {
    786   RequestContext request_context;
    787   scoped_refptr<Dispatcher> dispatcher(
    788       GetDispatcher(data_pipe_producer_handle));
    789   if (!dispatcher)
    790     return MOJO_RESULT_INVALID_ARGUMENT;
    791   if (options) {
    792     if (options->struct_size < sizeof(*options))
    793       return MOJO_RESULT_INVALID_ARGUMENT;
    794     if (options->flags != MOJO_END_WRITE_DATA_FLAG_NONE)
    795       return MOJO_RESULT_UNIMPLEMENTED;
    796   }
    797   return dispatcher->EndWriteData(num_bytes_written);
    798 }
    799 
    800 MojoResult Core::ReadData(MojoHandle data_pipe_consumer_handle,
    801                           const MojoReadDataOptions* options,
    802                           void* elements,
    803                           uint32_t* num_bytes) {
    804   RequestContext request_context;
    805   scoped_refptr<Dispatcher> dispatcher(
    806       GetDispatcher(data_pipe_consumer_handle));
    807   if (!dispatcher)
    808     return MOJO_RESULT_INVALID_ARGUMENT;
    809 
    810   MojoReadDataOptions validated_options;
    811   if (options) {
    812     if (options->struct_size < sizeof(*options))
    813       return MOJO_RESULT_INVALID_ARGUMENT;
    814 
    815     constexpr MojoReadDataFlags kSupportedFlags =
    816         MOJO_READ_DATA_FLAG_NONE | MOJO_READ_DATA_FLAG_ALL_OR_NONE |
    817         MOJO_READ_DATA_FLAG_DISCARD | MOJO_READ_DATA_FLAG_QUERY |
    818         MOJO_READ_DATA_FLAG_PEEK;
    819     if (options->flags & ~kSupportedFlags)
    820       return MOJO_RESULT_UNIMPLEMENTED;
    821     validated_options.flags = options->flags;
    822   } else {
    823     validated_options.flags = MOJO_WRITE_DATA_FLAG_NONE;
    824   }
    825   return dispatcher->ReadData(validated_options, elements, num_bytes);
    826 }
    827 
    828 MojoResult Core::BeginReadData(MojoHandle data_pipe_consumer_handle,
    829                                const MojoBeginReadDataOptions* options,
    830                                const void** buffer,
    831                                uint32_t* buffer_num_bytes) {
    832   RequestContext request_context;
    833   scoped_refptr<Dispatcher> dispatcher(
    834       GetDispatcher(data_pipe_consumer_handle));
    835   if (!dispatcher)
    836     return MOJO_RESULT_INVALID_ARGUMENT;
    837 
    838   if (options) {
    839     if (options->struct_size < sizeof(*options))
    840       return MOJO_RESULT_INVALID_ARGUMENT;
    841     if (options->flags != MOJO_BEGIN_READ_DATA_FLAG_NONE)
    842       return MOJO_RESULT_UNIMPLEMENTED;
    843   }
    844   return dispatcher->BeginReadData(buffer, buffer_num_bytes);
    845 }
    846 
    847 MojoResult Core::EndReadData(MojoHandle data_pipe_consumer_handle,
    848                              uint32_t num_bytes_read,
    849                              const MojoEndReadDataOptions* options) {
    850   RequestContext request_context;
    851   scoped_refptr<Dispatcher> dispatcher(
    852       GetDispatcher(data_pipe_consumer_handle));
    853   if (!dispatcher)
    854     return MOJO_RESULT_INVALID_ARGUMENT;
    855   if (options) {
    856     if (options->struct_size < sizeof(*options))
    857       return MOJO_RESULT_INVALID_ARGUMENT;
    858     if (options->flags != MOJO_END_READ_DATA_FLAG_NONE)
    859       return MOJO_RESULT_UNIMPLEMENTED;
    860   }
    861   return dispatcher->EndReadData(num_bytes_read);
    862 }
    863 
    864 MojoResult Core::CreateSharedBuffer(
    865     uint64_t num_bytes,
    866     const MojoCreateSharedBufferOptions* options,
    867     MojoHandle* shared_buffer_handle) {
    868   RequestContext request_context;
    869   MojoCreateSharedBufferOptions validated_options = {};
    870   MojoResult result = SharedBufferDispatcher::ValidateCreateOptions(
    871       options, &validated_options);
    872   if (result != MOJO_RESULT_OK)
    873     return result;
    874 
    875   scoped_refptr<SharedBufferDispatcher> dispatcher;
    876   result = SharedBufferDispatcher::Create(
    877       validated_options, GetNodeController(), num_bytes, &dispatcher);
    878   if (result != MOJO_RESULT_OK) {
    879     DCHECK(!dispatcher);
    880     return result;
    881   }
    882 
    883   *shared_buffer_handle = AddDispatcher(dispatcher);
    884   if (*shared_buffer_handle == MOJO_HANDLE_INVALID) {
    885     LOG(ERROR) << "Handle table full";
    886     dispatcher->Close();
    887     return MOJO_RESULT_RESOURCE_EXHAUSTED;
    888   }
    889 
    890   return MOJO_RESULT_OK;
    891 }
    892 
    893 MojoResult Core::DuplicateBufferHandle(
    894     MojoHandle buffer_handle,
    895     const MojoDuplicateBufferHandleOptions* options,
    896     MojoHandle* new_buffer_handle) {
    897   RequestContext request_context;
    898   scoped_refptr<Dispatcher> dispatcher(GetDispatcher(buffer_handle));
    899   if (!dispatcher)
    900     return MOJO_RESULT_INVALID_ARGUMENT;
    901 
    902   // Don't verify |options| here; that's the dispatcher's job.
    903   scoped_refptr<Dispatcher> new_dispatcher;
    904   MojoResult result =
    905       dispatcher->DuplicateBufferHandle(options, &new_dispatcher);
    906   if (result != MOJO_RESULT_OK)
    907     return result;
    908 
    909   *new_buffer_handle = AddDispatcher(new_dispatcher);
    910   if (*new_buffer_handle == MOJO_HANDLE_INVALID) {
    911     LOG(ERROR) << "Handle table full";
    912     new_dispatcher->Close();
    913     return MOJO_RESULT_RESOURCE_EXHAUSTED;
    914   }
    915 
    916   return MOJO_RESULT_OK;
    917 }
    918 
    919 MojoResult Core::MapBuffer(MojoHandle buffer_handle,
    920                            uint64_t offset,
    921                            uint64_t num_bytes,
    922                            const MojoMapBufferOptions* options,
    923                            void** buffer) {
    924   scoped_refptr<Dispatcher> dispatcher(GetDispatcher(buffer_handle));
    925   if (!dispatcher)
    926     return MOJO_RESULT_INVALID_ARGUMENT;
    927   if (options) {
    928     if (options->struct_size < sizeof(*options))
    929       return MOJO_RESULT_INVALID_ARGUMENT;
    930     if (options->flags != MOJO_MAP_BUFFER_FLAG_NONE)
    931       return MOJO_RESULT_UNIMPLEMENTED;
    932   }
    933 
    934   std::unique_ptr<PlatformSharedMemoryMapping> mapping;
    935   MojoResult result = dispatcher->MapBuffer(offset, num_bytes, &mapping);
    936   if (result != MOJO_RESULT_OK)
    937     return result;
    938 
    939   DCHECK(mapping);
    940   void* address = mapping->GetBase();
    941   {
    942     base::AutoLock locker(mapping_table_lock_);
    943     if (mapping_table_.size() >= GetConfiguration().max_mapping_table_size)
    944       return MOJO_RESULT_RESOURCE_EXHAUSTED;
    945     auto emplace_result = mapping_table_.emplace(address, std::move(mapping));
    946     DCHECK(emplace_result.second);
    947   }
    948 
    949   *buffer = address;
    950   return MOJO_RESULT_OK;
    951 }
    952 
    953 MojoResult Core::UnmapBuffer(void* buffer) {
    954   std::unique_ptr<PlatformSharedMemoryMapping> mapping;
    955   // Destroy |mapping| while not holding the lock.
    956   {
    957     base::AutoLock lock(mapping_table_lock_);
    958     auto iter = mapping_table_.find(buffer);
    959     if (iter == mapping_table_.end())
    960       return MOJO_RESULT_INVALID_ARGUMENT;
    961 
    962     // Grab a reference so that it gets unmapped outside of this lock.
    963     mapping = std::move(iter->second);
    964     mapping_table_.erase(iter);
    965   }
    966   return MOJO_RESULT_OK;
    967 }
    968 
    969 MojoResult Core::GetBufferInfo(MojoHandle buffer_handle,
    970                                const MojoGetBufferInfoOptions* options,
    971                                MojoSharedBufferInfo* info) {
    972   if (options) {
    973     if (options->struct_size < sizeof(*options))
    974       return MOJO_RESULT_INVALID_ARGUMENT;
    975     if (options->flags != MOJO_GET_BUFFER_INFO_FLAG_NONE)
    976       return MOJO_RESULT_UNIMPLEMENTED;
    977   }
    978   if (!info || info->struct_size < sizeof(MojoSharedBufferInfo))
    979     return MOJO_RESULT_INVALID_ARGUMENT;
    980 
    981   scoped_refptr<Dispatcher> dispatcher(GetDispatcher(buffer_handle));
    982   if (!dispatcher)
    983     return MOJO_RESULT_INVALID_ARGUMENT;
    984 
    985   return dispatcher->GetBufferInfo(info);
    986 }
    987 
    988 MojoResult Core::WrapPlatformHandle(
    989     const MojoPlatformHandle* platform_handle,
    990     const MojoWrapPlatformHandleOptions* options,
    991     MojoHandle* mojo_handle) {
    992   if (!platform_handle ||
    993       platform_handle->struct_size < sizeof(*platform_handle)) {
    994     return MOJO_RESULT_INVALID_ARGUMENT;
    995   }
    996 
    997   auto handle = PlatformHandle::FromMojoPlatformHandle(platform_handle);
    998   MojoHandle h =
    999       AddDispatcher(PlatformHandleDispatcher::Create(std::move(handle)));
   1000   if (h == MOJO_HANDLE_INVALID)
   1001     return MOJO_RESULT_RESOURCE_EXHAUSTED;
   1002 
   1003   *mojo_handle = h;
   1004   return MOJO_RESULT_OK;
   1005 }
   1006 
   1007 MojoResult Core::UnwrapPlatformHandle(
   1008     MojoHandle mojo_handle,
   1009     const MojoUnwrapPlatformHandleOptions* options,
   1010     MojoPlatformHandle* platform_handle) {
   1011   if (!platform_handle ||
   1012       platform_handle->struct_size < sizeof(*platform_handle)) {
   1013     return MOJO_RESULT_INVALID_ARGUMENT;
   1014   }
   1015 
   1016   scoped_refptr<Dispatcher> dispatcher;
   1017   {
   1018     base::AutoLock lock(handles_->GetLock());
   1019     dispatcher = handles_->GetDispatcher(mojo_handle);
   1020     if (dispatcher->GetType() != Dispatcher::Type::PLATFORM_HANDLE)
   1021       return MOJO_RESULT_INVALID_ARGUMENT;
   1022 
   1023     MojoResult result =
   1024         handles_->GetAndRemoveDispatcher(mojo_handle, &dispatcher);
   1025     if (result != MOJO_RESULT_OK)
   1026       return result;
   1027   }
   1028 
   1029   PlatformHandleDispatcher* phd =
   1030       static_cast<PlatformHandleDispatcher*>(dispatcher.get());
   1031   PlatformHandle handle = phd->TakePlatformHandle();
   1032   phd->Close();
   1033 
   1034   PlatformHandle::ToMojoPlatformHandle(std::move(handle), platform_handle);
   1035   return MOJO_RESULT_OK;
   1036 }
   1037 
   1038 MojoResult Core::WrapPlatformSharedMemoryRegion(
   1039     const MojoPlatformHandle* platform_handles,
   1040     uint32_t num_platform_handles,
   1041     uint64_t size,
   1042     const MojoSharedBufferGuid* guid,
   1043     MojoPlatformSharedMemoryRegionAccessMode access_mode,
   1044     const MojoWrapPlatformSharedMemoryRegionOptions* options,
   1045     MojoHandle* mojo_handle) {
   1046   DCHECK(size);
   1047 
   1048 #if defined(OS_POSIX) && !defined(OS_ANDROID) && \
   1049     (!defined(OS_MACOSX) || defined(OS_IOS))
   1050   if (access_mode == MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_WRITABLE) {
   1051     if (num_platform_handles != 2)
   1052       return MOJO_RESULT_INVALID_ARGUMENT;
   1053   }
   1054 #else
   1055   if (num_platform_handles != 1)
   1056     return MOJO_RESULT_INVALID_ARGUMENT;
   1057 #endif
   1058 
   1059   PlatformHandle handles[2];
   1060   bool handles_ok = true;
   1061   for (size_t i = 0; i < num_platform_handles; ++i) {
   1062     handles[i] = PlatformHandle::FromMojoPlatformHandle(&platform_handles[i]);
   1063     if (!handles[i].is_valid())
   1064       handles_ok = false;
   1065   }
   1066   if (!handles_ok)
   1067     return MOJO_RESULT_INVALID_ARGUMENT;
   1068 
   1069   base::UnguessableToken token =
   1070       base::UnguessableToken::Deserialize(guid->high, guid->low);
   1071 
   1072   base::subtle::PlatformSharedMemoryRegion::Mode mode;
   1073   switch (access_mode) {
   1074     case MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_READ_ONLY:
   1075       mode = base::subtle::PlatformSharedMemoryRegion::Mode::kReadOnly;
   1076       break;
   1077     case MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_WRITABLE:
   1078       mode = base::subtle::PlatformSharedMemoryRegion::Mode::kWritable;
   1079       break;
   1080     case MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_UNSAFE:
   1081       mode = base::subtle::PlatformSharedMemoryRegion::Mode::kUnsafe;
   1082       break;
   1083     default:
   1084       return MOJO_RESULT_INVALID_ARGUMENT;
   1085   }
   1086 
   1087   base::subtle::PlatformSharedMemoryRegion region =
   1088       base::subtle::PlatformSharedMemoryRegion::Take(
   1089           CreateSharedMemoryRegionHandleFromPlatformHandles(
   1090               std::move(handles[0]), std::move(handles[1])),
   1091           mode, size, token);
   1092   if (!region.IsValid())
   1093     return MOJO_RESULT_UNKNOWN;
   1094 
   1095   scoped_refptr<SharedBufferDispatcher> dispatcher;
   1096   MojoResult result =
   1097       SharedBufferDispatcher::CreateFromPlatformSharedMemoryRegion(
   1098           std::move(region), &dispatcher);
   1099   if (result != MOJO_RESULT_OK)
   1100     return result;
   1101 
   1102   MojoHandle h = AddDispatcher(dispatcher);
   1103   if (h == MOJO_HANDLE_INVALID) {
   1104     dispatcher->Close();
   1105     return MOJO_RESULT_RESOURCE_EXHAUSTED;
   1106   }
   1107 
   1108   *mojo_handle = h;
   1109   return MOJO_RESULT_OK;
   1110 }
   1111 
   1112 MojoResult Core::UnwrapPlatformSharedMemoryRegion(
   1113     MojoHandle mojo_handle,
   1114     const MojoUnwrapPlatformSharedMemoryRegionOptions* options,
   1115     MojoPlatformHandle* platform_handles,
   1116     uint32_t* num_platform_handles,
   1117     uint64_t* size,
   1118     MojoSharedBufferGuid* guid,
   1119     MojoPlatformSharedMemoryRegionAccessMode* access_mode) {
   1120   scoped_refptr<Dispatcher> dispatcher;
   1121   MojoResult result = MOJO_RESULT_OK;
   1122   {
   1123     base::AutoLock lock(handles_->GetLock());
   1124     result = handles_->GetAndRemoveDispatcher(mojo_handle, &dispatcher);
   1125     if (result != MOJO_RESULT_OK)
   1126       return result;
   1127   }
   1128 
   1129   if (dispatcher->GetType() != Dispatcher::Type::SHARED_BUFFER) {
   1130     dispatcher->Close();
   1131     return MOJO_RESULT_INVALID_ARGUMENT;
   1132   }
   1133 
   1134   SharedBufferDispatcher* shm_dispatcher =
   1135       static_cast<SharedBufferDispatcher*>(dispatcher.get());
   1136   base::subtle::PlatformSharedMemoryRegion region =
   1137       shm_dispatcher->PassPlatformSharedMemoryRegion();
   1138   DCHECK(region.IsValid());
   1139   DCHECK(size);
   1140   *size = region.GetSize();
   1141 
   1142   base::UnguessableToken token = region.GetGUID();
   1143   guid->high = token.GetHighForSerialization();
   1144   guid->low = token.GetLowForSerialization();
   1145 
   1146   DCHECK(access_mode);
   1147   switch (region.GetMode()) {
   1148     case base::subtle::PlatformSharedMemoryRegion::Mode::kReadOnly:
   1149       *access_mode = MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_READ_ONLY;
   1150       break;
   1151     case base::subtle::PlatformSharedMemoryRegion::Mode::kWritable:
   1152       *access_mode = MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_WRITABLE;
   1153       break;
   1154     case base::subtle::PlatformSharedMemoryRegion::Mode::kUnsafe:
   1155       *access_mode = MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_UNSAFE;
   1156       break;
   1157     default:
   1158       return MOJO_RESULT_INVALID_ARGUMENT;
   1159   }
   1160 
   1161   PlatformHandle handle;
   1162   PlatformHandle read_only_handle;
   1163   ExtractPlatformHandlesFromSharedMemoryRegionHandle(
   1164       region.PassPlatformHandle(), &handle, &read_only_handle);
   1165 
   1166   const uint32_t available_handle_storage_slots = *num_platform_handles;
   1167   if (available_handle_storage_slots < 1)
   1168     return MOJO_RESULT_RESOURCE_EXHAUSTED;
   1169   *num_platform_handles = 1;
   1170 #if defined(OS_POSIX) && !defined(OS_ANDROID) && \
   1171     (!defined(OS_MACOSX) || defined(OS_IOS))
   1172   if (region.GetMode() ==
   1173       base::subtle::PlatformSharedMemoryRegion::Mode::kWritable) {
   1174     if (available_handle_storage_slots < 2)
   1175       return MOJO_RESULT_INVALID_ARGUMENT;
   1176     PlatformHandle::ToMojoPlatformHandle(std::move(read_only_handle),
   1177                                          &platform_handles[1]);
   1178     if (platform_handles[1].type == MOJO_PLATFORM_HANDLE_TYPE_INVALID)
   1179       return MOJO_RESULT_INVALID_ARGUMENT;
   1180     *num_platform_handles = 2;
   1181   }
   1182 #endif
   1183 
   1184   PlatformHandle::ToMojoPlatformHandle(std::move(handle), &platform_handles[0]);
   1185   if (platform_handles[0].type == MOJO_PLATFORM_HANDLE_TYPE_INVALID)
   1186     return MOJO_RESULT_INVALID_ARGUMENT;
   1187 
   1188   return MOJO_RESULT_OK;
   1189 }
   1190 
   1191 MojoResult Core::CreateInvitation(const MojoCreateInvitationOptions* options,
   1192                                   MojoHandle* invitation_handle) {
   1193   if (options && options->struct_size < sizeof(*options))
   1194     return MOJO_RESULT_INVALID_ARGUMENT;
   1195   if (!invitation_handle)
   1196     return MOJO_RESULT_INVALID_ARGUMENT;
   1197 
   1198   *invitation_handle = AddDispatcher(new InvitationDispatcher);
   1199   if (*invitation_handle == MOJO_HANDLE_INVALID)
   1200     return MOJO_RESULT_RESOURCE_EXHAUSTED;
   1201 
   1202   return MOJO_RESULT_OK;
   1203 }
   1204 
   1205 MojoResult Core::AttachMessagePipeToInvitation(
   1206     MojoHandle invitation_handle,
   1207     const void* name,
   1208     uint32_t name_num_bytes,
   1209     const MojoAttachMessagePipeToInvitationOptions* options,
   1210     MojoHandle* message_pipe_handle) {
   1211   if (options && options->struct_size < sizeof(*options))
   1212     return MOJO_RESULT_INVALID_ARGUMENT;
   1213   if (!message_pipe_handle)
   1214     return MOJO_RESULT_INVALID_ARGUMENT;
   1215   if (name_num_bytes == 0)
   1216     return MOJO_RESULT_INVALID_ARGUMENT;
   1217 
   1218   scoped_refptr<Dispatcher> dispatcher = GetDispatcher(invitation_handle);
   1219   if (!dispatcher || dispatcher->GetType() != Dispatcher::Type::INVITATION)
   1220     return MOJO_RESULT_INVALID_ARGUMENT;
   1221   auto* invitation_dispatcher =
   1222       static_cast<InvitationDispatcher*>(dispatcher.get());
   1223 
   1224   RequestContext request_context;
   1225 
   1226   ports::PortRef remote_peer_port;
   1227   MojoHandle local_handle = CreatePartialMessagePipe(&remote_peer_port);
   1228   if (local_handle == MOJO_HANDLE_INVALID)
   1229     return MOJO_RESULT_RESOURCE_EXHAUSTED;
   1230 
   1231   MojoResult result = invitation_dispatcher->AttachMessagePipe(
   1232       base::StringPiece(static_cast<const char*>(name), name_num_bytes),
   1233       std::move(remote_peer_port));
   1234   if (result != MOJO_RESULT_OK) {
   1235     Close(local_handle);
   1236     return result;
   1237   }
   1238 
   1239   *message_pipe_handle = local_handle;
   1240   return MOJO_RESULT_OK;
   1241 }
   1242 
   1243 MojoResult Core::ExtractMessagePipeFromInvitation(
   1244     MojoHandle invitation_handle,
   1245     const void* name,
   1246     uint32_t name_num_bytes,
   1247     const MojoExtractMessagePipeFromInvitationOptions* options,
   1248     MojoHandle* message_pipe_handle) {
   1249   if (options && options->struct_size < sizeof(*options))
   1250     return MOJO_RESULT_INVALID_ARGUMENT;
   1251   if (!message_pipe_handle)
   1252     return MOJO_RESULT_INVALID_ARGUMENT;
   1253   if (name_num_bytes == 0)
   1254     return MOJO_RESULT_INVALID_ARGUMENT;
   1255 
   1256   RequestContext request_context;
   1257 
   1258   base::StringPiece name_string(static_cast<const char*>(name), name_num_bytes);
   1259   scoped_refptr<Dispatcher> dispatcher = GetDispatcher(invitation_handle);
   1260   if (!dispatcher || dispatcher->GetType() != Dispatcher::Type::INVITATION)
   1261     return MOJO_RESULT_INVALID_ARGUMENT;
   1262   auto* invitation_dispatcher =
   1263       static_cast<InvitationDispatcher*>(dispatcher.get());
   1264   // First attempt to extract from the invitation object itself. This is for
   1265   // cases where this invitation was created in-process or is an accepted
   1266   // isolated invitation.
   1267   MojoResult extract_result = invitation_dispatcher->ExtractMessagePipe(
   1268       name_string, message_pipe_handle);
   1269   if (extract_result == MOJO_RESULT_OK ||
   1270       extract_result == MOJO_RESULT_RESOURCE_EXHAUSTED) {
   1271     return extract_result;
   1272   }
   1273 
   1274   *message_pipe_handle =
   1275       ExtractMessagePipeFromInvitation(name_string.as_string());
   1276   if (*message_pipe_handle == MOJO_HANDLE_INVALID)
   1277     return MOJO_RESULT_RESOURCE_EXHAUSTED;
   1278   return MOJO_RESULT_OK;
   1279 }
   1280 
   1281 MojoResult Core::SendInvitation(
   1282     MojoHandle invitation_handle,
   1283     const MojoPlatformProcessHandle* process_handle,
   1284     const MojoInvitationTransportEndpoint* transport_endpoint,
   1285     MojoProcessErrorHandler error_handler,
   1286     uintptr_t error_handler_context,
   1287     const MojoSendInvitationOptions* options) {
   1288   if (options && options->struct_size < sizeof(*options))
   1289     return MOJO_RESULT_INVALID_ARGUMENT;
   1290 
   1291   base::ProcessHandle target_process = base::kNullProcessHandle;
   1292   if (process_handle) {
   1293     if (process_handle->struct_size < sizeof(*process_handle))
   1294       return MOJO_RESULT_INVALID_ARGUMENT;
   1295 #if defined(OS_WIN)
   1296     target_process = reinterpret_cast<base::ProcessHandle>(
   1297         static_cast<uintptr_t>(process_handle->value));
   1298 #else
   1299     target_process = static_cast<base::ProcessHandle>(process_handle->value);
   1300 #endif
   1301   }
   1302 
   1303   ProcessErrorCallback process_error_callback;
   1304   if (error_handler) {
   1305     auto error_handler_task_runner = GetNodeController()->io_task_runner();
   1306     process_error_callback = base::BindRepeating(
   1307         &RunMojoProcessErrorHandler,
   1308         base::Owned(new ProcessDisconnectHandler(
   1309             error_handler_task_runner, error_handler, error_handler_context)),
   1310         error_handler_task_runner, error_handler, error_handler_context);
   1311   } else if (default_process_error_callback_) {
   1312     process_error_callback = default_process_error_callback_;
   1313   }
   1314 
   1315   if (!transport_endpoint)
   1316     return MOJO_RESULT_INVALID_ARGUMENT;
   1317   if (transport_endpoint->struct_size < sizeof(*transport_endpoint))
   1318     return MOJO_RESULT_INVALID_ARGUMENT;
   1319   if (transport_endpoint->num_platform_handles == 0)
   1320     return MOJO_RESULT_INVALID_ARGUMENT;
   1321   if (!transport_endpoint->platform_handles)
   1322     return MOJO_RESULT_INVALID_ARGUMENT;
   1323   if (transport_endpoint->type != MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL &&
   1324       transport_endpoint->type !=
   1325           MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL_SERVER) {
   1326     return MOJO_RESULT_UNIMPLEMENTED;
   1327   }
   1328 
   1329   scoped_refptr<Dispatcher> dispatcher = GetDispatcher(invitation_handle);
   1330   if (!dispatcher || dispatcher->GetType() != Dispatcher::Type::INVITATION)
   1331     return MOJO_RESULT_INVALID_ARGUMENT;
   1332   auto* invitation_dispatcher =
   1333       static_cast<InvitationDispatcher*>(dispatcher.get());
   1334 
   1335   auto endpoint = PlatformHandle::FromMojoPlatformHandle(
   1336       &transport_endpoint->platform_handles[0]);
   1337   if (!endpoint.is_valid())
   1338     return MOJO_RESULT_INVALID_ARGUMENT;
   1339 
   1340   ConnectionParams connection_params;
   1341 #if defined(OS_WIN) || defined(OS_POSIX)
   1342   if (transport_endpoint->type ==
   1343       MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL_SERVER) {
   1344     connection_params =
   1345         ConnectionParams(PlatformChannelServerEndpoint(std::move(endpoint)));
   1346   }
   1347 #endif
   1348   if (!connection_params.server_endpoint().is_valid()) {
   1349     connection_params =
   1350         ConnectionParams(PlatformChannelEndpoint(std::move(endpoint)));
   1351   }
   1352 
   1353   // At this point everything else has been validated, so we can take ownership
   1354   // of the dispatcher.
   1355   {
   1356     base::AutoLock lock(handles_->GetLock());
   1357     scoped_refptr<Dispatcher> removed_dispatcher;
   1358     MojoResult result = handles_->GetAndRemoveDispatcher(invitation_handle,
   1359                                                          &removed_dispatcher);
   1360     if (result != MOJO_RESULT_OK) {
   1361       // Release ownership of the endpoint platform handle, per the API
   1362       // contract. The caller retains ownership on failure.
   1363       connection_params.TakeEndpoint().TakePlatformHandle().release();
   1364       connection_params.TakeServerEndpoint().TakePlatformHandle().release();
   1365       return result;
   1366     }
   1367     DCHECK_EQ(removed_dispatcher.get(), invitation_dispatcher);
   1368   }
   1369 
   1370   std::vector<std::pair<std::string, ports::PortRef>> attached_ports;
   1371   InvitationDispatcher::PortMapping attached_port_map =
   1372       invitation_dispatcher->TakeAttachedPorts();
   1373   invitation_dispatcher->Close();
   1374   for (auto& entry : attached_port_map)
   1375     attached_ports.emplace_back(entry.first, std::move(entry.second));
   1376 
   1377   bool is_isolated =
   1378       options && (options->flags & MOJO_SEND_INVITATION_FLAG_ISOLATED);
   1379   RequestContext request_context;
   1380   if (is_isolated) {
   1381     DCHECK_EQ(attached_ports.size(), 1u);
   1382     DCHECK_EQ(attached_ports[0].first, kIsolatedInvitationPipeName);
   1383     base::StringPiece connection_name(options->isolated_connection_name,
   1384                                       options->isolated_connection_name_length);
   1385     GetNodeController()->ConnectIsolated(std::move(connection_params),
   1386                                          attached_ports[0].second,
   1387                                          connection_name);
   1388   } else {
   1389     GetNodeController()->SendBrokerClientInvitation(
   1390         target_process, std::move(connection_params), attached_ports,
   1391         process_error_callback);
   1392   }
   1393 
   1394   return MOJO_RESULT_OK;
   1395 }
   1396 
   1397 MojoResult Core::AcceptInvitation(
   1398     const MojoInvitationTransportEndpoint* transport_endpoint,
   1399     const MojoAcceptInvitationOptions* options,
   1400     MojoHandle* invitation_handle) {
   1401   if (options && options->struct_size < sizeof(*options))
   1402     return MOJO_RESULT_INVALID_ARGUMENT;
   1403 
   1404   if (!transport_endpoint)
   1405     return MOJO_RESULT_INVALID_ARGUMENT;
   1406   if (transport_endpoint->struct_size < sizeof(*transport_endpoint))
   1407     return MOJO_RESULT_INVALID_ARGUMENT;
   1408   if (transport_endpoint->num_platform_handles == 0)
   1409     return MOJO_RESULT_INVALID_ARGUMENT;
   1410   if (!transport_endpoint->platform_handles)
   1411     return MOJO_RESULT_INVALID_ARGUMENT;
   1412   if (transport_endpoint->type != MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL &&
   1413       transport_endpoint->type !=
   1414           MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL_SERVER) {
   1415     return MOJO_RESULT_UNIMPLEMENTED;
   1416   }
   1417 
   1418   if (!invitation_handle)
   1419     return MOJO_RESULT_INVALID_ARGUMENT;
   1420   auto dispatcher = base::MakeRefCounted<InvitationDispatcher>();
   1421   *invitation_handle = AddDispatcher(dispatcher);
   1422   if (*invitation_handle == MOJO_HANDLE_INVALID)
   1423     return MOJO_RESULT_RESOURCE_EXHAUSTED;
   1424 
   1425   auto endpoint = PlatformHandle::FromMojoPlatformHandle(
   1426       &transport_endpoint->platform_handles[0]);
   1427   if (!endpoint.is_valid()) {
   1428     Close(*invitation_handle);
   1429     *invitation_handle = MOJO_HANDLE_INVALID;
   1430     return MOJO_RESULT_INVALID_ARGUMENT;
   1431   }
   1432 
   1433   ConnectionParams connection_params;
   1434 #if defined(OS_WIN) || defined(OS_POSIX)
   1435   if (transport_endpoint->type ==
   1436       MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL_SERVER) {
   1437     connection_params =
   1438         ConnectionParams(PlatformChannelServerEndpoint(std::move(endpoint)));
   1439   }
   1440 #endif
   1441   if (!connection_params.server_endpoint().is_valid()) {
   1442     connection_params =
   1443         ConnectionParams(PlatformChannelEndpoint(std::move(endpoint)));
   1444   }
   1445 
   1446   bool is_isolated =
   1447       options && (options->flags & MOJO_ACCEPT_INVITATION_FLAG_ISOLATED);
   1448   NodeController* const node_controller = GetNodeController();
   1449   RequestContext request_context;
   1450   if (is_isolated) {
   1451     // For an isolated invitation, we simply mint a new port pair here and send
   1452     // one name to the remote endpoint while stashing the other in the accepted
   1453     // invitation object for later extraction.
   1454     ports::PortRef local_port;
   1455     ports::PortRef remote_port;
   1456     node_controller->node()->CreatePortPair(&local_port, &remote_port);
   1457     node_controller->ConnectIsolated(std::move(connection_params), remote_port,
   1458                                      base::StringPiece());
   1459     MojoResult result =
   1460         dispatcher->AttachMessagePipe(kIsolatedInvitationPipeName, local_port);
   1461     DCHECK_EQ(MOJO_RESULT_OK, result);
   1462   } else {
   1463     node_controller->AcceptBrokerClientInvitation(std::move(connection_params));
   1464   }
   1465 
   1466   return MOJO_RESULT_OK;
   1467 }
   1468 
   1469 MojoResult Core::SetQuota(MojoHandle handle,
   1470                           MojoQuotaType type,
   1471                           uint64_t limit,
   1472                           const MojoSetQuotaOptions* options) {
   1473   RequestContext request_context;
   1474   if (options && options->struct_size < sizeof(*options))
   1475     return MOJO_RESULT_INVALID_ARGUMENT;
   1476   auto dispatcher = GetDispatcher(handle);
   1477   if (!dispatcher)
   1478     return MOJO_RESULT_INVALID_ARGUMENT;
   1479 
   1480   return dispatcher->SetQuota(type, limit);
   1481 }
   1482 
   1483 MojoResult Core::QueryQuota(MojoHandle handle,
   1484                             MojoQuotaType type,
   1485                             const MojoQueryQuotaOptions* options,
   1486                             uint64_t* limit,
   1487                             uint64_t* usage) {
   1488   RequestContext request_context;
   1489   if (options && options->struct_size < sizeof(*options))
   1490     return MOJO_RESULT_INVALID_ARGUMENT;
   1491   auto dispatcher = GetDispatcher(handle);
   1492   if (!dispatcher)
   1493     return MOJO_RESULT_INVALID_ARGUMENT;
   1494   return dispatcher->QueryQuota(type, limit, usage);
   1495 }
   1496 
   1497 void Core::GetActiveHandlesForTest(std::vector<MojoHandle>* handles) {
   1498   base::AutoLock lock(handles_->GetLock());
   1499   handles_->GetActiveHandlesForTest(handles);
   1500 }
   1501 
   1502 // static
   1503 void Core::PassNodeControllerToIOThread(
   1504     std::unique_ptr<NodeController> node_controller) {
   1505   // It's OK to leak this reference. At this point we know the IO loop is still
   1506   // running, and we know the NodeController will observe its eventual
   1507   // destruction. This tells the NodeController to delete itself when that
   1508   // happens.
   1509   node_controller.release()->DestroyOnIOThreadShutdown();
   1510 }
   1511 
   1512 }  // namespace core
   1513 }  // namespace mojo
   1514