Index: mojo/edk/system/ports/node.h |
diff --git a/mojo/edk/system/ports/node.h b/mojo/edk/system/ports/node.h |
new file mode 100644 |
index 0000000000000000000000000000000000000000..410d53b7ec1e76117cb23a3a682fc8294bf758df |
--- /dev/null |
+++ b/mojo/edk/system/ports/node.h |
@@ -0,0 +1,192 @@ |
+// Copyright 2016 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_EDK_SYSTEM_PORTS_NODE_H_ |
+#define MOJO_EDK_SYSTEM_PORTS_NODE_H_ |
+ |
+#include <stddef.h> |
+#include <stdint.h> |
+ |
+#include <queue> |
+#include <unordered_map> |
+ |
+#include "base/macros.h" |
+#include "base/memory/ref_counted.h" |
+#include "base/synchronization/lock.h" |
+#include "mojo/edk/system/ports/event.h" |
+#include "mojo/edk/system/ports/hash_functions.h" |
+#include "mojo/edk/system/ports/message.h" |
+#include "mojo/edk/system/ports/name.h" |
+#include "mojo/edk/system/ports/port.h" |
+#include "mojo/edk/system/ports/port_ref.h" |
+#include "mojo/edk/system/ports/user_data.h" |
+ |
+#undef SendMessage // Gah, windows |
+ |
+namespace mojo { |
+namespace edk { |
+namespace ports { |
+ |
+enum : int { |
+ OK = 0, |
+ ERROR_PORT_UNKNOWN = -10, |
+ ERROR_PORT_EXISTS = -11, |
+ ERROR_PORT_STATE_UNEXPECTED = -12, |
+ ERROR_PORT_CANNOT_SEND_SELF = -13, |
+ ERROR_PORT_PEER_CLOSED = -14, |
+ ERROR_PORT_CANNOT_SEND_PEER = -15, |
+ ERROR_NOT_IMPLEMENTED = -100, |
+}; |
+ |
+struct PortStatus { |
+ bool has_messages; |
+ bool receiving_messages; |
+ bool peer_closed; |
+}; |
+ |
+class NodeDelegate; |
+ |
+class Node { |
+ public: |
+ // Does not take ownership of the delegate. |
+ Node(const NodeName& name, NodeDelegate* delegate); |
+ ~Node(); |
+ |
+ // Returns true iff there are no open ports referring to another node or ports |
+ // in the process of being transferred from this node to another. If this |
+ // returns false, then to ensure clean shutdown, it is necessary to keep the |
+ // node alive and continue routing messages to it via AcceptMessage. This |
+ // method may be called again after AcceptMessage to check if the Node is now |
+ // ready to be destroyed. |
+ // |
+ // If |allow_local_ports| is |true|, this will only return |false| when there |
+ // are transient ports referring to other nodes. |
+ bool CanShutdownCleanly(bool allow_local_ports); |
+ |
+ // Lookup the named port. |
+ int GetPort(const PortName& port_name, PortRef* port_ref); |
+ |
+ // Creates a port on this node. Before the port can be used, it must be |
+ // initialized using InitializePort. This method is useful for bootstrapping |
+ // a connection between two nodes. Generally, ports are created using |
+ // CreatePortPair instead. |
+ int CreateUninitializedPort(PortRef* port_ref); |
+ |
+ // Initializes a newly created port. |
+ int InitializePort(const PortRef& port_ref, |
+ const NodeName& peer_node_name, |
+ const PortName& peer_port_name); |
+ |
+ // Generates a new connected pair of ports bound to this node. These ports |
+ // are initialized and ready to go. |
+ int CreatePortPair(PortRef* port0_ref, PortRef* port1_ref); |
+ |
+ // User data associated with the port. |
+ int SetUserData(const PortRef& port_ref, |
+ const scoped_refptr<UserData>& user_data); |
+ int GetUserData(const PortRef& port_ref, |
+ scoped_refptr<UserData>* user_data); |
+ |
+ // Prevents further messages from being sent from this port or delivered to |
+ // this port. The port is removed, and the port's peer is notified of the |
+ // closure after it has consumed all pending messages. |
+ int ClosePort(const PortRef& port_ref); |
+ |
+ // Returns the current status of the port. |
+ int GetStatus(const PortRef& port_ref, PortStatus* port_status); |
+ |
+ // Returns the next available message on the specified port or returns a null |
+ // message if there are none available. Returns ERROR_PORT_PEER_CLOSED to |
+ // indicate that this port's peer has closed. In such cases GetMessage may |
+ // be called until it yields a null message, indicating that no more messages |
+ // may be read from the port. |
+ int GetMessage(const PortRef& port_ref, ScopedMessage* message); |
+ |
+ // Like GetMessage, but the caller may optionally supply a selector function |
+ // that decides whether or not to return the message. If |selector| is a |
+ // nullptr, then GetMessageIf acts just like GetMessage. The |selector| may |
+ // not call any Node methods. |
+ int GetMessageIf(const PortRef& port_ref, |
+ std::function<bool(const Message&)> selector, |
+ ScopedMessage* message); |
+ |
+ // Sends a message from the specified port to its peer. Note that the message |
+ // notification may arrive synchronously (via PortStatusChanged() on the |
+ // delegate) if the peer is local to this Node. |
+ // |
+ // If send fails for any reason, |message| is left unchanged. On success, |
+ // ownserhip is transferred and |message| is reset. |
+ int SendMessage(const PortRef& port_ref, ScopedMessage* message); |
+ |
+ // Corresponding to NodeDelegate::ForwardMessage. |
+ int AcceptMessage(ScopedMessage message); |
+ |
+ // Called to inform this node that communication with another node is lost |
+ // indefinitely. This triggers cleanup of ports bound to this node. |
+ int LostConnectionToNode(const NodeName& node_name); |
+ |
+ private: |
+ int OnUserMessage(ScopedMessage message); |
+ int OnPortAccepted(const PortName& port_name); |
+ int OnObserveProxy(const PortName& port_name, |
+ const ObserveProxyEventData& event); |
+ int OnObserveProxyAck(const PortName& port_name, uint64_t last_sequence_num); |
+ int OnObserveClosure(const PortName& port_name, uint64_t last_sequence_num); |
+ |
+ int AddPortWithName(const PortName& port_name, |
+ const scoped_refptr<Port>& port); |
+ void ErasePort(const PortName& port_name); |
+ void ErasePort_Locked(const PortName& port_name); |
+ scoped_refptr<Port> GetPort(const PortName& port_name); |
+ scoped_refptr<Port> GetPort_Locked(const PortName& port_name); |
+ |
+ void WillSendPort_Locked(Port* port, |
+ const NodeName& to_node_name, |
+ PortName* port_name, |
+ PortDescriptor* port_descriptor); |
+ int AcceptPort(const PortName& port_name, |
+ const PortDescriptor& port_descriptor); |
+ |
+ int WillSendMessage_Locked(Port* port, |
+ const PortName& port_name, |
+ Message* message); |
+ int ForwardMessages_Locked(Port* port, const PortName& port_name); |
+ void InitiateProxyRemoval_Locked(Port* port, const PortName& port_name); |
+ void MaybeRemoveProxy_Locked(Port* port, const PortName& port_name); |
+ |
+ ScopedMessage NewInternalMessage_Helper(const PortName& port_name, |
+ const EventType& type, |
+ const void* data, |
+ size_t num_data_bytes); |
+ |
+ ScopedMessage NewInternalMessage(const PortName& port_name, |
+ const EventType& type) { |
+ return NewInternalMessage_Helper(port_name, type, nullptr, 0); |
+ } |
+ |
+ template <typename EventData> |
+ ScopedMessage NewInternalMessage(const PortName& port_name, |
+ const EventType& type, |
+ const EventData& data) { |
+ return NewInternalMessage_Helper(port_name, type, &data, sizeof(data)); |
+ } |
+ |
+ const NodeName name_; |
+ NodeDelegate* const delegate_; |
+ |
+ // Guards |ports_| as well as any operation which needs to hold multiple port |
+ // locks simultaneously. Usage of this is subtle: it must NEVER be acquired |
+ // after a Port lock is acquired, and it must ALWAYS be acquired before |
+ // calling WillSendMessage_Locked or ForwardMessages_Locked. |
+ base::Lock ports_lock_; |
+ std::unordered_map<PortName, scoped_refptr<Port>> ports_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(Node); |
+}; |
+ |
+} // namespace ports |
+} // namespace edk |
+} // namespace mojo |
+ |
+#endif // MOJO_EDK_SYSTEM_PORTS_NODE_H_ |