• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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