| Index: mojo/public/cpp/bindings/lib/multiplex_router.h
|
| diff --git a/mojo/public/cpp/bindings/lib/multiplex_router.h b/mojo/public/cpp/bindings/lib/multiplex_router.h
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..d9e7323b31395300f5e4f6dba2fae4ed16d26a68
|
| --- /dev/null
|
| +++ b/mojo/public/cpp/bindings/lib/multiplex_router.h
|
| @@ -0,0 +1,207 @@
|
| +// Copyright 2015 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.
|
| +
|
| +#ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_MULTIPLEX_ROUTER_H_
|
| +#define MOJO_PUBLIC_CPP_BINDINGS_LIB_MULTIPLEX_ROUTER_H_
|
| +
|
| +#include <deque>
|
| +#include <map>
|
| +
|
| +#include "base/logging.h"
|
| +#include "base/macros.h"
|
| +#include "base/memory/ref_counted.h"
|
| +#include "base/memory/ref_counted_delete_on_message_loop.h"
|
| +#include "base/memory/scoped_ptr.h"
|
| +#include "base/memory/weak_ptr.h"
|
| +#include "base/synchronization/lock.h"
|
| +#include "base/threading/thread_checker.h"
|
| +#include "mojo/public/cpp/bindings/callback.h"
|
| +#include "mojo/public/cpp/bindings/lib/connector.h"
|
| +#include "mojo/public/cpp/bindings/lib/interface_id.h"
|
| +#include "mojo/public/cpp/bindings/lib/message_header_validator.h"
|
| +#include "mojo/public/cpp/bindings/lib/pipe_control_message_handler.h"
|
| +#include "mojo/public/cpp/bindings/lib/pipe_control_message_handler_delegate.h"
|
| +#include "mojo/public/cpp/bindings/lib/pipe_control_message_proxy.h"
|
| +#include "mojo/public/cpp/bindings/lib/scoped_interface_endpoint_handle.h"
|
| +#include "mojo/public/cpp/environment/environment.h"
|
| +
|
| +namespace mojo {
|
| +namespace internal {
|
| +
|
| +class InterfaceEndpointClient;
|
| +
|
| +// MultiplexRouter supports routing messages for multiple interfaces over a
|
| +// single message pipe.
|
| +//
|
| +// It is created on the thread where the master interface of the message pipe
|
| +// lives. Although it is ref-counted, it is guarateed to be destructed on the
|
| +// same thread.
|
| +// Some public methods are only allowed to be called on the creating thread;
|
| +// while the others are safe to call from any threads. Please see the method
|
| +// comments for more details.
|
| +class MultiplexRouter
|
| + : public MessageReceiver,
|
| + public base::RefCountedDeleteOnMessageLoop<MultiplexRouter>,
|
| + public PipeControlMessageHandlerDelegate {
|
| + public:
|
| + // If |set_interface_id_namespace_bit| is true, the interface IDs generated by
|
| + // this router will have the highest bit set.
|
| + MultiplexRouter(
|
| + bool set_interface_id_namespace_bit,
|
| + ScopedMessagePipeHandle message_pipe,
|
| + const MojoAsyncWaiter* waiter = Environment::GetDefaultAsyncWaiter());
|
| +
|
| + // ---------------------------------------------------------------------------
|
| + // The following public methods are safe to call from any threads.
|
| +
|
| + // Creates a pair of interface endpoint handles. The method generates a new
|
| + // interface ID and assigns it to the two handles. |local_endpoint| is used
|
| + // locally; while |remote_endpoint| is sent over the message pipe.
|
| + void CreateEndpointHandlePair(ScopedInterfaceEndpointHandle* local_endpoint,
|
| + ScopedInterfaceEndpointHandle* remote_endpoint);
|
| +
|
| + // Creates an interface endpoint handle from a given interface ID. The handle
|
| + // is used locally.
|
| + // Typically, this method is used to (1) create an endpoint handle for the
|
| + // master interface; or (2) create an endpoint handle on receiving an
|
| + // interface ID from the message pipe.
|
| + ScopedInterfaceEndpointHandle CreateLocalEndpointHandle(InterfaceId id);
|
| +
|
| + // Closes an interface endpoint handle.
|
| + void CloseEndpointHandle(InterfaceId id, bool is_local);
|
| +
|
| + // Attaches an client to the specified endpoint to send and receive messages.
|
| + void AttachEndpointClient(const ScopedInterfaceEndpointHandle& handle,
|
| + InterfaceEndpointClient* endpoint_client);
|
| + // Detaches the client attached to the specified endpoint. It should be called
|
| + // on the same thread as the corresponding AttachEndpointClient() call.
|
| + void DetachEndpointClient(const ScopedInterfaceEndpointHandle& handle);
|
| +
|
| + bool SendMessage(const ScopedInterfaceEndpointHandle& handle,
|
| + Message* message);
|
| +
|
| + // Raises an error on the underlying message pipe. It disconnects the pipe
|
| + // and notifies all interfaces running on this pipe.
|
| + void RaiseError();
|
| +
|
| + // ---------------------------------------------------------------------------
|
| + // The following public methods are called on the creating thread.
|
| +
|
| + // Please note that this method shouldn't be called unless it results from an
|
| + // explicit request of the user of bindings (e.g., the user sets an
|
| + // InterfacePtr to null or closes a Binding).
|
| + void CloseMessagePipe() {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + connector_.CloseMessagePipe();
|
| + }
|
| +
|
| + // Extracts the underlying message pipe.
|
| + //
|
| + // TODO(yzshen): For now, users need to make sure there is no one holding on
|
| + // to associated interface endpoint handles at both sides of the message pipe
|
| + // in order to call this method. We need a way to forcefully invalidate
|
| + // associated interface endpoint handles.
|
| + ScopedMessagePipeHandle PassMessagePipe();
|
| +
|
| + // Blocks the current thread until the first incoming message, or |deadline|.
|
| + bool WaitForIncomingMessage(MojoDeadline deadline) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + return connector_.WaitForIncomingMessage(deadline);
|
| + }
|
| +
|
| + // See Binding for details of pause/resume.
|
| + void PauseIncomingMethodCallProcessing() {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + connector_.PauseIncomingMethodCallProcessing();
|
| + }
|
| + void ResumeIncomingMethodCallProcessing() {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + connector_.ResumeIncomingMethodCallProcessing();
|
| + }
|
| +
|
| + // Sets this object to testing mode.
|
| + // In testing mode, the object doesn't disconnect the underlying message pipe
|
| + // when it receives unexpected or invalid messages.
|
| + void EnableTestingMode();
|
| +
|
| + // Is the router bound to a message pipe handle?
|
| + bool is_valid() const {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + return connector_.is_valid();
|
| + }
|
| +
|
| + private:
|
| + friend class base::RefCountedDeleteOnMessageLoop<MultiplexRouter>;
|
| + friend class base::DeleteHelper<MultiplexRouter>;
|
| +
|
| + class InterfaceEndpoint;
|
| + struct Task;
|
| +
|
| + ~MultiplexRouter() override;
|
| +
|
| + // MessageReceiver implementation:
|
| + bool Accept(Message* message) override;
|
| +
|
| + // PipeControlMessageHandlerDelegate implementation:
|
| + bool OnPeerAssociatedEndpointClosed(InterfaceId id) override;
|
| + bool OnAssociatedEndpointClosedBeforeSent(InterfaceId id) override;
|
| +
|
| + void OnPipeConnectionError();
|
| +
|
| + // Processes enqueued tasks (incoming messages and error notifications).
|
| + // If |force_async| is true, it guarantees not to call any
|
| + // InterfaceEndpointClient methods directly.
|
| + //
|
| + // Note: Because calling into InterfaceEndpointClient may lead to destruction
|
| + // of this object, if |force_async| is set to false, the caller needs to hold
|
| + // on to a ref outside of |lock_| before calling this method.
|
| + void ProcessTasks(bool force_async);
|
| +
|
| + // Returns true to indicate that |task| has been processed. Otherwise the task
|
| + // will be added back to the front of the queue.
|
| + // |*force_async| may be set to true to force subsequent tasks being processed
|
| + // in an asynchronous manner.
|
| + bool ProcessNotifyErrorTask(Task* task, bool* force_async);
|
| + bool ProcessIncomingMessageTask(Task* task, bool* force_async);
|
| +
|
| + void LockAndCallProcessTasks();
|
| +
|
| + // Updates the state of |endpoint|. If both the endpoint and its peer have
|
| + // been closed, removes it from |endpoints_|.
|
| + // NOTE: The method may invalidate |endpoint|.
|
| + enum EndpointStateUpdateType { ENDPOINT_CLOSED, PEER_ENDPOINT_CLOSED };
|
| + void UpdateEndpointStateMayRemove(InterfaceEndpoint* endpoint,
|
| + EndpointStateUpdateType type);
|
| +
|
| + void RaiseErrorInNonTestingMode();
|
| +
|
| + // Whether to set the namespace bit when generating interface IDs. Please see
|
| + // comments of kInterfaceIdNamespaceMask.
|
| + const bool set_interface_id_namespace_bit_;
|
| +
|
| + MessageHeaderValidator header_validator_;
|
| + Connector connector_;
|
| + bool encountered_error_;
|
| +
|
| + base::ThreadChecker thread_checker_;
|
| +
|
| + // Protects the following members.
|
| + mutable base::Lock lock_;
|
| + PipeControlMessageHandler control_message_handler_;
|
| + PipeControlMessageProxy control_message_proxy_;
|
| +
|
| + std::map<InterfaceId, scoped_refptr<InterfaceEndpoint>> endpoints_;
|
| + uint32_t next_interface_id_value_;
|
| +
|
| + std::deque<scoped_ptr<Task>> tasks_;
|
| +
|
| + bool testing_mode_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(MultiplexRouter);
|
| +};
|
| +
|
| +} // namespace internal
|
| +} // namespace mojo
|
| +
|
| +#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_MULTIPLEX_ROUTER_H_
|
|
|