node.h (15204B)
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 <unordered_map> 12 13 #include "mojo/core/ports/event.h" 14 #include "mojo/core/ports/name.h" 15 #include "mojo/core/ports/port.h" 16 #include "mojo/core/ports/port_ref.h" 17 #include "mojo/core/ports/user_data.h" 18 #include "mozilla/Mutex.h" 19 #include "mozilla/RefPtr.h" 20 21 namespace mojo { 22 namespace core { 23 namespace ports { 24 25 enum : int { 26 OK = 0, 27 ERROR_PORT_UNKNOWN = -10, 28 ERROR_PORT_EXISTS = -11, 29 ERROR_PORT_STATE_UNEXPECTED = -12, 30 ERROR_PORT_CANNOT_SEND_SELF = -13, 31 ERROR_PORT_PEER_CLOSED = -14, 32 ERROR_PORT_CANNOT_SEND_PEER = -15, 33 ERROR_NOT_IMPLEMENTED = -100, 34 }; 35 36 struct PortStatus { 37 bool has_messages; 38 bool receiving_messages; 39 bool peer_closed; 40 bool peer_remote; 41 size_t queued_message_count; 42 size_t queued_num_bytes; 43 size_t unacknowledged_message_count; 44 #ifdef FUZZING_SNAPSHOT 45 NodeName peer_node_name; 46 #endif 47 }; 48 49 struct PendingUpdatePreviousPeer { 50 NodeName receiver; 51 PortName port; 52 PortName from_port; 53 uint64_t sequence_num; 54 NodeName new_prev_node; 55 PortName new_prev_port; 56 }; 57 58 class MessageFilter; 59 class NodeDelegate; 60 61 // A Node maintains a collection of Ports (see port.h) indexed by unique 128-bit 62 // addresses (names), performing routing and processing of events among the 63 // Ports within the Node and to or from other Nodes in the system. Typically 64 // (and practically, in all uses today) there is a single Node per system 65 // process. Thus a Node boundary effectively models a process boundary. 66 // 67 // New Ports can be created uninitialized using CreateUninitializedPort (and 68 // later initialized using InitializePort), or created in a fully initialized 69 // state using CreatePortPair(). Initialized ports have exactly one conjugate 70 // port which is the ultimate receiver of any user messages sent by that port. 71 // See SendUserMessage(). 72 // 73 // In addition to routing user message events, various control events are used 74 // by Nodes to coordinate Port behavior and lifetime within and across Nodes. 75 // See Event documentation for description of different types of events used by 76 // a Node to coordinate behavior. 77 class Node { 78 public: 79 enum class ShutdownPolicy { 80 DONT_ALLOW_LOCAL_PORTS, 81 ALLOW_LOCAL_PORTS, 82 }; 83 84 // Does not take ownership of the delegate. 85 Node(const NodeName& name, NodeDelegate* delegate); 86 ~Node(); 87 88 Node(const Node&) = delete; 89 void operator=(const Node&) = delete; 90 91 // Returns true iff there are no open ports referring to another node or ports 92 // in the process of being transferred from this node to another. If this 93 // returns false, then to ensure clean shutdown, it is necessary to keep the 94 // node alive and continue routing messages to it via AcceptMessage. This 95 // method may be called again after AcceptMessage to check if the Node is now 96 // ready to be destroyed. 97 // 98 // If |policy| is set to |ShutdownPolicy::ALLOW_LOCAL_PORTS|, this will return 99 // |true| even if some ports remain alive, as long as none of them are proxies 100 // to another node. 101 bool CanShutdownCleanly( 102 ShutdownPolicy policy = ShutdownPolicy::DONT_ALLOW_LOCAL_PORTS); 103 104 // Lookup the named port. 105 int GetPort(const PortName& port_name, PortRef* port_ref); 106 107 // Creates a port on this node. Before the port can be used, it must be 108 // initialized using InitializePort. This method is useful for bootstrapping 109 // a connection between two nodes. Generally, ports are created using 110 // CreatePortPair instead. 111 int CreateUninitializedPort(PortRef* port_ref); 112 113 // Initializes a newly created port. 114 int InitializePort(const PortRef& port_ref, const NodeName& peer_node_name, 115 const PortName& peer_port_name, 116 const NodeName& prev_node_name, 117 const PortName& prev_port_name); 118 119 // Generates a new connected pair of ports bound to this node. These ports 120 // are initialized and ready to go. 121 int CreatePortPair(PortRef* port0_ref, PortRef* port1_ref); 122 123 // User data associated with the port. 124 int SetUserData(const PortRef& port_ref, RefPtr<UserData> user_data); 125 int GetUserData(const PortRef& port_ref, RefPtr<UserData>* user_data); 126 127 // Prevents further messages from being sent from this port or delivered to 128 // this port. The port is removed, and the port's peer is notified of the 129 // closure after it has consumed all pending messages. 130 int ClosePort(const PortRef& port_ref); 131 132 // Returns the current status of the port. 133 int GetStatus(const PortRef& port_ref, PortStatus* port_status); 134 135 // Returns the next available message on the specified port or returns a null 136 // message if there are none available. Returns ERROR_PORT_PEER_CLOSED to 137 // indicate that this port's peer has closed. In such cases GetMessage may 138 // be called until it yields a null message, indicating that no more messages 139 // may be read from the port. 140 // 141 // If |filter| is non-null, the next available message is returned only if it 142 // is matched by the filter. If the provided filter does not match the next 143 // available message, GetMessage() behaves as if there is no message 144 // available. Ownership of |filter| is not taken, and it must outlive the 145 // extent of this call. 146 int GetMessage(const PortRef& port_ref, 147 mozilla::UniquePtr<UserMessageEvent>* message, 148 MessageFilter* filter); 149 150 // Sends a message from the specified port to its peer. Note that the message 151 // notification may arrive synchronously (via PortStatusChanged() on the 152 // delegate) if the peer is local to this Node. 153 int SendUserMessage(const PortRef& port_ref, 154 mozilla::UniquePtr<UserMessageEvent> message); 155 156 // Makes the port send acknowledge requests to its conjugate to acknowledge 157 // at least every |sequence_number_acknowledge_interval| messages as they're 158 // read from the conjugate. The number of unacknowledged messages is exposed 159 // in the |unacknowledged_message_count| field of PortStatus. This allows 160 // bounding the number of unread and/or in-transit messages from this port 161 // to its conjugate between zero and |unacknowledged_message_count|. 162 int SetAcknowledgeRequestInterval(const PortRef& port_ref, 163 uint64_t sequence_num_acknowledge_interval); 164 165 // Corresponding to NodeDelegate::ForwardEvent. 166 int AcceptEvent(const NodeName& from_node, ScopedEvent event); 167 168 // Called to merge two ports with each other. If you have two independent 169 // port pairs A <=> B and C <=> D, the net result of merging B and C is a 170 // single connected port pair A <=> D. 171 // 172 // Note that the behavior of this operation is undefined if either port to be 173 // merged (B or C above) has ever been read from or written to directly, and 174 // this must ONLY be called on one side of the merge, though it doesn't matter 175 // which side. 176 // 177 // It is safe for the non-merged peers (A and D above) to be transferred, 178 // closed, and/or written to before, during, or after the merge. 179 int MergePorts(const PortRef& port_ref, const NodeName& destination_node_name, 180 const PortName& destination_port_name); 181 182 // Like above but merges two ports local to this node. Because both ports are 183 // local this can also verify that neither port has been written to before the 184 // merge. If this fails for any reason, both ports are closed. Otherwise OK 185 // is returned and the ports' receiving peers are connected to each other. 186 int MergeLocalPorts(const PortRef& port0_ref, const PortRef& port1_ref); 187 188 // Called to inform this node that communication with another node is lost 189 // indefinitely. This triggers cleanup of ports bound to this node. 190 int LostConnectionToNode(const NodeName& node_name); 191 192 private: 193 // Helper to ensure that a Node always calls into its delegate safely, i.e. 194 // without holding any internal locks. 195 class DelegateHolder { 196 public: 197 DelegateHolder(Node* node, NodeDelegate* delegate); 198 ~DelegateHolder(); 199 200 DelegateHolder(const DelegateHolder&) = delete; 201 void operator=(const DelegateHolder&) = delete; 202 203 NodeDelegate* operator->() const { 204 EnsureSafeDelegateAccess(); 205 return delegate_; 206 } 207 208 private: 209 #ifdef DEBUG 210 void EnsureSafeDelegateAccess() const; 211 #else 212 void EnsureSafeDelegateAccess() const {} 213 #endif 214 215 Node* const node_; 216 NodeDelegate* const delegate_; 217 }; 218 219 int OnUserMessage(const PortRef& port_ref, const NodeName& from_node, 220 mozilla::UniquePtr<UserMessageEvent> message); 221 int OnPortAccepted(const PortRef& port_ref, 222 mozilla::UniquePtr<PortAcceptedEvent> event); 223 int OnObserveProxy(const PortRef& port_ref, 224 mozilla::UniquePtr<ObserveProxyEvent> event); 225 int OnObserveProxyAck(const PortRef& port_ref, 226 mozilla::UniquePtr<ObserveProxyAckEvent> event); 227 int OnObserveClosure(const PortRef& port_ref, 228 mozilla::UniquePtr<ObserveClosureEvent> event); 229 int OnMergePort(const PortRef& port_ref, 230 mozilla::UniquePtr<MergePortEvent> event); 231 int OnUserMessageReadAckRequest( 232 const PortRef& port_ref, 233 mozilla::UniquePtr<UserMessageReadAckRequestEvent> event); 234 int OnUserMessageReadAck(const PortRef& port_ref, 235 mozilla::UniquePtr<UserMessageReadAckEvent> event); 236 int OnUpdatePreviousPeer(const PortRef& port_ref, 237 mozilla::UniquePtr<UpdatePreviousPeerEvent> event); 238 239 int AddPortWithName(const PortName& port_name, RefPtr<Port> port); 240 void ErasePort(const PortName& port_name); 241 242 // Check if the event is sent by the previous peer of the port to decide if 243 // we can check the sequence number. 244 // This is not the case for example for PortAccepted or broadcasted events. 245 bool IsEventFromPreviousPeer(const Event& event); 246 247 int AcceptEventInternal(const PortRef& port_ref, const NodeName& from_node, 248 ScopedEvent event); 249 250 int SendUserMessageInternal(const PortRef& port_ref, 251 mozilla::UniquePtr<UserMessageEvent>* message); 252 int MergePortsInternal(const PortRef& port0_ref, const PortRef& port1_ref, 253 bool allow_close_on_bad_state); 254 void ConvertToProxy(Port* port, const NodeName& to_node_name, 255 PortName* port_name, 256 Event::PortDescriptor* port_descriptor, 257 PendingUpdatePreviousPeer* pending_update) 258 MOZ_REQUIRES(ports_lock_); 259 int AcceptPort(const PortName& port_name, 260 const Event::PortDescriptor& port_descriptor); 261 262 int PrepareToForwardUserMessage(const PortRef& forwarding_port_ref, 263 Port::State expected_port_state, 264 bool ignore_closed_peer, 265 UserMessageEvent* message, 266 NodeName* forward_to_node); 267 int BeginProxying(const PortRef& port_ref); 268 int ForwardUserMessagesFromProxy(const PortRef& port_ref); 269 void InitiateProxyRemoval(const PortRef& port_ref); 270 void TryRemoveProxy(const PortRef& port_ref); 271 void DestroyAllPortsWithPeer(const NodeName& node_name, 272 const PortName& port_name); 273 274 // Changes the peer node and port name referenced by |port|. Note that both 275 // |ports_lock_| MUST be held through the extent of this method. 276 // |local_port|'s lock must be held if and only if a reference to |local_port| 277 // exist in |ports_|. 278 void UpdatePortPeerAddress(const PortName& local_port_name, Port* local_port, 279 const NodeName& new_peer_node, 280 const PortName& new_peer_port) 281 MOZ_REQUIRES(ports_lock_); 282 283 // Removes an entry from |peer_port_map_| corresponding to |local_port|'s peer 284 // address, if valid. 285 void RemoveFromPeerPortMap(const PortName& local_port_name, Port* local_port) 286 MOZ_REQUIRES(ports_lock_); 287 288 // Swaps the peer information for two local ports. Used during port merges. 289 // Note that |ports_lock_| must be held along with each of the two port's own 290 // locks, through the extent of this method. 291 void SwapPortPeers(const PortName& port0_name, Port* port0, 292 const PortName& port1_name, Port* port1) 293 MOZ_REQUIRES(ports_lock_); 294 295 // Sends an acknowledge request to the peer if the port has a non-zero 296 // |sequence_num_acknowledge_interval|. This needs to be done when the port's 297 // peer changes, as the previous peer proxy may not have forwarded any prior 298 // acknowledge request before deleting itself. 299 void MaybeResendAckRequest(const PortRef& port_ref); 300 301 // Forwards a stored acknowledge request to the peer if the proxy has a 302 // non-zero |sequence_num_acknowledge_interval|. 303 void MaybeForwardAckRequest(const PortRef& port_ref); 304 305 // Sends an acknowledge of the most recently read sequence number to the peer 306 // if any messages have been read, and the port has a non-zero 307 // |sequence_num_to_acknowledge|. 308 void MaybeResendAck(const PortRef& port_ref); 309 310 const NodeName name_; 311 const DelegateHolder delegate_; 312 313 // Just to clarify readability of the types below. 314 using LocalPortName = PortName; 315 using PeerPortName = PortName; 316 317 // Guards access to |ports_| and |peer_port_maps_| below. 318 // 319 // This must never be acquired while an individual port's lock is held on the 320 // same thread. Conversely, individual port locks may be acquired while this 321 // one is held. 322 // 323 // Because UserMessage events may execute arbitrary user code during 324 // destruction, it is also important to ensure that such events are never 325 // destroyed while this (or any individual Port) lock is held. 326 mozilla::Mutex ports_lock_{"Ports Lock"}; 327 std::unordered_map<LocalPortName, RefPtr<Port>> ports_ 328 MOZ_GUARDED_BY(ports_lock_); 329 330 // Maps a peer port name to a list of PortRefs for all local ports which have 331 // the port name key designated as their peer port. The set of local ports 332 // which have the same peer port is expected to always be relatively small and 333 // usually 1. Hence we just use a flat_map of local PortRefs keyed on each 334 // local port's name. 335 // 336 // FIXME(nika): We don't have `base::flat_map` or a super equivalent type with 337 // the same API, so just use a nested `std::unordered_map` for now. We should 338 // probably change all of this to instead use our types eventually. 339 using PeerPortMap = 340 std::unordered_map<PeerPortName, 341 std::unordered_map<LocalPortName, PortRef>>; 342 343 // A reverse mapping which can be used to find all local ports that reference 344 // a given peer node or a local port that references a specific given peer 345 // port on a peer node. The key to this map is the corresponding peer node 346 // name. 347 std::unordered_map<NodeName, PeerPortMap> peer_port_maps_ 348 MOZ_GUARDED_BY(ports_lock_); 349 }; 350 351 } // namespace ports 352 } // namespace core 353 } // namespace mojo 354 355 #endif // MOJO_CORE_PORTS_NODE_H_