| // Copyright 2013 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "mojo/edk/system/message_pipe_dispatcher.h" |
| |
| #include <utility> |
| |
| #include "base/logging.h" |
| #include "mojo/edk/system/configuration.h" |
| #include "mojo/edk/system/handle_transport.h" |
| #include "mojo/edk/system/local_message_pipe_endpoint.h" |
| #include "mojo/edk/system/memory.h" |
| #include "mojo/edk/system/message_pipe.h" |
| #include "mojo/edk/system/options_validation.h" |
| #include "mojo/edk/system/proxy_message_pipe_endpoint.h" |
| |
| using mojo::platform::ScopedPlatformHandle; |
| using mojo::util::RefPtr; |
| |
| namespace mojo { |
| namespace system { |
| |
| const unsigned kInvalidPort = static_cast<unsigned>(-1); |
| |
| // MessagePipeDispatcher ------------------------------------------------------- |
| |
| // static |
| constexpr MojoHandleRights MessagePipeDispatcher::kDefaultHandleRights; |
| |
| // static |
| const MojoCreateMessagePipeOptions |
| MessagePipeDispatcher::kDefaultCreateOptions = { |
| static_cast<uint32_t>(sizeof(MojoCreateMessagePipeOptions)), |
| MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_NONE}; |
| |
| // static |
| MojoResult MessagePipeDispatcher::ValidateCreateOptions( |
| UserPointer<const MojoCreateMessagePipeOptions> in_options, |
| MojoCreateMessagePipeOptions* out_options) { |
| const MojoCreateMessagePipeOptionsFlags kKnownFlags = |
| MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_NONE; |
| |
| *out_options = kDefaultCreateOptions; |
| if (in_options.IsNull()) |
| return MOJO_RESULT_OK; |
| |
| UserOptionsReader<MojoCreateMessagePipeOptions> reader(in_options); |
| if (!reader.is_valid()) |
| return MOJO_RESULT_INVALID_ARGUMENT; |
| |
| if (!OPTIONS_STRUCT_HAS_MEMBER(MojoCreateMessagePipeOptions, flags, reader)) |
| return MOJO_RESULT_OK; |
| if ((reader.options().flags & ~kKnownFlags)) |
| return MOJO_RESULT_UNIMPLEMENTED; |
| out_options->flags = reader.options().flags; |
| |
| // Checks for fields beyond |flags|: |
| |
| // (Nothing here yet.) |
| |
| return MOJO_RESULT_OK; |
| } |
| |
| void MessagePipeDispatcher::Init(RefPtr<MessagePipe>&& message_pipe, |
| unsigned port) { |
| DCHECK(message_pipe); |
| DCHECK(port == 0 || port == 1); |
| |
| message_pipe_ = std::move(message_pipe); |
| port_ = port; |
| } |
| |
| Dispatcher::Type MessagePipeDispatcher::GetType() const { |
| return Type::MESSAGE_PIPE; |
| } |
| |
| bool MessagePipeDispatcher::SupportsEntrypointClass( |
| EntrypointClass entrypoint_class) const { |
| return (entrypoint_class == EntrypointClass::MESSAGE_PIPE); |
| } |
| |
| // static |
| RefPtr<MessagePipeDispatcher> MessagePipeDispatcher::CreateRemoteMessagePipe( |
| RefPtr<ChannelEndpoint>* channel_endpoint) { |
| auto message_pipe = MessagePipe::CreateLocalProxy(channel_endpoint); |
| auto dispatcher = MessagePipeDispatcher::Create(kDefaultCreateOptions); |
| dispatcher->Init(std::move(message_pipe), 0); |
| return dispatcher; |
| } |
| |
| // static |
| RefPtr<MessagePipeDispatcher> MessagePipeDispatcher::Deserialize( |
| Channel* channel, |
| const void* source, |
| size_t size) { |
| unsigned port = kInvalidPort; |
| RefPtr<MessagePipe> message_pipe; |
| if (!MessagePipe::Deserialize(channel, source, size, &message_pipe, &port)) |
| return nullptr; |
| DCHECK(message_pipe); |
| DCHECK(port == 0 || port == 1); |
| |
| auto dispatcher = MessagePipeDispatcher::Create(kDefaultCreateOptions); |
| dispatcher->Init(std::move(message_pipe), port); |
| return dispatcher; |
| } |
| |
| MessagePipeDispatcher::MessagePipeDispatcher() : port_(kInvalidPort) { |
| } |
| |
| MessagePipeDispatcher::~MessagePipeDispatcher() { |
| // |Close()|/|CloseImplNoLock()| should have taken care of the pipe. |
| DCHECK(!message_pipe_); |
| } |
| |
| MessagePipe* MessagePipeDispatcher::GetMessagePipeNoLock() const { |
| mutex().AssertHeld(); |
| return message_pipe_.get(); |
| } |
| |
| unsigned MessagePipeDispatcher::GetPortNoLock() const { |
| mutex().AssertHeld(); |
| return port_; |
| } |
| |
| void MessagePipeDispatcher::CancelAllAwakablesNoLock() { |
| mutex().AssertHeld(); |
| message_pipe_->CancelAllAwakables(port_); |
| } |
| |
| void MessagePipeDispatcher::CloseImplNoLock() { |
| mutex().AssertHeld(); |
| message_pipe_->Close(port_); |
| message_pipe_ = nullptr; |
| port_ = kInvalidPort; |
| } |
| |
| RefPtr<Dispatcher> |
| MessagePipeDispatcher::CreateEquivalentDispatcherAndCloseImplNoLock( |
| MessagePipe* message_pipe, |
| unsigned port) { |
| mutex().AssertHeld(); |
| |
| // "We" are being sent over our peer. |
| if (message_pipe == message_pipe_.get()) { |
| // A message pipe dispatcher can't be sent over itself (this should be |
| // disallowed by |Core|). Note that |port| is the destination port. |
| DCHECK_EQ(port, port_); |
| // In this case, |message_pipe_|'s mutex should already be held! |
| message_pipe_->CancelAllAwakablesNoLock(port_); |
| } else { |
| CancelAllAwakablesNoLock(); |
| } |
| |
| // TODO(vtl): Currently, there are no options, so we just use |
| // |kDefaultCreateOptions|. Eventually, we'll have to duplicate the options |
| // too. |
| auto dispatcher = MessagePipeDispatcher::Create(kDefaultCreateOptions); |
| dispatcher->Init(std::move(message_pipe_), port_); |
| port_ = kInvalidPort; |
| return dispatcher; |
| } |
| |
| MojoResult MessagePipeDispatcher::WriteMessageImplNoLock( |
| UserPointer<const void> bytes, |
| uint32_t num_bytes, |
| std::vector<HandleTransport>* transports, |
| MojoWriteMessageFlags flags) { |
| DCHECK(!transports || |
| (transports->size() > 0 && |
| transports->size() <= GetConfiguration().max_message_num_handles)); |
| |
| mutex().AssertHeld(); |
| |
| if (num_bytes > GetConfiguration().max_message_num_bytes) |
| return MOJO_RESULT_RESOURCE_EXHAUSTED; |
| |
| return message_pipe_->WriteMessage(port_, bytes, num_bytes, transports, |
| flags); |
| } |
| |
| MojoResult MessagePipeDispatcher::ReadMessageImplNoLock( |
| UserPointer<void> bytes, |
| UserPointer<uint32_t> num_bytes, |
| HandleVector* handles, |
| uint32_t* num_handles, |
| MojoReadMessageFlags flags) { |
| mutex().AssertHeld(); |
| return message_pipe_->ReadMessage(port_, bytes, num_bytes, handles, |
| num_handles, flags); |
| } |
| |
| HandleSignalsState MessagePipeDispatcher::GetHandleSignalsStateImplNoLock() |
| const { |
| mutex().AssertHeld(); |
| return message_pipe_->GetHandleSignalsState(port_); |
| } |
| |
| MojoResult MessagePipeDispatcher::AddAwakableImplNoLock( |
| Awakable* awakable, |
| MojoHandleSignals signals, |
| uint32_t context, |
| HandleSignalsState* signals_state) { |
| mutex().AssertHeld(); |
| return message_pipe_->AddAwakable(port_, awakable, signals, context, |
| signals_state); |
| } |
| |
| void MessagePipeDispatcher::RemoveAwakableImplNoLock( |
| Awakable* awakable, |
| HandleSignalsState* signals_state) { |
| mutex().AssertHeld(); |
| message_pipe_->RemoveAwakable(port_, awakable, signals_state); |
| } |
| |
| void MessagePipeDispatcher::StartSerializeImplNoLock( |
| Channel* channel, |
| size_t* max_size, |
| size_t* max_platform_handles) { |
| AssertHasOneRef(); // Only one ref => no need to take the lock. |
| return message_pipe_->StartSerialize(port_, channel, max_size, |
| max_platform_handles); |
| } |
| |
| bool MessagePipeDispatcher::EndSerializeAndCloseImplNoLock( |
| Channel* channel, |
| void* destination, |
| size_t* actual_size, |
| std::vector<ScopedPlatformHandle>* platform_handles) { |
| AssertHasOneRef(); // Only one ref => no need to take the lock. |
| |
| bool rv = message_pipe_->EndSerialize(port_, channel, destination, |
| actual_size, platform_handles); |
| message_pipe_ = nullptr; |
| port_ = kInvalidPort; |
| return rv; |
| } |
| |
| } // namespace system |
| } // namespace mojo |