michael@0: /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * vim: sw=4 ts=4 et : michael@0: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef mozilla_ipc_ProtocolUtils_h michael@0: #define mozilla_ipc_ProtocolUtils_h 1 michael@0: michael@0: #include "base/process.h" michael@0: #include "base/process_util.h" michael@0: #include "chrome/common/ipc_message_utils.h" michael@0: michael@0: #include "prenv.h" michael@0: michael@0: #include "IPCMessageStart.h" michael@0: #include "mozilla/Attributes.h" michael@0: #include "mozilla/ipc/FileDescriptor.h" michael@0: #include "mozilla/ipc/Shmem.h" michael@0: #include "mozilla/ipc/Transport.h" michael@0: #include "mozilla/ipc/MessageLink.h" michael@0: #include "mozilla/LinkedList.h" michael@0: michael@0: #if defined(ANDROID) && defined(DEBUG) michael@0: #include michael@0: #endif michael@0: michael@0: // WARNING: this takes into account the private, special-message-type michael@0: // enum in ipc_channel.h. They need to be kept in sync. michael@0: namespace { michael@0: // XXX the max message ID is actually kuint32max now ... when this michael@0: // changed, the assumptions of the special message IDs changed in that michael@0: // they're not carving out messages from likely-unallocated space, but michael@0: // rather carving out messages from the end of space allocated to michael@0: // protocol 0. Oops! We can get away with this until protocol 0 michael@0: // starts approaching its 65,536th message. michael@0: enum { michael@0: CHANNEL_OPENED_MESSAGE_TYPE = kuint16max - 5, michael@0: SHMEM_DESTROYED_MESSAGE_TYPE = kuint16max - 4, michael@0: SHMEM_CREATED_MESSAGE_TYPE = kuint16max - 3, michael@0: GOODBYE_MESSAGE_TYPE = kuint16max - 2 michael@0: michael@0: // kuint16max - 1 is used by ipc_channel.h. michael@0: }; michael@0: } michael@0: michael@0: namespace mozilla { michael@0: namespace dom { michael@0: class ContentParent; michael@0: } michael@0: michael@0: namespace net { michael@0: class NeckoParent; michael@0: } michael@0: michael@0: namespace ipc { michael@0: michael@0: #ifdef XP_WIN michael@0: const base::ProcessHandle kInvalidProcessHandle = INVALID_HANDLE_VALUE; michael@0: #else michael@0: const base::ProcessHandle kInvalidProcessHandle = -1; michael@0: #endif michael@0: michael@0: class ProtocolFdMapping; michael@0: class ProtocolCloneContext; michael@0: michael@0: // Used to pass references to protocol actors across the wire. michael@0: // Actors created on the parent-side have a positive ID, and actors michael@0: // allocated on the child side have a negative ID. michael@0: struct ActorHandle michael@0: { michael@0: int mId; michael@0: }; michael@0: michael@0: // Used internally to represent a "trigger" that might cause a state michael@0: // transition. Triggers are normalized across parent+child to Send michael@0: // and Recv (instead of child-in, child-out, parent-in, parent-out) so michael@0: // that they can share the same state machine implementation. To michael@0: // further normalize, |Send| is used for 'call', |Recv| for 'answer'. michael@0: struct Trigger michael@0: { michael@0: enum Action { Send, Recv }; michael@0: michael@0: Trigger(Action action, int32_t msg) : michael@0: mAction(action), michael@0: mMsg(msg) michael@0: {} michael@0: michael@0: Action mAction; michael@0: int32_t mMsg; michael@0: }; michael@0: michael@0: class ProtocolCloneContext michael@0: { michael@0: typedef mozilla::dom::ContentParent ContentParent; michael@0: typedef mozilla::net::NeckoParent NeckoParent; michael@0: michael@0: ContentParent* mContentParent; michael@0: NeckoParent* mNeckoParent; michael@0: michael@0: public: michael@0: ProtocolCloneContext() michael@0: : mContentParent(nullptr) michael@0: , mNeckoParent(nullptr) michael@0: {} michael@0: michael@0: void SetContentParent(ContentParent* aContentParent) michael@0: { michael@0: mContentParent = aContentParent; michael@0: } michael@0: michael@0: ContentParent* GetContentParent() { return mContentParent; } michael@0: michael@0: void SetNeckoParent(NeckoParent* aNeckoParent) michael@0: { michael@0: mNeckoParent = aNeckoParent; michael@0: } michael@0: michael@0: NeckoParent* GetNeckoParent() { return mNeckoParent; } michael@0: }; michael@0: michael@0: template michael@0: class /*NS_INTERFACE_CLASS*/ IProtocolManager michael@0: { michael@0: public: michael@0: enum ActorDestroyReason { michael@0: FailedConstructor, michael@0: Deletion, michael@0: AncestorDeletion, michael@0: NormalShutdown, michael@0: AbnormalShutdown michael@0: }; michael@0: michael@0: typedef base::ProcessHandle ProcessHandle; michael@0: michael@0: virtual int32_t Register(ListenerT*) = 0; michael@0: virtual int32_t RegisterID(ListenerT*, int32_t) = 0; michael@0: virtual ListenerT* Lookup(int32_t) = 0; michael@0: virtual void Unregister(int32_t) = 0; michael@0: virtual void RemoveManagee(int32_t, ListenerT*) = 0; michael@0: michael@0: virtual Shmem::SharedMemory* CreateSharedMemory( michael@0: size_t, SharedMemory::SharedMemoryType, bool, int32_t*) = 0; michael@0: virtual bool AdoptSharedMemory(Shmem::SharedMemory*, int32_t*) = 0; michael@0: virtual Shmem::SharedMemory* LookupSharedMemory(int32_t) = 0; michael@0: virtual bool IsTrackingSharedMemory(Shmem::SharedMemory*) = 0; michael@0: virtual bool DestroySharedMemory(Shmem&) = 0; michael@0: michael@0: // XXX odd ducks, acknowledged michael@0: virtual ProcessHandle OtherProcess() const = 0; michael@0: virtual MessageChannel* GetIPCChannel() = 0; michael@0: michael@0: // The implementation of function is generated by code generator. michael@0: virtual void CloneManagees(ListenerT* aSource, michael@0: ProtocolCloneContext* aCtx) = 0; michael@0: }; michael@0: michael@0: typedef IPCMessageStart ProtocolId; michael@0: michael@0: /** michael@0: * All RPC protocols should implement this interface. michael@0: */ michael@0: class IProtocol : protected MessageListener michael@0: { michael@0: public: michael@0: /** michael@0: * This function is used to clone this protocol actor. michael@0: * michael@0: * see IProtocol::CloneProtocol() michael@0: */ michael@0: virtual IProtocol* michael@0: CloneProtocol(MessageChannel* aChannel, michael@0: ProtocolCloneContext* aCtx) = 0; michael@0: }; michael@0: michael@0: /** michael@0: * All top-level protocols should inherit this class. michael@0: * michael@0: * IToplevelProtocol tracks all top-level protocol actors created from michael@0: * this protocol actor. michael@0: */ michael@0: class IToplevelProtocol : public LinkedListElement michael@0: { michael@0: protected: michael@0: IToplevelProtocol(ProtocolId aProtoId) michael@0: : mProtocolId(aProtoId) michael@0: , mTrans(nullptr) michael@0: { michael@0: } michael@0: michael@0: ~IToplevelProtocol(); michael@0: michael@0: /** michael@0: * Add an actor to the list of actors that have been opened by this michael@0: * protocol. michael@0: */ michael@0: void AddOpenedActor(IToplevelProtocol* aActor); michael@0: michael@0: public: michael@0: void SetTransport(Transport* aTrans) michael@0: { michael@0: mTrans = aTrans; michael@0: } michael@0: michael@0: Transport* GetTransport() const { return mTrans; } michael@0: michael@0: ProtocolId GetProtocolId() const { return mProtocolId; } michael@0: michael@0: /** michael@0: * Return first of actors of top level protocols opened by this one. michael@0: */ michael@0: IToplevelProtocol* GetFirstOpenedActors() michael@0: { michael@0: return mOpenActors.getFirst(); michael@0: } michael@0: const IToplevelProtocol* GetFirstOpenedActors() const michael@0: { michael@0: return mOpenActors.getFirst(); michael@0: } michael@0: michael@0: virtual IToplevelProtocol* michael@0: CloneToplevel(const InfallibleTArray& aFds, michael@0: base::ProcessHandle aPeerProcess, michael@0: ProtocolCloneContext* aCtx); michael@0: michael@0: void CloneOpenedToplevels(IToplevelProtocol* aTemplate, michael@0: const InfallibleTArray& aFds, michael@0: base::ProcessHandle aPeerProcess, michael@0: ProtocolCloneContext* aCtx); michael@0: michael@0: private: michael@0: LinkedList mOpenActors; // All protocol actors opened by this. michael@0: michael@0: ProtocolId mProtocolId; michael@0: Transport* mTrans; michael@0: }; michael@0: michael@0: michael@0: inline bool michael@0: LoggingEnabled() michael@0: { michael@0: #if defined(DEBUG) michael@0: return !!PR_GetEnv("MOZ_IPC_MESSAGE_LOG"); michael@0: #else michael@0: return false; michael@0: #endif michael@0: } michael@0: michael@0: MOZ_NEVER_INLINE void michael@0: ProtocolErrorBreakpoint(const char* aMsg); michael@0: michael@0: MOZ_NEVER_INLINE void michael@0: FatalError(const char* aProtocolName, const char* aMsg, michael@0: base::ProcessHandle aHandle, bool aIsParent); michael@0: michael@0: struct PrivateIPDLInterface {}; michael@0: michael@0: bool michael@0: Bridge(const PrivateIPDLInterface&, michael@0: MessageChannel*, base::ProcessHandle, MessageChannel*, base::ProcessHandle, michael@0: ProtocolId, ProtocolId); michael@0: michael@0: bool michael@0: Open(const PrivateIPDLInterface&, michael@0: MessageChannel*, base::ProcessHandle, Transport::Mode, michael@0: ProtocolId, ProtocolId); michael@0: michael@0: bool michael@0: UnpackChannelOpened(const PrivateIPDLInterface&, michael@0: const IPC::Message&, michael@0: TransportDescriptor*, base::ProcessId*, ProtocolId*); michael@0: michael@0: } // namespace ipc michael@0: } // namespace mozilla michael@0: michael@0: michael@0: namespace IPC { michael@0: michael@0: template <> michael@0: struct ParamTraits michael@0: { michael@0: typedef mozilla::ipc::ActorHandle paramType; michael@0: michael@0: static void Write(Message* aMsg, const paramType& aParam) michael@0: { michael@0: IPC::WriteParam(aMsg, aParam.mId); michael@0: } michael@0: michael@0: static bool Read(const Message* aMsg, void** aIter, paramType* aResult) michael@0: { michael@0: int id; michael@0: if (IPC::ReadParam(aMsg, aIter, &id)) { michael@0: aResult->mId = id; michael@0: return true; michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: static void Log(const paramType& aParam, std::wstring* aLog) michael@0: { michael@0: aLog->append(StringPrintf(L"(%d)", aParam.mId)); michael@0: } michael@0: }; michael@0: michael@0: } // namespace IPC michael@0: michael@0: michael@0: #endif // mozilla_ipc_ProtocolUtils_h