forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			173 lines
		
	
	
	
		
			6.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			173 lines
		
	
	
	
		
			6.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- 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_NodeController_h
 | |
| #define mozilla_ipc_NodeController_h
 | |
| 
 | |
| #include "mojo/core/ports/event.h"
 | |
| #include "mojo/core/ports/name.h"
 | |
| #include "mojo/core/ports/node.h"
 | |
| #include "mojo/core/ports/node_delegate.h"
 | |
| #include "chrome/common/ipc_message.h"
 | |
| #include "mozilla/ipc/ProtocolUtils.h"
 | |
| #include "nsTHashMap.h"
 | |
| #include "mozilla/Queue.h"
 | |
| #include "mozilla/DataMutex.h"
 | |
| #include "mozilla/UniquePtr.h"
 | |
| #include "mozilla/ipc/NodeChannel.h"
 | |
| 
 | |
| namespace mozilla::ipc {
 | |
| 
 | |
| class NodeController final : public mojo::core::ports::NodeDelegate,
 | |
|                              public NodeChannel::Listener {
 | |
|   using NodeName = mojo::core::ports::NodeName;
 | |
|   using PortName = mojo::core::ports::PortName;
 | |
|   using PortRef = mojo::core::ports::PortRef;
 | |
|   using Event = mojo::core::ports::Event;
 | |
|   using Node = mojo::core::ports::Node;
 | |
|   using UserData = mojo::core::ports::UserData;
 | |
|   using PortStatus = mojo::core::ports::PortStatus;
 | |
|   using UserMessageEvent = mojo::core::ports::UserMessageEvent;
 | |
|   using UserMessage = mojo::core::ports::UserMessage;
 | |
| 
 | |
|  public:
 | |
|   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(NodeController, override)
 | |
| 
 | |
|   // Return the global singleton instance. The returned value is only valid
 | |
|   // while the IO thread is alive.
 | |
|   static NodeController* GetSingleton();
 | |
| 
 | |
|   class PortObserver : public UserData {
 | |
|    public:
 | |
|     virtual void OnPortStatusChanged() = 0;
 | |
| 
 | |
|    protected:
 | |
|     ~PortObserver() override = default;
 | |
|   };
 | |
| 
 | |
|   // NOTE: For now there will always be a single broker process, and all
 | |
|   // processes in the graph need to be able to talk to it (the parent process).
 | |
|   // Give it a fixed node name for now to simplify things.
 | |
|   //
 | |
|   // If we ever decide to have multiple node networks intercommunicating (e.g.
 | |
|   // multiple instances or background services), we may need to change this.
 | |
|   static constexpr NodeName kBrokerNodeName{0x1, 0x1};
 | |
| 
 | |
|   bool IsBroker() const { return mName == kBrokerNodeName; }
 | |
| 
 | |
|   // Mint a new connected pair of ports within the current process.
 | |
|   std::pair<ScopedPort, ScopedPort> CreatePortPair();
 | |
| 
 | |
|   // Get a reference to the port with the given name. Returns an invalid
 | |
|   // `PortRef` if the name wasn't found.
 | |
|   PortRef GetPort(const PortName& aName);
 | |
| 
 | |
|   // Set the observer for the given port. This observer will be notified when
 | |
|   // the status of the port changes.
 | |
|   void SetPortObserver(const PortRef& aPort, PortObserver* aObserver);
 | |
| 
 | |
|   // See `mojo::core::ports::Node::GetStatus`
 | |
|   Maybe<PortStatus> GetStatus(const PortRef& aPort);
 | |
| 
 | |
|   // See `mojo::core::ports::Node::ClosePort`
 | |
|   void ClosePort(const PortRef& aPort);
 | |
| 
 | |
|   // Send a message to the the port's connected peer.
 | |
|   bool SendUserMessage(const PortRef& aPort, UniquePtr<IPC::Message> aMessage);
 | |
| 
 | |
|   // Get the next message from the port's message queue.
 | |
|   // Will set `*aMessage` to the found message, or `nullptr`.
 | |
|   // Returns `false` and sets `*aMessage` to `nullptr` if no further messages
 | |
|   // will be delivered to this port as its peer has been closed.
 | |
|   bool GetMessage(const PortRef& aPort, UniquePtr<IPC::Message>* aMessage);
 | |
| 
 | |
|   // Called in the broker process from GeckoChildProcessHost to introduce a new
 | |
|   // child process into the network. Returns a `PortRef` which can be used to
 | |
|   // communicate with the `PortRef` returned from `InitChildProcess`, and a
 | |
|   // reference to the `NodeChannel` created for the new process. The port can
 | |
|   // immediately have messages sent to it.
 | |
|   std::tuple<ScopedPort, RefPtr<NodeChannel>> InviteChildProcess(
 | |
|       UniquePtr<IPC::Channel> aChannel);
 | |
| 
 | |
|   // Called as the IO thread is started in the parent process.
 | |
|   static void InitBrokerProcess();
 | |
| 
 | |
|   // Called as the IO thread is started in a child process.
 | |
|   static ScopedPort InitChildProcess(UniquePtr<IPC::Channel> aChannel,
 | |
|                                      int32_t aParentPid = -1);
 | |
| 
 | |
|   // Called when the IO thread is torn down.
 | |
|   static void CleanUp();
 | |
| 
 | |
|  private:
 | |
|   explicit NodeController(const NodeName& aName);
 | |
|   ~NodeController();
 | |
| 
 | |
|   UniquePtr<IPC::Message> SerializeEventMessage(
 | |
|       UniquePtr<Event> aEvent, const NodeName* aRelayTarget = nullptr,
 | |
|       uint32_t aType = EVENT_MESSAGE_TYPE);
 | |
|   UniquePtr<Event> DeserializeEventMessage(UniquePtr<IPC::Message> aMessage,
 | |
|                                            NodeName* aRelayTarget = nullptr);
 | |
| 
 | |
|   // Get the `NodeChannel` for the named node.
 | |
|   already_AddRefed<NodeChannel> GetNodeChannel(const NodeName& aName);
 | |
| 
 | |
|   // Stop communicating with this peer. Must be called on the IO thread.
 | |
|   void DropPeer(NodeName aNodeName);
 | |
| 
 | |
|   // Message Handlers
 | |
|   void OnEventMessage(const NodeName& aFromNode,
 | |
|                       UniquePtr<IPC::Message> aMessage) override;
 | |
|   void OnBroadcast(const NodeName& aFromNode,
 | |
|                    UniquePtr<IPC::Message> aMessage) override;
 | |
|   void OnIntroduce(const NodeName& aFromNode,
 | |
|                    NodeChannel::Introduction aIntroduction) override;
 | |
|   void OnRequestIntroduction(const NodeName& aFromNode,
 | |
|                              const NodeName& aName) override;
 | |
|   void OnAcceptInvite(const NodeName& aFromNode, const NodeName& aRealName,
 | |
|                       const PortName& aInitialPort) override;
 | |
|   void OnChannelError(const NodeName& aFromNode) override;
 | |
| 
 | |
|   // NodeDelegate Implementation
 | |
|   void ForwardEvent(const NodeName& aNode, UniquePtr<Event> aEvent) override;
 | |
|   void BroadcastEvent(UniquePtr<Event> aEvent) override;
 | |
|   void PortStatusChanged(const PortRef& aPortRef) override;
 | |
| 
 | |
|   const NodeName mName;
 | |
|   const UniquePtr<Node> mNode;
 | |
| 
 | |
|   template <class T>
 | |
|   using NodeMap = nsTHashMap<NodeNameHashKey, T>;
 | |
| 
 | |
|   struct Invite {
 | |
|     // The channel which is being invited. This will have a temporary name until
 | |
|     // the invite is completed.
 | |
|     RefPtr<NodeChannel> mChannel;
 | |
|     // The port which will be merged with the port information from the new
 | |
|     // child process when recieved.
 | |
|     PortRef mToMerge;
 | |
|   };
 | |
| 
 | |
|   struct State {
 | |
|     // Channels for connecting to all known peers.
 | |
|     NodeMap<RefPtr<NodeChannel>> mPeers;
 | |
| 
 | |
|     // Messages which are queued for peers which we been introduced to yet.
 | |
|     NodeMap<Queue<UniquePtr<IPC::Message>, 64>> mPendingMessages;
 | |
| 
 | |
|     // Connections for peers being invited to the network.
 | |
|     NodeMap<Invite> mInvites;
 | |
| 
 | |
|     // Ports which are waiting to be merged by a particular peer node.
 | |
|     NodeMap<nsTArray<PortRef>> mPendingMerges;
 | |
|   };
 | |
| 
 | |
|   DataMutex<State> mState{"NodeController::mState"};
 | |
| };
 | |
| 
 | |
| }  // namespace mozilla::ipc
 | |
| 
 | |
| #endif
 | 
