// 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 "base/logging.h" #include "mojo/edk/system/configuration.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" namespace mojo { namespace system { const unsigned kInvalidPort = static_cast(-1); // MessagePipeDispatcher ------------------------------------------------------- // static const MojoCreateMessagePipeOptions MessagePipeDispatcher::kDefaultCreateOptions = { static_cast(sizeof(MojoCreateMessagePipeOptions)), MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_NONE}; MessagePipeDispatcher::MessagePipeDispatcher( const MojoCreateMessagePipeOptions& /*validated_options*/) : port_(kInvalidPort) { } // static MojoResult MessagePipeDispatcher::ValidateCreateOptions( UserPointer 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 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(scoped_refptr message_pipe, unsigned port) { DCHECK(message_pipe.get()); DCHECK(port == 0 || port == 1); message_pipe_ = message_pipe; port_ = port; } Dispatcher::Type MessagePipeDispatcher::GetType() const { return kTypeMessagePipe; } // static scoped_refptr MessagePipeDispatcher::CreateRemoteMessagePipe( scoped_refptr* channel_endpoint) { scoped_refptr message_pipe( MessagePipe::CreateLocalProxy(channel_endpoint)); scoped_refptr dispatcher( new MessagePipeDispatcher(MessagePipeDispatcher::kDefaultCreateOptions)); dispatcher->Init(message_pipe, 0); return dispatcher; } // static scoped_refptr MessagePipeDispatcher::Deserialize( Channel* channel, const void* source, size_t size) { unsigned port = kInvalidPort; scoped_refptr message_pipe; if (!MessagePipe::Deserialize(channel, source, size, &message_pipe, &port)) return nullptr; DCHECK(message_pipe.get()); DCHECK(port == 0 || port == 1); scoped_refptr dispatcher( new MessagePipeDispatcher(MessagePipeDispatcher::kDefaultCreateOptions)); dispatcher->Init(message_pipe, port); return dispatcher; } MessagePipeDispatcher::~MessagePipeDispatcher() { // |Close()|/|CloseImplNoLock()| should have taken care of the pipe. DCHECK(!message_pipe_.get()); } MessagePipe* MessagePipeDispatcher::GetMessagePipeNoLock() const { lock().AssertAcquired(); return message_pipe_.get(); } unsigned MessagePipeDispatcher::GetPortNoLock() const { lock().AssertAcquired(); return port_; } void MessagePipeDispatcher::CancelAllWaitersNoLock() { lock().AssertAcquired(); message_pipe_->CancelAllWaiters(port_); } void MessagePipeDispatcher::CloseImplNoLock() { lock().AssertAcquired(); message_pipe_->Close(port_); message_pipe_ = nullptr; port_ = kInvalidPort; } scoped_refptr MessagePipeDispatcher::CreateEquivalentDispatcherAndCloseImplNoLock() { lock().AssertAcquired(); // TODO(vtl): Currently, there are no options, so we just use // |kDefaultCreateOptions|. Eventually, we'll have to duplicate the options // too. scoped_refptr rv = new MessagePipeDispatcher(kDefaultCreateOptions); rv->Init(message_pipe_, port_); message_pipe_ = nullptr; port_ = kInvalidPort; return scoped_refptr(rv.get()); } MojoResult MessagePipeDispatcher::WriteMessageImplNoLock( UserPointer bytes, uint32_t num_bytes, std::vector* transports, MojoWriteMessageFlags flags) { DCHECK(!transports || (transports->size() > 0 && transports->size() <= GetConfiguration().max_message_num_handles)); lock().AssertAcquired(); 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 bytes, UserPointer num_bytes, DispatcherVector* dispatchers, uint32_t* num_dispatchers, MojoReadMessageFlags flags) { lock().AssertAcquired(); return message_pipe_->ReadMessage(port_, bytes, num_bytes, dispatchers, num_dispatchers, flags); } HandleSignalsState MessagePipeDispatcher::GetHandleSignalsStateImplNoLock() const { lock().AssertAcquired(); return message_pipe_->GetHandleSignalsState(port_); } MojoResult MessagePipeDispatcher::AddWaiterImplNoLock( Waiter* waiter, MojoHandleSignals signals, uint32_t context, HandleSignalsState* signals_state) { lock().AssertAcquired(); return message_pipe_->AddWaiter(port_, waiter, signals, context, signals_state); } void MessagePipeDispatcher::RemoveWaiterImplNoLock( Waiter* waiter, HandleSignalsState* signals_state) { lock().AssertAcquired(); message_pipe_->RemoveWaiter(port_, waiter, signals_state); } void MessagePipeDispatcher::StartSerializeImplNoLock( Channel* channel, size_t* max_size, size_t* max_platform_handles) { DCHECK(HasOneRef()); // 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, embedder::PlatformHandleVector* platform_handles) { DCHECK(HasOneRef()); // 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; } // MessagePipeDispatcherTransport ---------------------------------------------- MessagePipeDispatcherTransport::MessagePipeDispatcherTransport( DispatcherTransport transport) : DispatcherTransport(transport) { DCHECK_EQ(message_pipe_dispatcher()->GetType(), Dispatcher::kTypeMessagePipe); } } // namespace system } // namespace mojo