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
5  * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
6 
7 #ifndef IPC_GLUE_ENDPOINT_H_
8 #define IPC_GLUE_ENDPOINT_H_
9 
10 #include <utility>
11 #include "CrashAnnotations.h"
12 #include "base/process.h"
13 #include "base/process_util.h"
14 #include "mozilla/Assertions.h"
15 #include "mozilla/Maybe.h"
16 #include "mozilla/UniquePtr.h"
17 #include "mozilla/ipc/MessageLink.h"
18 #include "mozilla/ipc/Transport.h"
19 #include "mozilla/ipc/NodeController.h"
20 #include "mozilla/ipc/ScopedPort.h"
21 #include "nsXULAppAPI.h"
22 #include "nscore.h"
23 
24 namespace IPC {
25 template <class P>
26 struct ParamTraits;
27 }
28 
29 namespace mozilla {
30 namespace ipc {
31 
32 struct PrivateIPDLInterface {};
33 
34 /**
35  * An endpoint represents one end of a partially initialized IPDL channel. To
36  * set up a new top-level protocol:
37  *
38  * Endpoint<PFooParent> parentEp;
39  * Endpoint<PFooChild> childEp;
40  * nsresult rv;
41  * rv = PFoo::CreateEndpoints(parentPid, childPid, &parentEp, &childEp);
42  *
43  * You're required to pass in parentPid and childPid, which are the pids of the
44  * processes in which the parent and child endpoints will be used.
45  *
46  * Endpoints can be passed in IPDL messages or sent to other threads using
47  * PostTask. Once an Endpoint has arrived at its destination process and thread,
48  * you need to create the top-level actor and bind it to the endpoint:
49  *
50  * FooParent* parent = new FooParent();
51  * bool rv1 = parentEp.Bind(parent, processActor);
52  * bool rv2 = parent->SendBar(...);
53  *
54  * (See Bind below for an explanation of processActor.) Once the actor is bound
55  * to the endpoint, it can send and receive messages.
56  */
57 template <class PFooSide>
58 class Endpoint {
59  public:
60   using ProcessId = base::ProcessId;
61 
62   Endpoint() = default;
63 
Endpoint(const PrivateIPDLInterface &,ScopedPort aPort,ProcessId aMyPid,ProcessId aOtherPid)64   Endpoint(const PrivateIPDLInterface&, ScopedPort aPort, ProcessId aMyPid,
65            ProcessId aOtherPid)
66       : mPort(std::move(aPort)), mMyPid(aMyPid), mOtherPid(aOtherPid) {}
67 
68   Endpoint(const Endpoint&) = delete;
69   Endpoint(Endpoint&& aOther) = default;
70 
71   Endpoint& operator=(const Endpoint&) = delete;
72   Endpoint& operator=(Endpoint&& aOther) = default;
73 
OtherPid()74   ProcessId OtherPid() const { return mOtherPid; }
75 
76   // This method binds aActor to this endpoint. After this call, the actor can
77   // be used to send and receive messages. The endpoint becomes invalid.
Bind(PFooSide * aActor)78   bool Bind(PFooSide* aActor) {
79     MOZ_RELEASE_ASSERT(IsValid());
80     MOZ_RELEASE_ASSERT(mMyPid == base::GetCurrentProcId());
81     return aActor->Open(std::move(mPort), mOtherPid);
82   }
83 
IsValid()84   bool IsValid() const { return mPort.IsValid(); }
85 
86  private:
87   friend struct IPC::ParamTraits<Endpoint<PFooSide>>;
88 
89   ScopedPort mPort;
90   ProcessId mMyPid = 0;
91   ProcessId mOtherPid = 0;
92 };
93 
94 #if defined(XP_MACOSX)
95 void AnnotateCrashReportWithErrno(CrashReporter::Annotation tag, int error);
96 #else
97 inline void AnnotateCrashReportWithErrno(CrashReporter::Annotation tag,
98                                          int error) {}
99 #endif
100 
101 // This function is used internally to create a pair of Endpoints. See the
102 // comment above Endpoint for a description of how it might be used.
103 template <class PFooParent, class PFooChild>
104 nsresult CreateEndpoints(const PrivateIPDLInterface& aPrivate,
105                          base::ProcessId aParentDestPid,
106                          base::ProcessId aChildDestPid,
107                          Endpoint<PFooParent>* aParentEndpoint,
108                          Endpoint<PFooChild>* aChildEndpoint) {
109   MOZ_RELEASE_ASSERT(aParentDestPid);
110   MOZ_RELEASE_ASSERT(aChildDestPid);
111 
112   auto [parentPort, childPort] =
113       NodeController::GetSingleton()->CreatePortPair();
114   *aParentEndpoint = Endpoint<PFooParent>(aPrivate, std::move(parentPort),
115                                           aParentDestPid, aChildDestPid);
116   *aChildEndpoint = Endpoint<PFooChild>(aPrivate, std::move(childPort),
117                                         aChildDestPid, aParentDestPid);
118   return NS_OK;
119 }
120 
121 /**
122  * A managed endpoint represents one end of a partially initialized managed
123  * IPDL actor. It is used for situations where the usual IPDL Constructor
124  * methods do not give sufficient control over the construction of actors, such
125  * as when constructing actors within replies, or constructing multiple related
126  * actors simultaneously.
127  *
128  * FooParent* parent = new FooParent();
129  * ManagedEndpoint<PFooChild> childEp = parentMgr->OpenPFooEndpoint(parent);
130  *
131  * ManagedEndpoints should be sent using IPDL messages or other mechanisms to
132  * the other side of the manager channel. Once the ManagedEndpoint has arrived
133  * at its destination, you can create the actor, and bind it to the endpoint.
134  *
135  * FooChild* child = new FooChild();
136  * childMgr->BindPFooEndpoint(childEp, child);
137  *
138  * WARNING: If the remote side of an endpoint has not been bound before it
139  * begins to receive messages, an IPC routing error will occur, likely causing
140  * a browser crash.
141  */
142 template <class PFooSide>
143 class ManagedEndpoint {
144  public:
145   ManagedEndpoint() : mId(0) {}
146 
147   ManagedEndpoint(const PrivateIPDLInterface&, int32_t aId) : mId(aId) {}
148 
149   ManagedEndpoint(ManagedEndpoint&& aOther) : mId(aOther.mId) {
150     aOther.mId = 0;
151   }
152 
153   ManagedEndpoint& operator=(ManagedEndpoint&& aOther) {
154     mId = aOther.mId;
155     aOther.mId = 0;
156     return *this;
157   }
158 
159   bool IsValid() const { return mId != 0; }
160 
161   Maybe<int32_t> ActorId() const { return IsValid() ? Some(mId) : Nothing(); }
162 
163   bool operator==(const ManagedEndpoint& _o) const { return mId == _o.mId; }
164 
165  private:
166   friend struct IPC::ParamTraits<ManagedEndpoint<PFooSide>>;
167 
168   ManagedEndpoint(const ManagedEndpoint&) = delete;
169   ManagedEndpoint& operator=(const ManagedEndpoint&) = delete;
170 
171   // The routing ID for the to-be-created endpoint.
172   int32_t mId;
173 
174   // XXX(nika): Might be nice to have other info for assertions?
175   // e.g. mManagerId, mManagerType, etc.
176 };
177 
178 }  // namespace ipc
179 }  // namespace mozilla
180 
181 #endif  // IPC_GLUE_ENDPOINT_H_
182