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