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