tor-browser

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

NodeChannel.h (6453B)


      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_NodeChannel_h
      8 #define mozilla_ipc_NodeChannel_h
      9 
     10 #include "mojo/core/ports/node.h"
     11 #include "mojo/core/ports/node_delegate.h"
     12 #include "base/process.h"
     13 #include "chrome/common/ipc_message.h"
     14 #include "chrome/common/ipc_channel.h"
     15 #include "mozilla/ipc/ProtocolUtils.h"
     16 #include "nsISupports.h"
     17 #include "nsTHashMap.h"
     18 #include "mozilla/Queue.h"
     19 #include "mozilla/DataMutex.h"
     20 #include "mozilla/UniquePtr.h"
     21 #include "mozilla/WeakPtr.h"
     22 
     23 #ifdef FUZZING_SNAPSHOT
     24 #  include "mozilla/fuzzing/IPCFuzzController.h"
     25 #endif
     26 
     27 namespace mozilla::ipc {
     28 
     29 class GeckoChildProcessHost;
     30 class NodeController;
     31 
     32 // Represents a live connection between our Node and a remote process. This
     33 // object acts as an IPC::Channel listener and performs basic processing on
     34 // messages as they're passed between processes.
     35 
     36 class NodeChannel final : public IPC::Channel::Listener {
     37  using NodeName = mojo::core::ports::NodeName;
     38  using PortName = mojo::core::ports::PortName;
     39 
     40 #ifdef FUZZING_SNAPSHOT
     41  // Required because IPCFuzzController calls OnMessageReceived.
     42  friend class mozilla::fuzzing::IPCFuzzController;
     43 #endif
     44 
     45 public:
     46  NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_DESTROY(NodeChannel, Destroy())
     47 
     48  struct Introduction {
     49    NodeName mName;
     50    IPC::Channel::ChannelHandle mHandle;
     51    base::ProcessId mMyPid = base::kInvalidProcessId;
     52    base::ProcessId mOtherPid = base::kInvalidProcessId;
     53  };
     54 
     55  class Listener {
     56   public:
     57    virtual ~Listener() = default;
     58 
     59    NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING
     60 
     61    virtual void OnEventMessage(const NodeName& aFromNode,
     62                                UniquePtr<IPC::Message> aMessage) = 0;
     63    virtual void OnBroadcast(const NodeName& aFromNode,
     64                             UniquePtr<IPC::Message> aMessage) = 0;
     65    virtual void OnIntroduce(const NodeName& aFromNode,
     66                             Introduction aIntroduction) = 0;
     67    virtual void OnRequestIntroduction(const NodeName& aFromNode,
     68                                       const NodeName& aName) = 0;
     69    virtual void OnAcceptInvite(const NodeName& aFromNode,
     70                                const NodeName& aRealName,
     71                                const PortName& aInitialPort) = 0;
     72    virtual void OnChannelError(const NodeName& aFromNode) = 0;
     73  };
     74 
     75  NodeChannel(const NodeName& aName, IPC::Channel* aChannel,
     76              Listener* aListener,
     77              base::ProcessId aPid = base::kInvalidProcessId,
     78              GeckoChildProcessHost* aChildProcessHost = nullptr);
     79 
     80  // Send the given message over this peer channel link. May be called from any
     81  // thread.
     82  void SendEventMessage(UniquePtr<IPC::Message> aMessage);
     83 
     84  // Ask the broker process to broadcast this message to every node. May be
     85  // called from any thread.
     86  void Broadcast(UniquePtr<IPC::Message> aMessage);
     87 
     88  // Ask the broker process to introduce this node to another node with the
     89  // given name. May be called from any thread.
     90  void RequestIntroduction(const NodeName& aPeerName);
     91 
     92  // Send an introduction to the target node. May be called from any thread.
     93  void Introduce(Introduction aIntroduction);
     94 
     95  void AcceptInvite(const NodeName& aRealName, const PortName& aInitialPort);
     96 
     97  // The PID of the remote process, once known. May be called from any thread.
     98  base::ProcessId OtherPid() const { return mOtherPid; }
     99 
    100  // Start communicating with the remote process using this NodeChannel. MUST BE
    101  // CALLED FROM THE IO THREAD.
    102  void Start();
    103 
    104  // Stop communicating with the remote process using this NodeChannel, MUST BE
    105  // CALLED FROM THE IO THREAD.
    106  void Close();
    107 
    108  // Only ever called by NodeController to update the name after an invite has
    109  // completed. MUST BE CALLED FROM THE IO THREAD.
    110  void SetName(const NodeName& aNewName) { mName = aNewName; }
    111 
    112 #ifdef FUZZING_SNAPSHOT
    113  // MUST BE CALLED FROM THE IO THREAD.
    114  const NodeName& GetName() { return mName; }
    115 #endif
    116 
    117  // Update the known PID for the remote process. MUST BE CALLED FROM THE IO
    118  // THREAD.
    119  void SetOtherPid(base::ProcessId aNewPid);
    120 
    121 #ifdef XP_DARWIN
    122  // Called by the GeckoChildProcessHost to provide the task_t for the peer
    123  // process. MUST BE CALLED FROM THE IO THREAD.
    124  void SetMachTaskPort(task_t aTask);
    125 #endif
    126 
    127 private:
    128  ~NodeChannel();
    129 
    130  void Destroy();
    131  void FinalDestroy();
    132 
    133  void SendMessage(UniquePtr<IPC::Message> aMessage);
    134 
    135  // IPC::Channel::Listener implementation
    136  void OnMessageReceived(UniquePtr<IPC::Message> aMessage) override;
    137  void OnChannelConnected(base::ProcessId aPeerPid) override;
    138  void OnChannelError() override;
    139 
    140  // NOTE: This strong reference will create a reference cycle between the
    141  // listener and the NodeChannel while it is in use. The Listener must clear
    142  // its reference to the NodeChannel to avoid leaks before shutdown.
    143  const RefPtr<Listener> mListener;
    144 
    145  // The apparent name of this Node. This may change during the invite process
    146  // while waiting for the remote node name to be communicated to us.
    147 
    148  // WARNING: This must only be accessed on the IO thread.
    149  NodeName mName;
    150 
    151  // NOTE: This won't change once the connection has been established, but may
    152  // be `-1` until then. This will only be written to on the IO thread, but may
    153  // be read from other threads.
    154  std::atomic<base::ProcessId> mOtherPid;
    155 
    156  // WARNING: Most methods on the IPC::Channel are only safe to call on the IO
    157  // thread, however it is safe to call `Send()` from other threads. See
    158  // IPC::Channel's documentation for details.
    159  const RefPtr<IPC::Channel> mChannel;
    160 
    161  // The state will start out as `State::Active`, and will only transition to
    162  // `State::Closed` on the IO thread. If a Send fails, the state will
    163  // transition to `State::Closing`, and a runnable will be dispatched to the
    164  // I/O thread to notify callbacks.
    165  enum class State { Active, Closing, Closed };
    166  std::atomic<State> mState = State::Active;
    167 
    168 #ifdef FUZZING_SNAPSHOT
    169  std::atomic<bool> mBlockSendRecv = false;
    170 #endif
    171 
    172  // WARNING: Must only be accessed on the IO thread.
    173  WeakPtr<mozilla::ipc::GeckoChildProcessHost> mChildProcessHost;
    174 };
    175 
    176 }  // namespace mozilla::ipc
    177 
    178 #endif