• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
InvokeProcessErrorCallbackOnTaskRunner(scoped_refptr<base::TaskRunner> task_runner,MojoProcessErrorHandler handler,uintptr_t context,const std::string & error,MojoProcessErrorFlags flags)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:
ProcessDisconnectHandler(scoped_refptr<base::TaskRunner> task_runner,MojoProcessErrorHandler handler,uintptr_t context)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 
~ProcessDisconnectHandler()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 
RunMojoProcessErrorHandler(ProcessDisconnectHandler * disconnect_handler,scoped_refptr<base::TaskRunner> task_runner,MojoProcessErrorHandler handler,uintptr_t context,const std::string & error)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 
Core()128 Core::Core() {
129   handles_.reset(new HandleTable);
130   // base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
131   //     handles_.get(), "MojoHandleTable", nullptr);
132 }
133 
~Core()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 
SetIOTaskRunner(scoped_refptr<base::TaskRunner> io_task_runner)149 void Core::SetIOTaskRunner(scoped_refptr<base::TaskRunner> io_task_runner) {
150   GetNodeController()->SetIOTaskRunner(io_task_runner);
151 }
152 
GetNodeController()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 
GetDispatcher(MojoHandle handle)160 scoped_refptr<Dispatcher> Core::GetDispatcher(MojoHandle handle) {
161   base::AutoLock lock(handles_->GetLock());
162   return handles_->GetDispatcher(handle);
163 }
164 
GetAndRemoveDispatcher(MojoHandle handle)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 
SetDefaultProcessErrorCallback(const ProcessErrorCallback & callback)172 void Core::SetDefaultProcessErrorCallback(
173     const ProcessErrorCallback& callback) {
174   default_process_error_callback_ = callback;
175 }
176 
CreatePartialMessagePipe(ports::PortRef * peer)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 
CreatePartialMessagePipe(const ports::PortRef & port)185 MojoHandle Core::CreatePartialMessagePipe(const ports::PortRef& port) {
186   RequestContext request_context;
187   return AddDispatcher(new MessagePipeDispatcher(GetNodeController(), port,
188                                                  kUnknownPipeIdForDebug, 1));
189 }
190 
SendBrokerClientInvitation(base::ProcessHandle target_process,ConnectionParams connection_params,const std::vector<std::pair<std::string,ports::PortRef>> & attached_ports,const ProcessErrorCallback & process_error_callback)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 
AcceptBrokerClientInvitation(ConnectionParams connection_params)202 void Core::AcceptBrokerClientInvitation(ConnectionParams connection_params) {
203   RequestContext request_context;
204   GetNodeController()->AcceptBrokerClientInvitation(
205       std::move(connection_params));
206 }
207 
ConnectIsolated(ConnectionParams connection_params,const ports::PortRef & port,base::StringPiece connection_name)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 
SetMachPortProvider(base::PortProvider * port_provider)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)
GetMachPortRelay()223 MachPortRelay* Core::GetMachPortRelay() {
224   return GetNodeController()->GetMachPortRelay();
225 }
226 #endif
227 
AddDispatcher(scoped_refptr<Dispatcher> dispatcher)228 MojoHandle Core::AddDispatcher(scoped_refptr<Dispatcher> dispatcher) {
229   base::AutoLock lock(handles_->GetLock());
230   return handles_->AddDispatcher(dispatcher);
231 }
232 
AddDispatchersFromTransit(const std::vector<Dispatcher::DispatcherInTransit> & dispatchers,MojoHandle * handles)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 
AcquireDispatchersForTransit(const MojoHandle * handles,size_t num_handles,std::vector<Dispatcher::DispatcherInTransit> * dispatchers)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 
ReleaseDispatchersForTransit(const std::vector<Dispatcher::DispatcherInTransit> & dispatchers,bool in_transit)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 
RequestShutdown(const base::Closure & callback)273 void Core::RequestShutdown(const base::Closure& callback) {
274   GetNodeController()->RequestShutdown(callback);
275 }
276 
ExtractMessagePipeFromInvitation(const std::string & name)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 
GetTimeTicksNow()287 MojoTimeTicks Core::GetTimeTicksNow() {
288   return base::TimeTicks::Now().ToInternalValue();
289 }
290 
Close(MojoHandle handle)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 
QueryHandleSignalsState(MojoHandle handle,MojoHandleSignalsState * signals_state)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 
CreateTrap(MojoTrapEventHandler handler,const MojoCreateTrapOptions * options,MojoHandle * trap_handle)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 
AddTrigger(MojoHandle trap_handle,MojoHandle handle,MojoHandleSignals signals,MojoTriggerCondition condition,uintptr_t context,const MojoAddTriggerOptions * options)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 
RemoveTrigger(MojoHandle trap_handle,uintptr_t context,const MojoRemoveTriggerOptions * options)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 
ArmTrap(MojoHandle trap_handle,const MojoArmTrapOptions * options,uint32_t * num_blocking_events,MojoTrapEvent * blocking_events)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 
CreateMessage(const MojoCreateMessageOptions * options,MojoMessageHandle * message_handle)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 
DestroyMessage(MojoMessageHandle message_handle)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 
SerializeMessage(MojoMessageHandle message_handle,const MojoSerializeMessageOptions * options)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 
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)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 
GetMessageData(MojoMessageHandle message_handle,const MojoGetMessageDataOptions * options,void ** buffer,uint32_t * num_bytes,MojoHandle * handles,uint32_t * num_handles)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 
SetMessageContext(MojoMessageHandle message_handle,uintptr_t context,MojoMessageContextSerializer serializer,MojoMessageContextDestructor destructor,const MojoSetMessageContextOptions * options)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 
GetMessageContext(MojoMessageHandle message_handle,const MojoGetMessageContextOptions * options,uintptr_t * context)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 
CreateMessagePipe(const MojoCreateMessagePipeOptions * options,MojoHandle * message_pipe_handle0,MojoHandle * message_pipe_handle1)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 
WriteMessage(MojoHandle message_pipe_handle,MojoMessageHandle message_handle,const MojoWriteMessageOptions * options)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 
ReadMessage(MojoHandle message_pipe_handle,const MojoReadMessageOptions * options,MojoMessageHandle * message_handle)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 
FuseMessagePipes(MojoHandle handle0,MojoHandle handle1,const MojoFuseMessagePipesOptions * options)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 
NotifyBadMessage(MojoMessageHandle message_handle,const char * error,size_t error_num_bytes,const MojoNotifyBadMessageOptions * options)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 
CreateDataPipe(const MojoCreateDataPipeOptions * options,MojoHandle * data_pipe_producer_handle,MojoHandle * data_pipe_consumer_handle)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 
WriteData(MojoHandle data_pipe_producer_handle,const void * elements,uint32_t * num_bytes,const MojoWriteDataOptions * options)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 
BeginWriteData(MojoHandle data_pipe_producer_handle,const MojoBeginWriteDataOptions * options,void ** buffer,uint32_t * buffer_num_bytes)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 
EndWriteData(MojoHandle data_pipe_producer_handle,uint32_t num_bytes_written,const MojoEndWriteDataOptions * options)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 
ReadData(MojoHandle data_pipe_consumer_handle,const MojoReadDataOptions * options,void * elements,uint32_t * num_bytes)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 
BeginReadData(MojoHandle data_pipe_consumer_handle,const MojoBeginReadDataOptions * options,const void ** buffer,uint32_t * buffer_num_bytes)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 
EndReadData(MojoHandle data_pipe_consumer_handle,uint32_t num_bytes_read,const MojoEndReadDataOptions * options)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 
CreateSharedBuffer(uint64_t num_bytes,const MojoCreateSharedBufferOptions * options,MojoHandle * shared_buffer_handle)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 
DuplicateBufferHandle(MojoHandle buffer_handle,const MojoDuplicateBufferHandleOptions * options,MojoHandle * new_buffer_handle)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 
MapBuffer(MojoHandle buffer_handle,uint64_t offset,uint64_t num_bytes,const MojoMapBufferOptions * options,void ** buffer)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 
UnmapBuffer(void * buffer)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 
GetBufferInfo(MojoHandle buffer_handle,const MojoGetBufferInfoOptions * options,MojoSharedBufferInfo * info)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 
WrapPlatformHandle(const MojoPlatformHandle * platform_handle,const MojoWrapPlatformHandleOptions * options,MojoHandle * mojo_handle)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 
UnwrapPlatformHandle(MojoHandle mojo_handle,const MojoUnwrapPlatformHandleOptions * options,MojoPlatformHandle * platform_handle)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 
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)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 
UnwrapPlatformSharedMemoryRegion(MojoHandle mojo_handle,const MojoUnwrapPlatformSharedMemoryRegionOptions * options,MojoPlatformHandle * platform_handles,uint32_t * num_platform_handles,uint64_t * size,MojoSharedBufferGuid * guid,MojoPlatformSharedMemoryRegionAccessMode * access_mode)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 
CreateInvitation(const MojoCreateInvitationOptions * options,MojoHandle * invitation_handle)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 
AttachMessagePipeToInvitation(MojoHandle invitation_handle,const void * name,uint32_t name_num_bytes,const MojoAttachMessagePipeToInvitationOptions * options,MojoHandle * message_pipe_handle)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 
ExtractMessagePipeFromInvitation(MojoHandle invitation_handle,const void * name,uint32_t name_num_bytes,const MojoExtractMessagePipeFromInvitationOptions * options,MojoHandle * message_pipe_handle)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 
SendInvitation(MojoHandle invitation_handle,const MojoPlatformProcessHandle * process_handle,const MojoInvitationTransportEndpoint * transport_endpoint,MojoProcessErrorHandler error_handler,uintptr_t error_handler_context,const MojoSendInvitationOptions * options)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 
AcceptInvitation(const MojoInvitationTransportEndpoint * transport_endpoint,const MojoAcceptInvitationOptions * options,MojoHandle * invitation_handle)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 
SetQuota(MojoHandle handle,MojoQuotaType type,uint64_t limit,const MojoSetQuotaOptions * options)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 
QueryQuota(MojoHandle handle,MojoQuotaType type,const MojoQueryQuotaOptions * options,uint64_t * limit,uint64_t * usage)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 
GetActiveHandlesForTest(std::vector<MojoHandle> * handles)1497 void Core::GetActiveHandlesForTest(std::vector<MojoHandle>* handles) {
1498   base::AutoLock lock(handles_->GetLock());
1499   handles_->GetActiveHandlesForTest(handles);
1500 }
1501 
1502 // static
PassNodeControllerToIOThread(std::unique_ptr<NodeController> node_controller)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