tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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_