tor-browser

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

NodeController.h (7491B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #ifndef mozilla_ipc_NodeController_h
      8 #define mozilla_ipc_NodeController_h
      9 
     10 #include "mojo/core/ports/event.h"
     11 #include "mojo/core/ports/name.h"
     12 #include "mojo/core/ports/node.h"
     13 #include "mojo/core/ports/node_delegate.h"
     14 #include "chrome/common/ipc_message.h"
     15 #include "mozilla/ipc/ProtocolUtils.h"
     16 #include "nsTHashMap.h"
     17 #include "mozilla/Queue.h"
     18 #include "mozilla/DataMutex.h"
     19 #include "mozilla/UniquePtr.h"
     20 #include "mozilla/ipc/NodeChannel.h"
     21 
     22 namespace mozilla::ipc {
     23 
     24 class GeckoChildProcessHost;
     25 
     26 class NodeController final : public mojo::core::ports::NodeDelegate,
     27                             public NodeChannel::Listener {
     28  using NodeName = mojo::core::ports::NodeName;
     29  using PortName = mojo::core::ports::PortName;
     30  using PortRef = mojo::core::ports::PortRef;
     31  using Event = mojo::core::ports::Event;
     32  using Node = mojo::core::ports::Node;
     33  using UserData = mojo::core::ports::UserData;
     34  using PortStatus = mojo::core::ports::PortStatus;
     35  using UserMessageEvent = mojo::core::ports::UserMessageEvent;
     36  using UserMessage = mojo::core::ports::UserMessage;
     37 
     38 public:
     39  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(NodeController, override)
     40 
     41  // Return the global singleton instance. The returned value is only valid
     42  // while the IO thread is alive.
     43  static NodeController* GetSingleton();
     44 
     45  class PortObserver : public UserData {
     46   public:
     47    virtual void OnPortStatusChanged() = 0;
     48 
     49   protected:
     50    ~PortObserver() override = default;
     51  };
     52 
     53  // NOTE: For now there will always be a single broker process, and all
     54  // processes in the graph need to be able to talk to it (the parent process).
     55  // Give it a fixed node name for now to simplify things.
     56  //
     57  // If we ever decide to have multiple node networks intercommunicating (e.g.
     58  // multiple instances or background services), we may need to change this.
     59  static constexpr NodeName kBrokerNodeName{0x1, 0x1};
     60 
     61  bool IsBroker() const { return mName == kBrokerNodeName; }
     62 
     63  // Mint a new connected pair of ports within the current process.
     64  std::pair<ScopedPort, ScopedPort> CreatePortPair();
     65 
     66  // Get a reference to the port with the given name. Returns an invalid
     67  // `PortRef` if the name wasn't found.
     68  PortRef GetPort(const PortName& aName);
     69 
     70  // Set the observer for the given port. This observer will be notified when
     71  // the status of the port changes.
     72  void SetPortObserver(const PortRef& aPort, PortObserver* aObserver);
     73 
     74  // See `mojo::core::ports::Node::GetStatus`
     75  Maybe<PortStatus> GetStatus(const PortRef& aPort);
     76 
     77  // See `mojo::core::ports::Node::ClosePort`
     78  void ClosePort(const PortRef& aPort);
     79 
     80  // Send a message to the the port's connected peer.
     81  bool SendUserMessage(const PortRef& aPort, UniquePtr<IPC::Message> aMessage);
     82 
     83  // Get the next message from the port's message queue.
     84  // Will set `*aMessage` to the found message, or `nullptr`.
     85  // Returns `false` and sets `*aMessage` to `nullptr` if no further messages
     86  // will be delivered to this port as its peer has been closed.
     87  bool GetMessage(const PortRef& aPort, UniquePtr<IPC::Message>* aMessage);
     88 
     89  // Called in the broker process from GeckoChildProcessHost to introduce a new
     90  // child process into the network. On success, `aInitialPort` will be a
     91  // `PortRef` which can be used to communicate with the `PortRef` returned from
     92  // `InitChildProcess`, `aNodeChannel` will be a reference to the `NodeChannel`
     93  // created for the new process, and `aClientHandle` will be the
     94  // `ChannelHandle` to pass to the child process on the command line.
     95  // The port can immediately have messages sent to it.
     96  bool InviteChildProcess(GeckoChildProcessHost* aChildProcessHost,
     97                          IPC::Channel::ChannelHandle* aClientHandle,
     98                          ScopedPort* aInitialPort, NodeChannel** aNodeChannel);
     99 
    100  // Called as the IO thread is started in the parent process.
    101  static void InitBrokerProcess(const IPC::Channel::ChannelKind* aChannelKind);
    102 
    103  // Called as the IO thread is started in a child process.
    104  static ScopedPort InitChildProcess(
    105      IPC::Channel::ChannelHandle&& aChannelHandle, base::ProcessId aParentPid);
    106 
    107  // Called when the IO thread is torn down.
    108  static void CleanUp();
    109 
    110 private:
    111  NodeController(const NodeName& aName,
    112                 const IPC::Channel::ChannelKind* aChannelKind);
    113  ~NodeController();
    114 
    115  UniquePtr<IPC::Message> SerializeEventMessage(
    116      UniquePtr<Event> aEvent, const NodeName* aRelayTarget = nullptr,
    117      uint32_t aType = EVENT_MESSAGE_TYPE);
    118  UniquePtr<Event> DeserializeEventMessage(UniquePtr<IPC::Message> aMessage,
    119                                           NodeName* aRelayTarget = nullptr);
    120 
    121  // Get the `NodeChannel` for the named node.
    122  already_AddRefed<NodeChannel> GetNodeChannel(const NodeName& aName);
    123 
    124  // Stop communicating with this peer. Must be called on the IO thread.
    125  void DropPeer(NodeName aNodeName);
    126 
    127  // Ensure that there is a direct connection to a remote node, requesting an
    128  // introduction if there is not.
    129  // If provided, will optionally send an event to the remote node.
    130  void ContactRemotePeer(const NodeName& aNode, UniquePtr<Event> aEvent);
    131 
    132  // Message Handlers
    133  void OnEventMessage(const NodeName& aFromNode,
    134                      UniquePtr<IPC::Message> aMessage) override;
    135  void OnBroadcast(const NodeName& aFromNode,
    136                   UniquePtr<IPC::Message> aMessage) override;
    137  void OnIntroduce(const NodeName& aFromNode,
    138                   NodeChannel::Introduction aIntroduction) override;
    139  void OnRequestIntroduction(const NodeName& aFromNode,
    140                             const NodeName& aName) override;
    141  void OnAcceptInvite(const NodeName& aFromNode, const NodeName& aRealName,
    142                      const PortName& aInitialPort) override;
    143  void OnChannelError(const NodeName& aFromNode) override;
    144 
    145  // NodeDelegate Implementation
    146  void ForwardEvent(const NodeName& aNode, UniquePtr<Event> aEvent) override;
    147  void BroadcastEvent(UniquePtr<Event> aEvent) override;
    148  void PortStatusChanged(const PortRef& aPortRef) override;
    149  void ObserveRemoteNode(const NodeName& aNode) override;
    150 
    151  const NodeName mName;
    152  const UniquePtr<Node> mNode;
    153  const IPC::Channel::ChannelKind* const mChannelKind;
    154 
    155  template <class T>
    156  using NodeMap = nsTHashMap<NodeNameHashKey, T>;
    157 
    158  struct Invite {
    159    // The channel which is being invited. This will have a temporary name until
    160    // the invite is completed.
    161    RefPtr<NodeChannel> mChannel;
    162    // The port which will be merged with the port information from the new
    163    // child process when recieved.
    164    PortRef mToMerge;
    165  };
    166 
    167  struct State {
    168    // Channels for connecting to all known peers.
    169    NodeMap<RefPtr<NodeChannel>> mPeers;
    170 
    171    // Messages which are queued for peers which we been introduced to yet.
    172    NodeMap<Queue<UniquePtr<IPC::Message>, 64>> mPendingMessages;
    173 
    174    // Connections for peers being invited to the network.
    175    NodeMap<Invite> mInvites;
    176 
    177    // Ports which are waiting to be merged by a particular peer node.
    178    NodeMap<nsTArray<PortRef>> mPendingMerges;
    179  };
    180 
    181  DataMutex<State> mState{"NodeController::mState"};
    182 };
    183 
    184 }  // namespace mozilla::ipc
    185 
    186 #endif