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_EDK_SYSTEM_PORTS_NODE_H_ 6 #define MOJO_EDK_SYSTEM_PORTS_NODE_H_ 7 8 #include <stddef.h> 9 #include <stdint.h> 10 11 #include <queue> 12 #include <unordered_map> 13 14 #include "base/macros.h" 15 #include "base/memory/ref_counted.h" 16 #include "base/synchronization/lock.h" 17 #include "mojo/edk/system/ports/event.h" 18 #include "mojo/edk/system/ports/message.h" 19 #include "mojo/edk/system/ports/name.h" 20 #include "mojo/edk/system/ports/port.h" 21 #include "mojo/edk/system/ports/port_ref.h" 22 #include "mojo/edk/system/ports/user_data.h" 23 24 #undef SendMessage // Gah, windows 25 26 namespace mojo { 27 namespace edk { 28 namespace ports { 29 30 enum : int { 31 OK = 0, 32 ERROR_PORT_UNKNOWN = -10, 33 ERROR_PORT_EXISTS = -11, 34 ERROR_PORT_STATE_UNEXPECTED = -12, 35 ERROR_PORT_CANNOT_SEND_SELF = -13, 36 ERROR_PORT_PEER_CLOSED = -14, 37 ERROR_PORT_CANNOT_SEND_PEER = -15, 38 ERROR_NOT_IMPLEMENTED = -100, 39 }; 40 41 struct PortStatus { 42 bool has_messages; 43 bool receiving_messages; 44 bool peer_closed; 45 }; 46 47 class MessageFilter; 48 class NodeDelegate; 49 50 class Node { 51 public: 52 enum class ShutdownPolicy { 53 DONT_ALLOW_LOCAL_PORTS, 54 ALLOW_LOCAL_PORTS, 55 }; 56 57 // Does not take ownership of the delegate. 58 Node(const NodeName& name, NodeDelegate* delegate); 59 ~Node(); 60 61 // Returns true iff there are no open ports referring to another node or ports 62 // in the process of being transferred from this node to another. If this 63 // returns false, then to ensure clean shutdown, it is necessary to keep the 64 // node alive and continue routing messages to it via AcceptMessage. This 65 // method may be called again after AcceptMessage to check if the Node is now 66 // ready to be destroyed. 67 // 68 // If |policy| is set to |ShutdownPolicy::ALLOW_LOCAL_PORTS|, this will return 69 // |true| even if some ports remain alive, as long as none of them are proxies 70 // to another node. 71 bool CanShutdownCleanly( 72 ShutdownPolicy policy = ShutdownPolicy::DONT_ALLOW_LOCAL_PORTS); 73 74 // Lookup the named port. 75 int GetPort(const PortName& port_name, PortRef* port_ref); 76 77 // Creates a port on this node. Before the port can be used, it must be 78 // initialized using InitializePort. This method is useful for bootstrapping 79 // a connection between two nodes. Generally, ports are created using 80 // CreatePortPair instead. 81 int CreateUninitializedPort(PortRef* port_ref); 82 83 // Initializes a newly created port. 84 int InitializePort(const PortRef& port_ref, 85 const NodeName& peer_node_name, 86 const PortName& peer_port_name); 87 88 // Generates a new connected pair of ports bound to this node. These ports 89 // are initialized and ready to go. 90 int CreatePortPair(PortRef* port0_ref, PortRef* port1_ref); 91 92 // User data associated with the port. 93 int SetUserData(const PortRef& port_ref, scoped_refptr<UserData> user_data); 94 int GetUserData(const PortRef& port_ref, 95 scoped_refptr<UserData>* user_data); 96 97 // Prevents further messages from being sent from this port or delivered to 98 // this port. The port is removed, and the port's peer is notified of the 99 // closure after it has consumed all pending messages. 100 int ClosePort(const PortRef& port_ref); 101 102 // Returns the current status of the port. 103 int GetStatus(const PortRef& port_ref, PortStatus* port_status); 104 105 // Returns the next available message on the specified port or returns a null 106 // message if there are none available. Returns ERROR_PORT_PEER_CLOSED to 107 // indicate that this port's peer has closed. In such cases GetMessage may 108 // be called until it yields a null message, indicating that no more messages 109 // may be read from the port. 110 // 111 // If |filter| is non-null, the next available message is returned only if it 112 // is matched by the filter. If the provided filter does not match the next 113 // available message, GetMessage() behaves as if there is no message 114 // available. Ownership of |filter| is not taken, and it must outlive the 115 // extent of this call. 116 int GetMessage(const PortRef& port_ref, 117 ScopedMessage* message, 118 MessageFilter* filter); 119 120 // Sends a message from the specified port to its peer. Note that the message 121 // notification may arrive synchronously (via PortStatusChanged() on the 122 // delegate) if the peer is local to this Node. 123 int SendMessage(const PortRef& port_ref, ScopedMessage message); 124 125 // Corresponding to NodeDelegate::ForwardMessage. 126 int AcceptMessage(ScopedMessage message); 127 128 // Called to merge two ports with each other. If you have two independent 129 // port pairs A <=> B and C <=> D, the net result of merging B and C is a 130 // single connected port pair A <=> D. 131 // 132 // Note that the behavior of this operation is undefined if either port to be 133 // merged (B or C above) has ever been read from or written to directly, and 134 // this must ONLY be called on one side of the merge, though it doesn't matter 135 // which side. 136 // 137 // It is safe for the non-merged peers (A and D above) to be transferred, 138 // closed, and/or written to before, during, or after the merge. 139 int MergePorts(const PortRef& port_ref, 140 const NodeName& destination_node_name, 141 const PortName& destination_port_name); 142 143 // Like above but merges two ports local to this node. Because both ports are 144 // local this can also verify that neither port has been written to before the 145 // merge. If this fails for any reason, both ports are closed. Otherwise OK 146 // is returned and the ports' receiving peers are connected to each other. 147 int MergeLocalPorts(const PortRef& port0_ref, const PortRef& port1_ref); 148 149 // Called to inform this node that communication with another node is lost 150 // indefinitely. This triggers cleanup of ports bound to this node. 151 int LostConnectionToNode(const NodeName& node_name); 152 153 private: 154 class LockedPort; 155 156 // Note: Functions that end with _Locked require |ports_lock_| to be held 157 // before calling. 158 int OnUserMessage(ScopedMessage message); 159 int OnPortAccepted(const PortName& port_name); 160 int OnObserveProxy(const PortName& port_name, 161 const ObserveProxyEventData& event); 162 int OnObserveProxyAck(const PortName& port_name, uint64_t last_sequence_num); 163 int OnObserveClosure(const PortName& port_name, uint64_t last_sequence_num); 164 int OnMergePort(const PortName& port_name, const MergePortEventData& event); 165 166 int AddPortWithName(const PortName& port_name, scoped_refptr<Port> port); 167 void ErasePort(const PortName& port_name); 168 void ErasePort_Locked(const PortName& port_name); 169 scoped_refptr<Port> GetPort(const PortName& port_name); 170 scoped_refptr<Port> GetPort_Locked(const PortName& port_name); 171 172 int SendMessageInternal(const PortRef& port_ref, ScopedMessage* message); 173 int MergePorts_Locked(const PortRef& port0_ref, const PortRef& port1_ref); 174 void WillSendPort(const LockedPort& port, 175 const NodeName& to_node_name, 176 PortName* port_name, 177 PortDescriptor* port_descriptor); 178 int AcceptPort(const PortName& port_name, 179 const PortDescriptor& port_descriptor); 180 181 int WillSendMessage_Locked(const LockedPort& port, 182 const PortName& port_name, 183 Message* message); 184 int BeginProxying_Locked(const LockedPort& port, const PortName& port_name); 185 int BeginProxying(PortRef port_ref); 186 int ForwardMessages_Locked(const LockedPort& port, const PortName& port_name); 187 void InitiateProxyRemoval(const LockedPort& port, const PortName& port_name); 188 void MaybeRemoveProxy_Locked(const LockedPort& port, 189 const PortName& port_name); 190 void TryRemoveProxy(PortRef port_ref); 191 void DestroyAllPortsWithPeer(const NodeName& node_name, 192 const PortName& port_name); 193 194 ScopedMessage NewInternalMessage_Helper(const PortName& port_name, 195 const EventType& type, 196 const void* data, 197 size_t num_data_bytes); 198 NewInternalMessage(const PortName & port_name,const EventType & type)199 ScopedMessage NewInternalMessage(const PortName& port_name, 200 const EventType& type) { 201 return NewInternalMessage_Helper(port_name, type, nullptr, 0); 202 } 203 204 template <typename EventData> NewInternalMessage(const PortName & port_name,const EventType & type,const EventData & data)205 ScopedMessage NewInternalMessage(const PortName& port_name, 206 const EventType& type, 207 const EventData& data) { 208 return NewInternalMessage_Helper(port_name, type, &data, sizeof(data)); 209 } 210 211 const NodeName name_; 212 NodeDelegate* const delegate_; 213 214 // Guards |ports_| as well as any operation which needs to hold multiple port 215 // locks simultaneously. Usage of this is subtle: it must NEVER be acquired 216 // after a Port lock is acquired, and it must ALWAYS be acquired before 217 // calling WillSendMessage_Locked or ForwardMessages_Locked. 218 base::Lock ports_lock_; 219 std::unordered_map<PortName, scoped_refptr<Port>> ports_; 220 221 DISALLOW_COPY_AND_ASSIGN(Node); 222 }; 223 224 } // namespace ports 225 } // namespace edk 226 } // namespace mojo 227 228 #endif // MOJO_EDK_SYSTEM_PORTS_NODE_H_ 229