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