Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: sw=4 ts=4 et :
3 : */
4 : /* This Source Code Form is subject to the terms of the Mozilla Public
5 : * License, v. 2.0. If a copy of the MPL was not distributed with this
6 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 :
8 : #ifndef mozilla_ipc_ProtocolUtils_h
9 : #define mozilla_ipc_ProtocolUtils_h 1
10 :
11 : #include "base/id_map.h"
12 : #include "base/process.h"
13 : #include "base/process_util.h"
14 : #include "chrome/common/ipc_message_utils.h"
15 :
16 : #include "prenv.h"
17 :
18 : #include "IPCMessageStart.h"
19 : #include "mozilla/AlreadyAddRefed.h"
20 : #include "mozilla/Attributes.h"
21 : #include "mozilla/ipc/FileDescriptor.h"
22 : #include "mozilla/ipc/Shmem.h"
23 : #include "mozilla/ipc/Transport.h"
24 : #include "mozilla/ipc/MessageLink.h"
25 : #include "mozilla/LinkedList.h"
26 : #include "mozilla/Maybe.h"
27 : #include "mozilla/MozPromise.h"
28 : #include "mozilla/Mutex.h"
29 : #include "mozilla/NotNull.h"
30 : #include "mozilla/UniquePtr.h"
31 : #include "MainThreadUtils.h"
32 :
33 : #if defined(ANDROID) && defined(DEBUG)
34 : #include <android/log.h>
35 : #endif
36 :
37 : template<typename T> class nsTHashtable;
38 : template<typename T> class nsPtrHashKey;
39 :
40 : // WARNING: this takes into account the private, special-message-type
41 : // enum in ipc_channel.h. They need to be kept in sync.
42 : namespace {
43 : // XXX the max message ID is actually kuint32max now ... when this
44 : // changed, the assumptions of the special message IDs changed in that
45 : // they're not carving out messages from likely-unallocated space, but
46 : // rather carving out messages from the end of space allocated to
47 : // protocol 0. Oops! We can get away with this until protocol 0
48 : // starts approaching its 65,536th message.
49 : enum {
50 : BUILD_ID_MESSAGE_TYPE = kuint16max - 7,
51 : CHANNEL_OPENED_MESSAGE_TYPE = kuint16max - 6,
52 : SHMEM_DESTROYED_MESSAGE_TYPE = kuint16max - 5,
53 : SHMEM_CREATED_MESSAGE_TYPE = kuint16max - 4,
54 : GOODBYE_MESSAGE_TYPE = kuint16max - 3,
55 : CANCEL_MESSAGE_TYPE = kuint16max - 2,
56 :
57 : // kuint16max - 1 is used by ipc_channel.h.
58 : };
59 :
60 : } // namespace
61 :
62 : class nsIEventTarget;
63 :
64 : namespace mozilla {
65 : namespace dom {
66 : class ContentParent;
67 : } // namespace dom
68 :
69 : namespace net {
70 : class NeckoParent;
71 : } // namespace net
72 :
73 : namespace ipc {
74 :
75 : class MessageChannel;
76 :
77 : #ifdef XP_WIN
78 : const base::ProcessHandle kInvalidProcessHandle = INVALID_HANDLE_VALUE;
79 :
80 : // In theory, on Windows, this is a valid process ID, but in practice they are
81 : // currently divisible by four. Process IDs share the kernel handle allocation
82 : // code and they are guaranteed to be divisible by four.
83 : // As this could change for process IDs we shouldn't generally rely on this
84 : // property, however even if that were to change, it seems safe to rely on this
85 : // particular value never being used.
86 : const base::ProcessId kInvalidProcessId = kuint32max;
87 : #else
88 : const base::ProcessHandle kInvalidProcessHandle = -1;
89 : const base::ProcessId kInvalidProcessId = -1;
90 : #endif
91 :
92 : // Scoped base::ProcessHandle to ensure base::CloseProcessHandle is called.
93 : struct ScopedProcessHandleTraits
94 : {
95 : typedef base::ProcessHandle type;
96 :
97 0 : static type empty()
98 : {
99 0 : return kInvalidProcessHandle;
100 : }
101 :
102 0 : static void release(type aProcessHandle)
103 : {
104 0 : if (aProcessHandle && aProcessHandle != kInvalidProcessHandle) {
105 0 : base::CloseProcessHandle(aProcessHandle);
106 : }
107 0 : }
108 : };
109 : typedef mozilla::Scoped<ScopedProcessHandleTraits> ScopedProcessHandle;
110 :
111 : class ProtocolFdMapping;
112 : class ProtocolCloneContext;
113 :
114 : // Used to pass references to protocol actors across the wire.
115 : // Actors created on the parent-side have a positive ID, and actors
116 : // allocated on the child side have a negative ID.
117 : struct ActorHandle
118 : {
119 : int mId;
120 : };
121 :
122 : // What happens if Interrupt calls race?
123 : enum RacyInterruptPolicy {
124 : RIPError,
125 : RIPChildWins,
126 : RIPParentWins
127 : };
128 :
129 : class IToplevelProtocol;
130 :
131 : class IProtocol : public HasResultCodes
132 : {
133 : public:
134 : enum ActorDestroyReason {
135 : FailedConstructor,
136 : Deletion,
137 : AncestorDeletion,
138 : NormalShutdown,
139 : AbnormalShutdown
140 : };
141 :
142 : typedef base::ProcessId ProcessId;
143 : typedef IPC::Message Message;
144 : typedef IPC::MessageInfo MessageInfo;
145 :
146 394 : IProtocol(Side aSide) : mId(0), mSide(aSide), mManager(nullptr), mChannel(nullptr) {}
147 :
148 : virtual int32_t Register(IProtocol*);
149 : virtual int32_t RegisterID(IProtocol*, int32_t);
150 : virtual IProtocol* Lookup(int32_t);
151 : virtual void Unregister(int32_t);
152 : virtual void RemoveManagee(int32_t, IProtocol*) = 0;
153 :
154 : virtual Shmem::SharedMemory* CreateSharedMemory(
155 : size_t, SharedMemory::SharedMemoryType, bool, int32_t*);
156 : virtual Shmem::SharedMemory* LookupSharedMemory(int32_t);
157 : virtual bool IsTrackingSharedMemory(Shmem::SharedMemory*);
158 : virtual bool DestroySharedMemory(Shmem&);
159 :
160 : // XXX odd ducks, acknowledged
161 : virtual ProcessId OtherPid() const;
162 41 : Side GetSide() const { return mSide; }
163 :
164 : virtual const char* ProtocolName() const = 0;
165 : void FatalError(const char* const aErrorMsg) const;
166 : virtual void HandleFatalError(const char* aProtocolName, const char* aErrorMsg) const;
167 :
168 : Maybe<IProtocol*> ReadActor(const IPC::Message* aMessage, PickleIterator* aIter, bool aNullable,
169 : const char* aActorDescription, int32_t aProtocolTypeId);
170 :
171 : virtual Result OnMessageReceived(const Message& aMessage) = 0;
172 : virtual Result OnMessageReceived(const Message& aMessage, Message *& aReply) = 0;
173 : virtual Result OnCallReceived(const Message& aMessage, Message *& aReply) = 0;
174 :
175 : virtual int32_t GetProtocolTypeId() = 0;
176 :
177 643 : int32_t Id() const { return mId; }
178 401 : IProtocol* Manager() const { return mManager; }
179 0 : virtual const MessageChannel* GetIPCChannel() const { return mChannel; }
180 521 : virtual MessageChannel* GetIPCChannel() { return mChannel; }
181 :
182 : bool AllocShmem(size_t aSize, Shmem::SharedMemory::SharedMemoryType aType, Shmem* aOutMem);
183 : bool AllocUnsafeShmem(size_t aSize, Shmem::SharedMemory::SharedMemoryType aType, Shmem* aOutMem);
184 : bool DeallocShmem(Shmem& aMem);
185 :
186 : // Sets an event target to which all messages for aActor will be
187 : // dispatched. This method must be called before right before the SendPFoo
188 : // message for aActor is sent. And SendPFoo *must* be called if
189 : // SetEventTargetForActor is called. The receiver when calling
190 : // SetEventTargetForActor must be the actor that will be the manager for
191 : // aActor.
192 : void SetEventTargetForActor(IProtocol* aActor, nsIEventTarget* aEventTarget);
193 :
194 : // Replace the event target for the messages of aActor. There must not be
195 : // any messages of aActor in the task queue, or we might run into some
196 : // unexpected behavior.
197 : void ReplaceEventTargetForActor(IProtocol* aActor,
198 : nsIEventTarget* aEventTarget);
199 :
200 : // Returns the event target set by SetEventTargetForActor() if available.
201 : virtual nsIEventTarget* GetActorEventTarget();
202 :
203 : protected:
204 : friend class IToplevelProtocol;
205 :
206 80 : void SetId(int32_t aId) { mId = aId; }
207 0 : void ResetManager() { mManager = nullptr; }
208 : void SetManager(IProtocol* aManager);
209 71 : void SetIPCChannel(MessageChannel* aChannel) { mChannel = aChannel; }
210 :
211 : virtual void SetEventTargetForActorInternal(IProtocol* aActor, nsIEventTarget* aEventTarget);
212 : virtual void ReplaceEventTargetForActorInternal(
213 : IProtocol* aActor,
214 : nsIEventTarget* aEventTarget);
215 :
216 : virtual already_AddRefed<nsIEventTarget>
217 : GetActorEventTargetInternal(IProtocol* aActor);
218 :
219 : static const int32_t kNullActorId = 0;
220 : static const int32_t kFreedActorId = 1;
221 :
222 : private:
223 : int32_t mId;
224 : Side mSide;
225 : IProtocol* mManager;
226 : MessageChannel* mChannel;
227 : };
228 :
229 : typedef IPCMessageStart ProtocolId;
230 :
231 : #define IPC_OK() mozilla::ipc::IPCResult::Ok()
232 : #define IPC_FAIL(actor, why) mozilla::ipc::IPCResult::Fail(WrapNotNull(actor), __func__, (why))
233 : #define IPC_FAIL_NO_REASON(actor) mozilla::ipc::IPCResult::Fail(WrapNotNull(actor), __func__)
234 :
235 : /**
236 : * All message deserializer and message handler should return this
237 : * type via above macros. We use a less generic name here to avoid
238 : * conflict with mozilla::Result because we have quite a few using
239 : * namespace mozilla::ipc; in the code base.
240 : */
241 : class IPCResult {
242 : public:
243 471 : static IPCResult Ok() { return IPCResult(true); }
244 : static IPCResult Fail(NotNull<IProtocol*> aActor, const char* aWhere, const char* aWhy = "");
245 454 : MOZ_IMPLICIT operator bool() const { return mSuccess; }
246 : private:
247 471 : explicit IPCResult(bool aResult) : mSuccess(aResult) {}
248 : bool mSuccess;
249 : };
250 :
251 : template<class PFooSide>
252 : class Endpoint;
253 :
254 : /**
255 : * All top-level protocols should inherit this class.
256 : *
257 : * IToplevelProtocol tracks all top-level protocol actors created from
258 : * this protocol actor.
259 : */
260 : class IToplevelProtocol : public IProtocol
261 : {
262 : template<class PFooSide> friend class Endpoint;
263 :
264 : protected:
265 : explicit IToplevelProtocol(ProtocolId aProtoId, Side aSide);
266 : ~IToplevelProtocol();
267 :
268 : public:
269 24 : void SetTransport(UniquePtr<Transport> aTrans)
270 : {
271 24 : mTrans = Move(aTrans);
272 24 : }
273 :
274 : Transport* GetTransport() const { return mTrans.get(); }
275 :
276 : ProtocolId GetProtocolId() const { return mProtocolId; }
277 :
278 : base::ProcessId OtherPid() const;
279 : void SetOtherProcessId(base::ProcessId aOtherPid);
280 :
281 : bool TakeMinidump(nsIFile** aDump, uint32_t* aSequence);
282 :
283 : virtual void OnChannelClose() = 0;
284 : virtual void OnChannelError() = 0;
285 0 : virtual void ProcessingError(Result aError, const char* aMsgName) {}
286 17 : virtual void OnChannelConnected(int32_t peer_pid) {}
287 :
288 : bool Open(mozilla::ipc::Transport* aTransport,
289 : base::ProcessId aOtherPid,
290 : MessageLoop* aThread = nullptr,
291 : mozilla::ipc::Side aSide = mozilla::ipc::UnknownSide);
292 :
293 : bool Open(MessageChannel* aChannel,
294 : MessageLoop* aMessageLoop,
295 : mozilla::ipc::Side aSide = mozilla::ipc::UnknownSide);
296 :
297 : void Close();
298 :
299 : void SetReplyTimeoutMs(int32_t aTimeoutMs);
300 :
301 : virtual int32_t Register(IProtocol*);
302 : virtual int32_t RegisterID(IProtocol*, int32_t);
303 : virtual IProtocol* Lookup(int32_t);
304 : virtual void Unregister(int32_t);
305 :
306 : virtual Shmem::SharedMemory* CreateSharedMemory(
307 : size_t, SharedMemory::SharedMemoryType, bool, int32_t*);
308 : virtual Shmem::SharedMemory* LookupSharedMemory(int32_t);
309 : virtual bool IsTrackingSharedMemory(Shmem::SharedMemory*);
310 : virtual bool DestroySharedMemory(Shmem&);
311 :
312 : void DeallocShmems();
313 :
314 : bool ShmemCreated(const Message& aMsg);
315 : bool ShmemDestroyed(const Message& aMsg);
316 :
317 0 : virtual bool ShouldContinueFromReplyTimeout() {
318 0 : return false;
319 : }
320 :
321 : // WARNING: This function is called with the MessageChannel monitor held.
322 0 : virtual void IntentionalCrash() {
323 0 : MOZ_CRASH("Intentional IPDL crash");
324 : }
325 :
326 : // The code here is only useful for fuzzing. It should not be used for any
327 : // other purpose.
328 : #ifdef DEBUG
329 : // Returns true if we should simulate a timeout.
330 : // WARNING: This is a testing-only function that is called with the
331 : // MessageChannel monitor held. Don't do anything fancy here or we could
332 : // deadlock.
333 3 : virtual bool ArtificialTimeout() {
334 3 : return false;
335 : }
336 :
337 : // Returns true if we want to cause the worker thread to sleep with the
338 : // monitor unlocked.
339 3 : virtual bool NeedArtificialSleep() {
340 3 : return false;
341 : }
342 :
343 : // This function should be implemented to sleep for some amount of time on
344 : // the worker thread. Will only be called if NeedArtificialSleep() returns
345 : // true.
346 907 : virtual void ArtificialSleep() {}
347 : #else
348 : bool ArtificialTimeout() { return false; }
349 : bool NeedArtificialSleep() { return false; }
350 : void ArtificialSleep() {}
351 : #endif
352 :
353 0 : virtual void EnteredCxxStack() {}
354 0 : virtual void ExitedCxxStack() {}
355 0 : virtual void EnteredCall() {}
356 0 : virtual void ExitedCall() {}
357 :
358 : bool IsOnCxxStack() const;
359 :
360 0 : virtual RacyInterruptPolicy MediateInterruptRace(const MessageInfo& parent,
361 : const MessageInfo& child)
362 : {
363 0 : return RIPChildWins;
364 : }
365 :
366 : /**
367 : * Return true if windows messages can be handled while waiting for a reply
368 : * to a sync IPDL message.
369 : */
370 3 : virtual bool HandleWindowsMessages(const Message& aMsg) const { return true; }
371 :
372 3 : virtual void OnEnteredSyncSend() {
373 3 : }
374 3 : virtual void OnExitedSyncSend() {
375 3 : }
376 :
377 0 : virtual void ProcessRemoteNativeEventsInInterruptCall() {
378 0 : }
379 :
380 : virtual already_AddRefed<nsIEventTarget>
381 : GetMessageEventTarget(const Message& aMsg);
382 :
383 : already_AddRefed<nsIEventTarget>
384 : GetActorEventTarget(IProtocol* aActor);
385 :
386 : virtual nsIEventTarget*
387 : GetActorEventTarget();
388 :
389 454 : virtual void OnChannelReceivedMessage(const Message& aMsg) {}
390 :
391 473 : bool IsMainThreadProtocol() const { return mIsMainThreadProtocol; }
392 38 : void SetIsMainThreadProtocol() { mIsMainThreadProtocol = NS_IsMainThread(); }
393 :
394 : protected:
395 : // Override this method in top-level protocols to change the event target
396 : // for a new actor (and its sub-actors).
397 : virtual already_AddRefed<nsIEventTarget>
398 30 : GetConstructedEventTarget(const Message& aMsg) { return nullptr; }
399 :
400 : // Override this method in top-level protocols to change the event target
401 : // for specific messages.
402 : virtual already_AddRefed<nsIEventTarget>
403 236 : GetSpecificMessageEventTarget(const Message& aMsg) { return nullptr; }
404 :
405 : virtual void SetEventTargetForActorInternal(IProtocol* aActor, nsIEventTarget* aEventTarget);
406 : virtual void ReplaceEventTargetForActorInternal(
407 : IProtocol* aActor,
408 : nsIEventTarget* aEventTarget);
409 :
410 : virtual already_AddRefed<nsIEventTarget>
411 : GetActorEventTargetInternal(IProtocol* aActor);
412 :
413 : private:
414 : ProtocolId mProtocolId;
415 : UniquePtr<Transport> mTrans;
416 : base::ProcessId mOtherPid;
417 : IDMap<IProtocol*> mActorMap;
418 : int32_t mLastRouteId;
419 : IDMap<Shmem::SharedMemory*> mShmemMap;
420 : Shmem::id_t mLastShmemId;
421 : bool mIsMainThreadProtocol;
422 :
423 : Mutex mEventTargetMutex;
424 : IDMap<nsCOMPtr<nsIEventTarget>> mEventTargetMap;
425 : };
426 :
427 14 : class IShmemAllocator
428 : {
429 : public:
430 : virtual bool AllocShmem(size_t aSize,
431 : mozilla::ipc::SharedMemory::SharedMemoryType aShmType,
432 : mozilla::ipc::Shmem* aShmem) = 0;
433 : virtual bool AllocUnsafeShmem(size_t aSize,
434 : mozilla::ipc::SharedMemory::SharedMemoryType aShmType,
435 : mozilla::ipc::Shmem* aShmem) = 0;
436 : virtual bool DeallocShmem(mozilla::ipc::Shmem& aShmem) = 0;
437 : };
438 :
439 : #define FORWARD_SHMEM_ALLOCATOR_TO(aImplClass) \
440 : virtual bool AllocShmem(size_t aSize, \
441 : mozilla::ipc::SharedMemory::SharedMemoryType aShmType, \
442 : mozilla::ipc::Shmem* aShmem) override \
443 : { return aImplClass::AllocShmem(aSize, aShmType, aShmem); } \
444 : virtual bool AllocUnsafeShmem(size_t aSize, \
445 : mozilla::ipc::SharedMemory::SharedMemoryType aShmType, \
446 : mozilla::ipc::Shmem* aShmem) override \
447 : { return aImplClass::AllocUnsafeShmem(aSize, aShmType, aShmem); } \
448 : virtual bool DeallocShmem(mozilla::ipc::Shmem& aShmem) override \
449 : { return aImplClass::DeallocShmem(aShmem); }
450 :
451 : inline bool
452 0 : LoggingEnabled()
453 : {
454 : #if defined(DEBUG) || defined(FUZZING)
455 0 : return !!PR_GetEnv("MOZ_IPC_MESSAGE_LOG");
456 : #else
457 : return false;
458 : #endif
459 : }
460 :
461 : inline bool
462 976 : LoggingEnabledFor(const char *aTopLevelProtocol)
463 : {
464 : #if defined(DEBUG) || defined(FUZZING)
465 976 : const char *filter = PR_GetEnv("MOZ_IPC_MESSAGE_LOG");
466 976 : if (!filter) {
467 976 : return false;
468 : }
469 0 : return strcmp(filter, "1") == 0 || strcmp(filter, aTopLevelProtocol) == 0;
470 : #else
471 : return false;
472 : #endif
473 : }
474 :
475 : enum class MessageDirection {
476 : eSending,
477 : eReceiving,
478 : };
479 :
480 : MOZ_NEVER_INLINE void
481 : LogMessageForProtocol(const char* aTopLevelProtocol, base::ProcessId aOtherPid,
482 : const char* aContextDescription,
483 : uint32_t aMessageId,
484 : MessageDirection aDirection);
485 :
486 : MOZ_NEVER_INLINE void
487 : ProtocolErrorBreakpoint(const char* aMsg);
488 :
489 : // The code generator calls this function for errors which come from the
490 : // methods of protocols. Doing this saves codesize by making the error
491 : // cases significantly smaller.
492 : MOZ_NEVER_INLINE void
493 : FatalError(const char* aProtocolName, const char* aMsg, bool aIsParent);
494 :
495 : // The code generator calls this function for errors which are not
496 : // protocol-specific: errors in generated struct methods or errors in
497 : // transition functions, for instance. Doing this saves codesize by
498 : // by making the error cases significantly smaller.
499 : MOZ_NEVER_INLINE void
500 : LogicError(const char* aMsg);
501 :
502 : MOZ_NEVER_INLINE void
503 : ActorIdReadError(const char* aActorDescription);
504 :
505 : MOZ_NEVER_INLINE void
506 : BadActorIdError(const char* aActorDescription);
507 :
508 : MOZ_NEVER_INLINE void
509 : ActorLookupError(const char* aActorDescription);
510 :
511 : MOZ_NEVER_INLINE void
512 : MismatchedActorTypeError(const char* aActorDescription);
513 :
514 : MOZ_NEVER_INLINE void
515 : UnionTypeReadError(const char* aUnionName);
516 :
517 : MOZ_NEVER_INLINE void
518 : ArrayLengthReadError(const char* aElementName);
519 :
520 : MOZ_NEVER_INLINE void
521 : SentinelReadError(const char* aElementName);
522 :
523 : struct PrivateIPDLInterface {};
524 :
525 : nsresult
526 : Bridge(const PrivateIPDLInterface&,
527 : MessageChannel*, base::ProcessId, MessageChannel*, base::ProcessId,
528 : ProtocolId, ProtocolId);
529 :
530 : bool
531 : Open(const PrivateIPDLInterface&,
532 : MessageChannel*, base::ProcessId, Transport::Mode,
533 : ProtocolId, ProtocolId);
534 :
535 : bool
536 : UnpackChannelOpened(const PrivateIPDLInterface&,
537 : const IPC::Message&,
538 : TransportDescriptor*, base::ProcessId*, ProtocolId*);
539 :
540 : #if defined(XP_WIN)
541 : // This is a restricted version of Windows' DuplicateHandle() function
542 : // that works inside the sandbox and can send handles but not retrieve
543 : // them. Unlike DuplicateHandle(), it takes a process ID rather than
544 : // a process handle. It returns true on success, false otherwise.
545 : bool
546 : DuplicateHandle(HANDLE aSourceHandle,
547 : DWORD aTargetProcessId,
548 : HANDLE* aTargetHandle,
549 : DWORD aDesiredAccess,
550 : DWORD aOptions);
551 : #endif
552 :
553 : /**
554 : * Annotate the crash reporter with the error code from the most recent system
555 : * call. Returns the system error.
556 : */
557 : #ifdef MOZ_CRASHREPORTER
558 : void AnnotateSystemError();
559 : #else
560 : #define AnnotateSystemError() do { } while (0)
561 : #endif
562 :
563 : /**
564 : * An endpoint represents one end of a partially initialized IPDL channel. To
565 : * set up a new top-level protocol:
566 : *
567 : * Endpoint<PFooParent> parentEp;
568 : * Endpoint<PFooChild> childEp;
569 : * nsresult rv;
570 : * rv = PFoo::CreateEndpoints(parentPid, childPid, &parentEp, &childEp);
571 : *
572 : * You're required to pass in parentPid and childPid, which are the pids of the
573 : * processes in which the parent and child endpoints will be used.
574 : *
575 : * Endpoints can be passed in IPDL messages or sent to other threads using
576 : * PostTask. Once an Endpoint has arrived at its destination process and thread,
577 : * you need to create the top-level actor and bind it to the endpoint:
578 : *
579 : * FooParent* parent = new FooParent();
580 : * bool rv1 = parentEp.Bind(parent, processActor);
581 : * bool rv2 = parent->SendBar(...);
582 : *
583 : * (See Bind below for an explanation of processActor.) Once the actor is bound
584 : * to the endpoint, it can send and receive messages.
585 : */
586 : template<class PFooSide>
587 : class Endpoint
588 : {
589 : public:
590 : typedef base::ProcessId ProcessId;
591 :
592 48 : Endpoint()
593 48 : : mValid(false)
594 48 : {}
595 :
596 26 : Endpoint(const PrivateIPDLInterface&,
597 : mozilla::ipc::Transport::Mode aMode,
598 : TransportDescriptor aTransport,
599 : ProcessId aMyPid,
600 : ProcessId aOtherPid,
601 : ProtocolId aProtocolId)
602 : : mValid(true)
603 : , mMode(aMode)
604 : , mTransport(aTransport)
605 : , mMyPid(aMyPid)
606 : , mOtherPid(aOtherPid)
607 26 : , mProtocolId(aProtocolId)
608 26 : {}
609 :
610 29 : Endpoint(Endpoint&& aOther)
611 29 : : mValid(aOther.mValid)
612 29 : , mMode(aOther.mMode)
613 : , mTransport(aOther.mTransport)
614 29 : , mMyPid(aOther.mMyPid)
615 29 : , mOtherPid(aOther.mOtherPid)
616 116 : , mProtocolId(aOther.mProtocolId)
617 : {
618 29 : aOther.mValid = false;
619 29 : }
620 :
621 32 : Endpoint& operator=(Endpoint&& aOther)
622 : {
623 32 : mValid = aOther.mValid;
624 32 : mMode = aOther.mMode;
625 32 : mTransport = aOther.mTransport;
626 32 : mMyPid = aOther.mMyPid;
627 32 : mOtherPid = aOther.mOtherPid;
628 32 : mProtocolId = aOther.mProtocolId;
629 :
630 32 : aOther.mValid = false;
631 32 : return *this;
632 : }
633 :
634 102 : ~Endpoint() {
635 102 : if (mValid) {
636 13 : CloseDescriptor(mTransport);
637 : }
638 102 : }
639 :
640 6 : ProcessId OtherPid() const {
641 6 : return mOtherPid;
642 : }
643 :
644 : // This method binds aActor to this endpoint. After this call, the actor can
645 : // be used to send and receive messages. The endpoint becomes invalid.
646 24 : bool Bind(PFooSide* aActor)
647 : {
648 24 : MOZ_RELEASE_ASSERT(mValid);
649 24 : MOZ_RELEASE_ASSERT(mMyPid == base::GetCurrentProcId());
650 :
651 48 : UniquePtr<Transport> t = mozilla::ipc::OpenDescriptor(mTransport, mMode);
652 24 : if (!t) {
653 0 : return false;
654 : }
655 24 : if (!aActor->Open(t.get(), mOtherPid, XRE_GetIOMessageLoop(),
656 24 : mMode == Transport::MODE_SERVER ? ParentSide : ChildSide)) {
657 0 : return false;
658 : }
659 24 : mValid = false;
660 24 : aActor->SetTransport(Move(t));
661 24 : return true;
662 : }
663 :
664 18 : bool IsValid() const {
665 18 : return mValid;
666 : }
667 :
668 : private:
669 : friend struct IPC::ParamTraits<Endpoint<PFooSide>>;
670 :
671 : Endpoint(const Endpoint&) = delete;
672 : Endpoint& operator=(const Endpoint&) = delete;
673 :
674 : bool mValid;
675 : mozilla::ipc::Transport::Mode mMode;
676 : TransportDescriptor mTransport;
677 : ProcessId mMyPid, mOtherPid;
678 : ProtocolId mProtocolId;
679 : };
680 :
681 : #if defined(MOZ_CRASHREPORTER) && defined(XP_MACOSX)
682 : void AnnotateCrashReportWithErrno(const char* tag, int error);
683 : #else
684 0 : static inline void AnnotateCrashReportWithErrno(const char* tag, int error)
685 0 : {}
686 : #endif
687 :
688 : // This function is used internally to create a pair of Endpoints. See the
689 : // comment above Endpoint for a description of how it might be used.
690 : template<class PFooParent, class PFooChild>
691 : nsresult
692 13 : CreateEndpoints(const PrivateIPDLInterface& aPrivate,
693 : base::ProcessId aParentDestPid,
694 : base::ProcessId aChildDestPid,
695 : ProtocolId aProtocol,
696 : ProtocolId aChildProtocol,
697 : Endpoint<PFooParent>* aParentEndpoint,
698 : Endpoint<PFooChild>* aChildEndpoint)
699 : {
700 13 : MOZ_RELEASE_ASSERT(aParentDestPid);
701 13 : MOZ_RELEASE_ASSERT(aChildDestPid);
702 :
703 13 : TransportDescriptor parentTransport, childTransport;
704 : nsresult rv;
705 13 : if (NS_FAILED(rv = CreateTransport(aParentDestPid, &parentTransport, &childTransport))) {
706 0 : AnnotateCrashReportWithErrno("IpcCreateEndpointsNsresult", int(rv));
707 0 : return rv;
708 : }
709 :
710 13 : *aParentEndpoint = Endpoint<PFooParent>(aPrivate, mozilla::ipc::Transport::MODE_SERVER,
711 : parentTransport, aParentDestPid, aChildDestPid, aProtocol);
712 :
713 13 : *aChildEndpoint = Endpoint<PFooChild>(aPrivate, mozilla::ipc::Transport::MODE_CLIENT,
714 : childTransport, aChildDestPid, aParentDestPid, aChildProtocol);
715 :
716 13 : return NS_OK;
717 : }
718 :
719 : void
720 : TableToArray(const nsTHashtable<nsPtrHashKey<void>>& aTable,
721 : nsTArray<void*>& aArray);
722 :
723 : const char* StringFromIPCMessageType(uint32_t aMessageType);
724 :
725 : } // namespace ipc
726 :
727 : template<typename Protocol>
728 473 : class ManagedContainer : public nsTHashtable<nsPtrHashKey<Protocol>>
729 : {
730 : typedef nsTHashtable<nsPtrHashKey<Protocol>> BaseClass;
731 :
732 : public:
733 : // Having the core logic work on void pointers, rather than typed pointers,
734 : // means that we can have one instance of this code out-of-line, rather
735 : // than several hundred instances of this code out-of-lined. (Those
736 : // repeated instances don't necessarily get folded together by the linker
737 : // because they contain member offsets and such that differ between the
738 : // functions.) We do have to pay for it with some eye-bleedingly bad casts,
739 : // though.
740 0 : void ToArray(nsTArray<Protocol*>& aArray) const {
741 0 : ::mozilla::ipc::TableToArray(*reinterpret_cast<const nsTHashtable<nsPtrHashKey<void>>*>
742 : (static_cast<const BaseClass*>(this)),
743 : reinterpret_cast<nsTArray<void*>&>(aArray));
744 0 : }
745 : };
746 :
747 : template<typename Protocol>
748 : Protocol*
749 927 : LoneManagedOrNullAsserts(const ManagedContainer<Protocol>& aManagees)
750 : {
751 927 : if (aManagees.IsEmpty()) {
752 281 : return nullptr;
753 : }
754 646 : MOZ_ASSERT(aManagees.Count() == 1);
755 646 : return aManagees.ConstIter().Get()->GetKey();
756 : }
757 :
758 : // appId's are for B2G only currently, where managees.Count() == 1. This is
759 : // not guaranteed currently in Desktop, so for paths used for desktop,
760 : // don't assert there's one managee.
761 : template<typename Protocol>
762 : Protocol*
763 0 : SingleManagedOrNull(const ManagedContainer<Protocol>& aManagees)
764 : {
765 0 : if (aManagees.Count() != 1) {
766 0 : return nullptr;
767 : }
768 0 : return aManagees.ConstIter().Get()->GetKey();
769 : }
770 :
771 : } // namespace mozilla
772 :
773 :
774 : namespace IPC {
775 :
776 : template <>
777 : struct ParamTraits<mozilla::ipc::ActorHandle>
778 : {
779 : typedef mozilla::ipc::ActorHandle paramType;
780 :
781 : static void Write(Message* aMsg, const paramType& aParam)
782 : {
783 : IPC::WriteParam(aMsg, aParam.mId);
784 : }
785 :
786 68 : static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
787 : {
788 : int id;
789 68 : if (IPC::ReadParam(aMsg, aIter, &id)) {
790 68 : aResult->mId = id;
791 68 : return true;
792 : }
793 0 : return false;
794 : }
795 :
796 : static void Log(const paramType& aParam, std::wstring* aLog)
797 : {
798 : aLog->append(StringPrintf(L"(%d)", aParam.mId));
799 : }
800 : };
801 :
802 : template<class PFooSide>
803 : struct ParamTraits<mozilla::ipc::Endpoint<PFooSide>>
804 : {
805 : typedef mozilla::ipc::Endpoint<PFooSide> paramType;
806 :
807 15 : static void Write(Message* aMsg, const paramType& aParam)
808 : {
809 15 : IPC::WriteParam(aMsg, aParam.mValid);
810 15 : if (!aParam.mValid) {
811 2 : return;
812 : }
813 :
814 13 : IPC::WriteParam(aMsg, static_cast<uint32_t>(aParam.mMode));
815 :
816 : // We duplicate the descriptor so that our own file descriptor remains
817 : // valid after the write. An alternative would be to set
818 : // aParam.mTransport.mValid to false, but that won't work because aParam
819 : // is const.
820 13 : mozilla::ipc::TransportDescriptor desc = mozilla::ipc::DuplicateDescriptor(aParam.mTransport);
821 13 : IPC::WriteParam(aMsg, desc);
822 :
823 13 : IPC::WriteParam(aMsg, aParam.mMyPid);
824 13 : IPC::WriteParam(aMsg, aParam.mOtherPid);
825 13 : IPC::WriteParam(aMsg, static_cast<uint32_t>(aParam.mProtocolId));
826 : }
827 :
828 14 : static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
829 : {
830 14 : MOZ_RELEASE_ASSERT(!aResult->mValid);
831 :
832 14 : if (!IPC::ReadParam(aMsg, aIter, &aResult->mValid)) {
833 0 : return false;
834 : }
835 14 : if (!aResult->mValid) {
836 : // Object is empty, but read succeeded.
837 2 : return true;
838 : }
839 :
840 : uint32_t mode, protocolId;
841 36 : if (!IPC::ReadParam(aMsg, aIter, &mode) ||
842 24 : !IPC::ReadParam(aMsg, aIter, &aResult->mTransport) ||
843 24 : !IPC::ReadParam(aMsg, aIter, &aResult->mMyPid) ||
844 36 : !IPC::ReadParam(aMsg, aIter, &aResult->mOtherPid) ||
845 12 : !IPC::ReadParam(aMsg, aIter, &protocolId)) {
846 0 : return false;
847 : }
848 12 : aResult->mMode = Channel::Mode(mode);
849 12 : aResult->mProtocolId = mozilla::ipc::ProtocolId(protocolId);
850 12 : return true;
851 : }
852 :
853 : static void Log(const paramType& aParam, std::wstring* aLog)
854 : {
855 : aLog->append(StringPrintf(L"Endpoint"));
856 : }
857 : };
858 :
859 : } // namespace IPC
860 :
861 :
862 : #endif // mozilla_ipc_ProtocolUtils_h
|