1 // Copyright 2016 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 #ifndef MOJO_CORE_PORTS_NODE_H_
6 #define MOJO_CORE_PORTS_NODE_H_
7
8 #include <stddef.h>
9 #include <stdint.h>
10
11 #include <queue>
12 #include <unordered_map>
13
14 #include "base/component_export.h"
15 #include "base/macros.h"
16 #include "base/memory/ref_counted.h"
17 #include "base/synchronization/lock.h"
18 #include "mojo/core/ports/event.h"
19 #include "mojo/core/ports/name.h"
20 #include "mojo/core/ports/port.h"
21 #include "mojo/core/ports/port_ref.h"
22 #include "mojo/core/ports/user_data.h"
23
24 namespace mojo {
25 namespace core {
26 namespace ports {
27
28 enum : int {
29 OK = 0,
30 ERROR_PORT_UNKNOWN = -10,
31 ERROR_PORT_EXISTS = -11,
32 ERROR_PORT_STATE_UNEXPECTED = -12,
33 ERROR_PORT_CANNOT_SEND_SELF = -13,
34 ERROR_PORT_PEER_CLOSED = -14,
35 ERROR_PORT_CANNOT_SEND_PEER = -15,
36 ERROR_NOT_IMPLEMENTED = -100,
37 };
38
39 struct PortStatus {
40 bool has_messages;
41 bool receiving_messages;
42 bool peer_closed;
43 bool peer_remote;
44 size_t queued_message_count;
45 size_t queued_num_bytes;
46 };
47
48 class MessageFilter;
49 class NodeDelegate;
50
51 // A Node maintains a collection of Ports (see port.h) indexed by unique 128-bit
52 // addresses (names), performing routing and processing of events among the
53 // Ports within the Node and to or from other Nodes in the system. Typically
54 // (and practically, in all uses today) there is a single Node per system
55 // process. Thus a Node boundary effectively models a process boundary.
56 //
57 // New Ports can be created uninitialized using CreateUninitializedPort (and
58 // later initialized using InitializePort), or created in a fully initialized
59 // state using CreatePortPair(). Initialized ports have exactly one conjugate
60 // port which is the ultimate receiver of any user messages sent by that port.
61 // See SendUserMessage().
62 //
63 // In addition to routing user message events, various control events are used
64 // by Nodes to coordinate Port behavior and lifetime within and across Nodes.
65 // See Event documentation for description of different types of events used by
66 // a Node to coordinate behavior.
COMPONENT_EXPORT(MOJO_CORE_PORTS)67 class COMPONENT_EXPORT(MOJO_CORE_PORTS) Node {
68 public:
69 enum class ShutdownPolicy {
70 DONT_ALLOW_LOCAL_PORTS,
71 ALLOW_LOCAL_PORTS,
72 };
73
74 // Does not take ownership of the delegate.
75 Node(const NodeName& name, NodeDelegate* delegate);
76 ~Node();
77
78 // Returns true iff there are no open ports referring to another node or ports
79 // in the process of being transferred from this node to another. If this
80 // returns false, then to ensure clean shutdown, it is necessary to keep the
81 // node alive and continue routing messages to it via AcceptMessage. This
82 // method may be called again after AcceptMessage to check if the Node is now
83 // ready to be destroyed.
84 //
85 // If |policy| is set to |ShutdownPolicy::ALLOW_LOCAL_PORTS|, this will return
86 // |true| even if some ports remain alive, as long as none of them are proxies
87 // to another node.
88 bool CanShutdownCleanly(
89 ShutdownPolicy policy = ShutdownPolicy::DONT_ALLOW_LOCAL_PORTS);
90
91 // Lookup the named port.
92 int GetPort(const PortName& port_name, PortRef* port_ref);
93
94 // Creates a port on this node. Before the port can be used, it must be
95 // initialized using InitializePort. This method is useful for bootstrapping
96 // a connection between two nodes. Generally, ports are created using
97 // CreatePortPair instead.
98 int CreateUninitializedPort(PortRef* port_ref);
99
100 // Initializes a newly created port.
101 int InitializePort(const PortRef& port_ref,
102 const NodeName& peer_node_name,
103 const PortName& peer_port_name);
104
105 // Generates a new connected pair of ports bound to this node. These ports
106 // are initialized and ready to go.
107 int CreatePortPair(PortRef* port0_ref, PortRef* port1_ref);
108
109 // User data associated with the port.
110 int SetUserData(const PortRef& port_ref, scoped_refptr<UserData> user_data);
111 int GetUserData(const PortRef& port_ref, scoped_refptr<UserData>* user_data);
112
113 // Prevents further messages from being sent from this port or delivered to
114 // this port. The port is removed, and the port's peer is notified of the
115 // closure after it has consumed all pending messages.
116 int ClosePort(const PortRef& port_ref);
117
118 // Returns the current status of the port.
119 int GetStatus(const PortRef& port_ref, PortStatus* port_status);
120
121 // Returns the next available message on the specified port or returns a null
122 // message if there are none available. Returns ERROR_PORT_PEER_CLOSED to
123 // indicate that this port's peer has closed. In such cases GetMessage may
124 // be called until it yields a null message, indicating that no more messages
125 // may be read from the port.
126 //
127 // If |filter| is non-null, the next available message is returned only if it
128 // is matched by the filter. If the provided filter does not match the next
129 // available message, GetMessage() behaves as if there is no message
130 // available. Ownership of |filter| is not taken, and it must outlive the
131 // extent of this call.
132 int GetMessage(const PortRef& port_ref,
133 std::unique_ptr<UserMessageEvent>* message,
134 MessageFilter* filter);
135
136 // Sends a message from the specified port to its peer. Note that the message
137 // notification may arrive synchronously (via PortStatusChanged() on the
138 // delegate) if the peer is local to this Node.
139 int SendUserMessage(const PortRef& port_ref,
140 std::unique_ptr<UserMessageEvent> message);
141
142 // Corresponding to NodeDelegate::ForwardEvent.
143 int AcceptEvent(ScopedEvent event);
144
145 // Called to merge two ports with each other. If you have two independent
146 // port pairs A <=> B and C <=> D, the net result of merging B and C is a
147 // single connected port pair A <=> D.
148 //
149 // Note that the behavior of this operation is undefined if either port to be
150 // merged (B or C above) has ever been read from or written to directly, and
151 // this must ONLY be called on one side of the merge, though it doesn't matter
152 // which side.
153 //
154 // It is safe for the non-merged peers (A and D above) to be transferred,
155 // closed, and/or written to before, during, or after the merge.
156 int MergePorts(const PortRef& port_ref,
157 const NodeName& destination_node_name,
158 const PortName& destination_port_name);
159
160 // Like above but merges two ports local to this node. Because both ports are
161 // local this can also verify that neither port has been written to before the
162 // merge. If this fails for any reason, both ports are closed. Otherwise OK
163 // is returned and the ports' receiving peers are connected to each other.
164 int MergeLocalPorts(const PortRef& port0_ref, const PortRef& port1_ref);
165
166 // Called to inform this node that communication with another node is lost
167 // indefinitely. This triggers cleanup of ports bound to this node.
168 int LostConnectionToNode(const NodeName& node_name);
169
170 private:
171 // Helper to ensure that a Node always calls into its delegate safely, i.e.
172 // without holding any internal locks.
173 class DelegateHolder {
174 public:
175 DelegateHolder(Node* node, NodeDelegate* delegate);
176 ~DelegateHolder();
177
178 NodeDelegate* operator->() const {
179 EnsureSafeDelegateAccess();
180 return delegate_;
181 }
182
183 private:
184 #if DCHECK_IS_ON()
185 void EnsureSafeDelegateAccess() const;
186 #else
187 void EnsureSafeDelegateAccess() const {}
188 #endif
189
190 Node* const node_;
191 NodeDelegate* const delegate_;
192
193 DISALLOW_COPY_AND_ASSIGN(DelegateHolder);
194 };
195
196 int OnUserMessage(std::unique_ptr<UserMessageEvent> message);
197 int OnPortAccepted(std::unique_ptr<PortAcceptedEvent> event);
198 int OnObserveProxy(std::unique_ptr<ObserveProxyEvent> event);
199 int OnObserveProxyAck(std::unique_ptr<ObserveProxyAckEvent> event);
200 int OnObserveClosure(std::unique_ptr<ObserveClosureEvent> event);
201 int OnMergePort(std::unique_ptr<MergePortEvent> event);
202
203 int AddPortWithName(const PortName& port_name, scoped_refptr<Port> port);
204 void ErasePort(const PortName& port_name);
205
206 int SendUserMessageInternal(const PortRef& port_ref,
207 std::unique_ptr<UserMessageEvent>* message);
208 int MergePortsInternal(const PortRef& port0_ref,
209 const PortRef& port1_ref,
210 bool allow_close_on_bad_state);
211 void ConvertToProxy(Port* port,
212 const NodeName& to_node_name,
213 PortName* port_name,
214 Event::PortDescriptor* port_descriptor);
215 int AcceptPort(const PortName& port_name,
216 const Event::PortDescriptor& port_descriptor);
217
218 int PrepareToForwardUserMessage(const PortRef& forwarding_port_ref,
219 Port::State expected_port_state,
220 bool ignore_closed_peer,
221 UserMessageEvent* message,
222 NodeName* forward_to_node);
223 int BeginProxying(const PortRef& port_ref);
224 int ForwardUserMessagesFromProxy(const PortRef& port_ref);
225 void InitiateProxyRemoval(const PortRef& port_ref);
226 void TryRemoveProxy(const PortRef& port_ref);
227 void DestroyAllPortsWithPeer(const NodeName& node_name,
228 const PortName& port_name);
229
230 const NodeName name_;
231 const DelegateHolder delegate_;
232
233 // Guards |ports_|. This must never be acquired while an individual port's
234 // lock is held on the same thread. Conversely, individual port locks may be
235 // acquired while this one is held.
236 //
237 // Because UserMessage events may execute arbitrary user code during
238 // destruction, it is also important to ensure that such events are never
239 // destroyed while this (or any individual Port) lock is held.
240 base::Lock ports_lock_;
241 std::unordered_map<PortName, scoped_refptr<Port>> ports_;
242
243 DISALLOW_COPY_AND_ASSIGN(Node);
244 };
245
246 } // namespace ports
247 } // namespace core
248 } // namespace mojo
249
250 #endif // MOJO_CORE_PORTS_NODE_H_
251