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/. */
7 #ifndef mozilla_ipc_NodeController_h
8 #define mozilla_ipc_NodeController_h
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"
22 namespace mozilla::ipc
{
24 class GeckoChildProcessHost
;
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
;
39 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(NodeController
, override
)
41 // Return the global singleton instance. The returned value is only valid
42 // while the IO thread is alive.
43 static NodeController
* GetSingleton();
45 class PortObserver
: public UserData
{
47 virtual void OnPortStatusChanged() = 0;
50 ~PortObserver() override
= default;
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.
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};
61 bool IsBroker() const { return mName
== kBrokerNodeName
; }
63 // Mint a new connected pair of ports within the current process.
64 std::pair
<ScopedPort
, ScopedPort
> CreatePortPair();
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
);
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
);
74 // See `mojo::core::ports::Node::GetStatus`
75 Maybe
<PortStatus
> GetStatus(const PortRef
& aPort
);
77 // See `mojo::core::ports::Node::ClosePort`
78 void ClosePort(const PortRef
& aPort
);
80 // Send a message to the the port's connected peer.
81 bool SendUserMessage(const PortRef
& aPort
, UniquePtr
<IPC::Message
> aMessage
);
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
);
89 // Called in the broker process from GeckoChildProcessHost to introduce a new
90 // child process into the network. Returns a `PortRef` which can be used to
91 // communicate with the `PortRef` returned from `InitChildProcess`, and a
92 // reference to the `NodeChannel` created for the new process. The port can
93 // immediately have messages sent to it.
94 std::tuple
<ScopedPort
, RefPtr
<NodeChannel
>> InviteChildProcess(
95 UniquePtr
<IPC::Channel
> aChannel
,
96 GeckoChildProcessHost
* aChildProcessHost
);
98 // Called as the IO thread is started in the parent process.
99 static void InitBrokerProcess();
101 // Called as the IO thread is started in a child process.
102 static ScopedPort
InitChildProcess(UniquePtr
<IPC::Channel
> aChannel
,
103 base::ProcessId aParentPid
);
105 // Called when the IO thread is torn down.
106 static void CleanUp();
109 explicit NodeController(const NodeName
& aName
);
112 UniquePtr
<IPC::Message
> SerializeEventMessage(
113 UniquePtr
<Event
> aEvent
, const NodeName
* aRelayTarget
= nullptr,
114 uint32_t aType
= EVENT_MESSAGE_TYPE
);
115 UniquePtr
<Event
> DeserializeEventMessage(UniquePtr
<IPC::Message
> aMessage
,
116 NodeName
* aRelayTarget
= nullptr);
118 // Get the `NodeChannel` for the named node.
119 already_AddRefed
<NodeChannel
> GetNodeChannel(const NodeName
& aName
);
121 // Stop communicating with this peer. Must be called on the IO thread.
122 void DropPeer(NodeName aNodeName
);
125 void OnEventMessage(const NodeName
& aFromNode
,
126 UniquePtr
<IPC::Message
> aMessage
) override
;
127 void OnBroadcast(const NodeName
& aFromNode
,
128 UniquePtr
<IPC::Message
> aMessage
) override
;
129 void OnIntroduce(const NodeName
& aFromNode
,
130 NodeChannel::Introduction aIntroduction
) override
;
131 void OnRequestIntroduction(const NodeName
& aFromNode
,
132 const NodeName
& aName
) override
;
133 void OnAcceptInvite(const NodeName
& aFromNode
, const NodeName
& aRealName
,
134 const PortName
& aInitialPort
) override
;
135 void OnChannelError(const NodeName
& aFromNode
) override
;
137 // NodeDelegate Implementation
138 void ForwardEvent(const NodeName
& aNode
, UniquePtr
<Event
> aEvent
) override
;
139 void BroadcastEvent(UniquePtr
<Event
> aEvent
) override
;
140 void PortStatusChanged(const PortRef
& aPortRef
) override
;
142 const NodeName mName
;
143 const UniquePtr
<Node
> mNode
;
146 using NodeMap
= nsTHashMap
<NodeNameHashKey
, T
>;
149 // The channel which is being invited. This will have a temporary name until
150 // the invite is completed.
151 RefPtr
<NodeChannel
> mChannel
;
152 // The port which will be merged with the port information from the new
153 // child process when recieved.
158 // Channels for connecting to all known peers.
159 NodeMap
<RefPtr
<NodeChannel
>> mPeers
;
161 // Messages which are queued for peers which we been introduced to yet.
162 NodeMap
<Queue
<UniquePtr
<IPC::Message
>, 64>> mPendingMessages
;
164 // Connections for peers being invited to the network.
165 NodeMap
<Invite
> mInvites
;
167 // Ports which are waiting to be merged by a particular peer node.
168 NodeMap
<nsTArray
<PortRef
>> mPendingMerges
;
171 DataMutex
<State
> mState
{"NodeController::mState"};
174 } // namespace mozilla::ipc