Wiley.Symbian.OS.Internals.Real.time.Kernel.Programming.Dec.2005.eBook-DDU (779891), страница 29
Текст из файла (страница 29)
It works in a similar way to themethod I described in the previous paragraph, except that the memoryallocation for the new session is performed in a separate thread andthe connect message is completed asynchronously, rather than aftera (potentially long) synchronous wait in DoConnect(). The separatethread will simply consist of a base call to DoConnect() as there is nopublic API to perform the actions of DoConnect() separately, such assetting the session’s ”cookie”.Your CServer2-derived server active object uses an instance of theprivate class RServer2 – which holds a handle to the equivalent kernelside server object, DServer – to receive messages from the kernel.The handle to the kernel-side kernel object, contained in the iServermember, remains open throughout the lifetime of the server object and isClose()d in its destructor.The server active object receives messages from the kernel by queuinga request on the RServer2.
This is done automatically for you inStart() after the kernel-side server object has been successfully created.A request is also automatically requeued after processing a messagein the server’s RunL(). The request to receive another message fromthe kernel is canceled in the server object’s DoCancel() and theserver active object Cancel()s itself in its destructor, as with any otheractive object.The kernel-side (DServer) object is created via a call to Start()on your CServer2-derived object and the level of session sharabilitythe server will support, as enumerated in CServer2::TServerType, isdetermined at this time. You specify the level of sharability a given sessionactually has when a client calls RSessionBase::CreateSession().The sharability of a new session is opaque to the server itself, which willonly know that a new session has been created.
Therefore it is the kernel’sresponsibility to police sharability – both when creating new sessions andalso when opening handles to existing ones.CSession2, from which you derive session objects used to manageper-session resources in your server, is shown below:CLIENT-SERVER ITC123class CSession2 : public CBase{friend class CServer2;public:IMPORT_C virtual ∼CSession2() =0;private:IMPORT_C virtual void CreateL(); // Default method, does nothingpublic:inline const CServer2* Server() const;IMPORT_C void ResourceCountMarkStart();IMPORT_C void ResourceCountMarkEnd(const RMessage2& aMessage);IMPORT_C virtual TInt CountResources();virtual void ServiceL(const RMessage2& aMessage) =0;IMPORT_C virtual void ServiceError(const RMessage2& aMessage,TInt aError);protected:IMPORT_C CSession2();IMPORT_C virtual void Disconnect(const RMessage2& aMessage);private:TInt iResourceCountMark;TDblQueLink iLink;const CServer2* iServer;};The heart of the session object is the ServiceL() method.
On receptionof a message, the server uses the cookie the kernel returns to it as a pointer toa session object and then passes the message to that session by calling ServiceL(). The session class will then perform appropriate actions to fulfillthe request contained in the message and at some future point the messagewill be completed to signal the completion of the request to the client.The virtual method Disconnect() is used to allow the sessionto implement asynchronous session deletion in a similar manner to thatdescribed for asynchronous session creation using CServer2::DoConnect().The server can access the kernel-side message objects using RMessagePtr2, which encapsulates both the handle to the message objectand descriptor APIs for accessing the client’s memory space using themessage.
A small number of APIs to allow manipulation of the clientthread are available to allow the server to enforce certain behavior of itsclient, for example, enforcing that the client passes certain parametersby panicking it if it presents a message containing invalid values. Finally,RMessagePtr2 also presents APIs that allow the security attributes ofthe client to be examined and checked against predetermined securitypolicies. The security of these APIs is ensured as the kernel verifies thatthe thread using them has a valid handle to a kernel message object.The client constructs a message for a particular session by specifyinga ‘‘function number’’ to identify the operation that is being requestedand optionally up to four message parameters.
These parameters may beeither plain integers, pointers or may be descriptors that the server will124INTER-THREAD COMMUNICATIONthen be able to use to access the client’s address space. Using templatedargument types and an overloaded function that maps argument typesto a bitfield, the class TIpcArgs (which is used to marshall messagearguments in IPCv2) generates a bit mask at compile time which describesthe types of its arguments.This bit mask is stored in the kernel-side message object. This allowsthe kernel to check whether operations requested by the server usingthe message are correct – for example, checking the source and targetdescriptors are either both 8-bit or both 16-bit descriptors.
It also allowsthe kernel to check that the requested operation is permitted by the client,for example by checking that when the server requests to write to a clientdescriptor, the client descriptor is TDes-derived (modifiable) rather thanTDesC-derived (constant).You should beware that though you can still pass pointers in IPCv2,there are no longer any APIs to directly access memory in another thread’saddress space using an arbitrary pointer and a handle to the thread asthis is inherently insecure.
The ability to pass a pointer between a clientand server is therefore only of any value when the client and server arewithin the same process. In this case, the use of a pointer is obviously notlimited to pointing to a descriptor, but may also be used to point to anarbitrary data structure containing information to be shared between theclient and server:class RMessagePtr2{public:inline RMessagePtr2();inline TBool IsNull();inline TInt Handle();#ifndef __KERNEL_MODE__inline TBool ClientDataCaging();IMPORT_C void Complete(TInt aReason);IMPORT_C void Complete(RHandleBase aHandle);IMPORT_C TInt GetDesLength(TInt aParam);IMPORT_C TInt GetDesLengthL(TInt aParam);IMPORT_C TInt GetDesMaxLength(TInt aParam);IMPORT_C TInt GetDesMaxLengthL(TInt aParam);IMPORT_C void ReadL(TInt aParam,TDes8& aDes,TInt aOffset=0);IMPORT_C void ReadL(TInt aParam,TDes16 &aDes,TInt aOffset=0);IMPORT_C void WriteL(TInt aParam,const TDesC8& aDes,TInt aOffset=0);IMPORT_C void WriteL(TInt aParam,const TDesC16& aDes,TInt aOffset=0);IMPORT_C TInt Read(TInt aParam,TDes8& aDes,TInt aOffset=0);IMPORT_C TInt Read(TInt aParam,TDes16 &aDes,TInt aOffset=0);IMPORT_C TInt Write(TInt aParam,const TDesC8& aDes,TInt aOffset=0);IMPORT_C TInt Write(TInt aParam,const TDesC16& aDes,TInt aOffset=0);IMPORT_C void Panic(const TDesC& aCategory,TInt aReason);IMPORT_C void Kill(TInt aReason);IMPORT_C void Terminate(TInt aReason);IMPORT_C TInt SetProcessPriority(TProcessPriority aPriority);CLIENT-SERVER ITC125inlinevoid SetProcessPriorityL(TProcessPriority aPriority);IMPORT_C TInt Client(RThread& aClient,TOwnerType aOwnerType=EOwnerProcess);inlinevoid ClientL(RThread& aClient,TOwnerType aOwnerType=EOwnerProcess);IMPORT_C TUint ClientProcessFlags();IMPORT_C TSecureId SecureId();IMPORT_C TVendorId VendorId();inline TBool HasCapability(TCapability aCapability,const char* aDiagnostic=0);inline void HasCapabilityL(TCapability aCapability,const char* aDiagnosticMessage=0);inline TBool HasCapability(TCapability aCapability1,TCapability aCapability2, const char* aDiagnostic=0);inline void HasCapabilityL(TCapability aCapability1,TCapability aCapability2, const char* aDiagnosticMessage=0);inline TUid Identity() const { return SecureId(); }#endifprotected:TInt iHandle;};inline TBool operator==(RMessagePtr2 aLeft,RMessagePtr2 aRight);inline TBool operator!=(RMessagePtr2 aLeft,RMessagePtr2 aRight);RMessage2 expands the API provided by RMessagePtr2 by bringinga copy of the message arguments and the cookie (CSession2 pointer)stored in the kernel over into user space, allowing access to both.
RMessage2 also contains a number of spare words that do not correspondto data stored in the kernel. One of these, iFlags, is used to providethe ‘‘Authorised()’’ APIs which are used by a utility server base class,CPolicyServer, which allows simple implementation of a server thatvalidates given security policies upon session creation and reception ofeach message. For full details of CPolicyServer and its use, refer to arecent Symbian OS SDK.class RMessage2 : public RMessagePtr2{friend class CServer2;public:enum TsessionMessages{EConnect=-1,EDisConnect=-2};public:inline RMessage2();#ifndef __KERNEL_MODE__IMPORT_C explicit RMessage2(const RMessagePtr2& aPtr);void SetAuthorised() const;void ClearAuthorised() const;TBool Authorised() const;#endif126INTER-THREAD COMMUNICATIONinline TInt Function() const;inline TInt Int0() const;inline TInt Int1() const;inline TInt Int2() const;inline TInt Int3() const;inline const TAny* Ptr0() const;inline const TAny* Ptr1() const;inline const TAny* Ptr2() const;inline const TAny* Ptr3() const;inline CSession2* Session() const;protected:TInt iFunction;TInt iArgs[KMaxMessageArguments];private:TInt iSpare1;protected:const TAny* iSessionPtr;private:mutable TInt iFlags; // Currently only used for *Authorised aboveTInt iSpare3;// Reserved for future usefriend class RMessage;};4.1.4 User-side architecture – clientThe client-side architecture is shown in Figure 4.2.clientserverCServer2CSession2RSubSessionBase(shared)RServer2RSessionBase(shared)Process-owned handle'cookie'==Address of CSession2Thread-ownedhandleuserkernelDSessionFigure 4.2DServerClient-side architectureThe remainder of the user-side support for client-server consists of twoclient base classes, one for sessions and another for sub-sessions.