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