Home | History | Annotate | Download | only in ports
      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 
    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>
    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