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