serialserver/c32serialserver/SCOMM/CS_STD.H
changeset 0 dfb7c4ff071f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/serialserver/c32serialserver/SCOMM/CS_STD.H	Thu Dec 17 09:22:25 2009 +0200
@@ -0,0 +1,480 @@
+// Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+
+
+// Defines global internals for C32. 
+
+#ifndef CS_STD_H
+#define CS_STD_H
+
+/** @file
+ *
+ * @internalComponent
+ */
+
+#include <cs_port.h>
+#include "COMMIPC.H"
+#include <cfmsgs.h>
+#include <cfshared.h>
+#include <cfutil.h>
+#include "cs_thread.h"	// CC32Workerthread, CCommChannelHandler
+#include <e32cmn.h>				// RFastLock
+
+
+
+#ifndef __WINS__
+#define VERBOSE
+#endif	// __WINS__
+
+// time for player to close all owned sessions. Is sent in msg from dealer to player so that player can 
+// determine if it should still process the message. If player doesn't see this msg until after timer 
+// expires, player does not process msg. Also, dealer won't process response and close session if this 
+// timer has expired before dealer sees response (I don't quite see why this needs to be the case? 
+// Surely this is only a problem if session close delay has also expired? ). 8 secs is derived from 
+// being "a long time" for this sort of operation.
+const TUint32 KC32SessionCloseDelay = 16*1000*1000;
+// time for session to clean up all subsessions from workers wrt this session. The client is normally 
+// held inside their Close() call until c32 completes the close. Must be longer than player close deadline 
+// since at expiration client is released and after that, csys accessing client memory will be dangerous. 
+// Is 8 secs longer than session close player deadline since this is how long it takes some test CSYs to 
+// perform their closure.
+const TUint32 KC32SessionClosePlayerDeadline = 8*1000*1000;
+
+// Short delay on asynchronous callback to allow for any others to run
+// In practice, the yield itself is normally enough
+const TInt KCommServerShutdownLatencyMicroSeconds = 100 * 1000;	
+
+_LIT(KCommServer, "!CommServer");
+_LIT(KCSYExtension, ".CSY" );
+_LIT8(KCSYExtension8, ".CSY" );
+_LIT8(KRoleLabel, "Role");
+_LIT8(KDealerRole, "Dealer");
+_LIT8(KPlayerRole, "Player");
+//_LIT8(KDealerPlayerRole, "DealerPlayer");  // maybe one day
+_LIT8(KWorkerIdLabel, "WorkerId");
+_LIT8(KCSYListLabel, "CSYList");
+
+
+void PanicClient(TInt aPanic, const RMessagePtr2& aMessage);
+void SafeComplete(const RMessagePtr2& aMessage, TInt aCompletionCode);
+TInt AddCSYExtension(TFileName& aFilename, const RMessage2& aMessage);
+
+
+
+/**
+ * External representation of the state of a CPort object.
+ */
+struct TCommDebugInfo 
+	{
+	TInternalCommAccess iMode;  //< The current main access mode of the port
+	TInt iAccessCount;          //< Number of open clients
+	TCommRole iRole;            //< DCE or DTE
+	TInt iOutstandingCommands;  //< Number of outstanding Opens, Closes, Waits etc.
+						        //< (excludes SetAccess requests)
+	};
+
+class CCommSubSession;
+class CC32Player;
+class CPort;
+
+class RNullableMessage : public RMessage2
+	{
+public:
+	void NullHandle() const
+		{
+		// Although this casting away of const looks awful it's in keeping with the ability to Complete() const
+		// messages - perhaps iHandle should have been mutable?
+		const_cast<RNullableMessage&>(*this).iHandle = 0;
+		}
+	};
+
+
+NONSHARABLE_CLASS(CCommSubSession) : public CBase
+/**
+@class
+CCommSubSession
+@internalComponent
+*/
+	{
+	friend class CCommSession;
+	friend class CC32Player;
+public:
+	// Reference counting methods formerly supplied by CObject.
+	inline void Open();
+	inline void Close();
+	inline TInt AccessCount() const;
+
+#ifdef _DEBUG
+	virtual ~CCommSubSession();
+#endif
+
+	inline CCommSession* Session() const;
+	inline CC32Player& Player() const;
+
+	/** 
+		Type identifier for the derived sub-session objects. Used e.g. in containers to identify
+		what is stored.
+
+		@see CCommSubSession::Type()
+	*/
+	enum TSubSessionType 
+		{ 
+		ENull, 
+		EAny, 
+		ECPort 
+		};
+
+	TSubSessionType Type() const
+		{
+		return CCommSubSession::ECPort;
+		}
+
+
+	static CCommSubSession* NewL(CCommSession* aSession, CPort* aPort, CC32Player* aPlayer);
+
+private:
+	CCommSubSession(CCommSession* aSession, CPort* aPort, CC32Player* aPlayer);
+	void RemoveAndDestroy();
+private:
+	CC32Player* iPlayer;	//< The Player responsible for this sub-session instance.
+	TInt iAccessCount;		//< Reference counting on the sub-session. If it goes to 0 the sub-session will be destroyed.
+	CPort* iPort;
+	CCommSession* iSession;
+	};
+
+//
+// CC32SubSessionIx - Subsession index
+//
+
+/**
+@class
+CC32SubSessionIx
+This sub-session container will maintain its own array of TEntry cells in memory as arrays provide for
+quick access in some situations. There will be two types of cells in the array; cells carrying pointers
+to sub-sessions and a virtual list of free cells.
+This layout means that with a handle, the entry holding the sub-session can be looked up in the container
+directly and if needing to insert a new entry the first free cell is indicated by iFreeListHead.
+The array will grow with EIndexGranularity each time it runs out of free entries. However, it maintains a high
+watermark and will never shrink.
+The handles are defined by TSubSessionHandle, which in the current architectures is a 32 bit word, constructed
+as needed. It is simple to deduct from the context so there is no need to store it.
+
+0        8        16              31
+|--------|--------|----------------|
+   Type     Magic       Index
+
+The three components comprising the handle are:
+    - Type	- 8 bit value. One of the members of CCommSubSession::TSubSessionType.
+    - Magic	- 8 bit value. Ensures that handles are not re-used immediately. Each time an entry is re-cycled this value increments, rolling around when reaching max.
+    - Index	- 16 bit value. The position in the array.
+@see CCommSubSession::TSubSessionType
+*/
+NONSHARABLE_CLASS(CC32SubSessionIx) : public CBase
+	{
+public:
+	typedef TInt TSubSessionHandle;
+	enum { KTypeBits = 8, KMagicBits = 8, KIndexBits = 16 };
+	enum { KIndexLimit = 1 << KIndexBits };
+	enum { KMagicMask = (1 << KMagicBits) - 1 };
+public:
+	~CC32SubSessionIx();
+
+	void InitialiseL();
+	inline void Lock() const;
+	inline void Unlock() const;
+	
+	CCommSubSession* At(TInt aHandle, CCommSubSession::TSubSessionType aType) const;
+	TInt Find(CCommSubSession* aSubSession, TSubSessionHandle& aHandle) const;
+
+	TInt Add(CCommSubSession* aSubSession, TSubSessionHandle& aHandle);
+	CCommSubSession* Remove(TSubSessionHandle aHandle);
+
+	NONSHARABLE_CLASS(TIter)
+		{
+	public:
+		TIter(CC32SubSessionIx& aContainer);
+		void SetToFirst();
+		CCommSubSession* operator++(TInt);
+		CCommSubSession* Next(TSubSessionHandle& aHandle);
+	private:
+		TInt iPos;
+		CC32SubSessionIx& iContainer;
+		};
+
+	friend class TIter;
+private:
+	enum { EIndexGranularity = 8 };
+
+	/** @class
+	CC32SubSessionIx::TEntry
+	One entry in the container. If iType is CCommSubSession::ENull, then it is a member of the free-list 
+	and iNextFree is the index of the next free TEntry instance otherwise it is an iObject* and points 
+	to a sub-session instance.
+	iType can be one those defined in CCommSubSession::TSubSessionType.
+	@see CCommSubSession::TSubSessionType
+	*/
+	class TEntry
+		{
+	public:
+		union
+			{
+			CCommSubSession* iObject;
+			TInt iNextFree;
+			};
+		TUint8 iType;
+		TUint16 iMagic;
+		};
+private:
+	inline TSubSessionHandle MakeHandle(TInt aIndex, TInt aMagic, TInt aType) const
+		{
+		return (((aIndex << KMagicBits) | aMagic) << KTypeBits) | aType;
+		}
+	inline TInt IndexFromHandle(TInt aHandle) const
+		{
+		return aHandle >> (KTypeBits + KMagicBits);
+		}
+	TEntry* At(TSubSessionHandle aHandle) const;
+	TInt ExpandArray();
+
+private:
+	class RWorkerLock : public RFastLock
+		{
+	public:
+		// overriden functions
+		inline void Wait();
+
+		inline void Signal();
+		// end overriden functions
+		
+		inline void AssertLockHeld() const;
+		
+		
+#ifdef _DEBUG
+	private:
+		// RFastLock does not nest, ie if the current holder attempts to re-acquire they deadlock
+		// We check for this in debug builds only as the cost of doing so likely negates the benefits
+		// of using the class over & above semaphores
+		TThreadId iHolder;
+#endif
+		};
+
+private:
+	TEntry* iIx;
+	TInt iSize;
+	TInt iActiveCount;			//< Number of active sub-sessions stored in this container.
+	TInt iFreeListHead;			//< Pointer to the first item/cell in the virtual free list.
+	mutable RWorkerLock iLock;
+	};
+
+
+
+
+/**
+ * Main Comms Server object.  Constructed on process initialisation; never deleted.
+ */
+class CC32WorkerThread;
+class CC32ThreadManager;
+class CC32Server : public CPolicyServer
+	{
+public:
+	enum {EPriority=1000}; //< priority of this Active Object
+public:
+	// from CServer
+	virtual CSession2* NewSessionL(const TVersion& aVersion, const RMessage2& aMessage) const;
+	~CC32Server();
+public:
+	inline CC32WorkerThread& WorkerThread() const;
+	inline CommsFW::TWorkerId WorkerId() const;
+	
+protected://virtuals from CPolicyServer
+	CPolicyServer::TCustomResult CustomSecurityCheckL(const RMessage2& aMsg, TInt& aAction, TSecurityInfo& aMissing);
+protected:
+	CC32Server(CC32WorkerThread* aOwnerThread, TInt aPriority);
+	void ConstructL(CC32ThreadManager* aThreadManager);
+
+private:
+	CC32WorkerThread* iOwnerThread;
+	CC32ThreadManager* iThreadManager;
+	TInt iThreadHandles;	
+
+private:
+	static const TUint iRangeCount;
+	static const TInt iRanges[];
+	static const TUint8 iElementsIndex[];
+	static const CPolicyServer::TPolicyElement iElements[];
+	static const CPolicyServer::TPolicy iPolicy;
+	};
+
+
+class CC32ThreadManager;
+/**
+ * A client session.
+ * Corresponds to an RCommSession object in the client.
+ */
+class CCommSession : public CSession2
+	{
+	friend class CCommSubSession;
+    friend class CC32Dealer;
+	typedef CSession2 inherited;
+
+public:
+	static CCommSession* NewL(CC32ThreadManager* aThreadManager);
+	virtual void ServiceL(const RMessage2 &aMessage);
+	virtual void ServiceError(const RMessage2& aMessage, TInt aError);
+	virtual ~CCommSession();
+	CCommSession(CC32ThreadManager* aThreadManager);
+	void ConstructL();
+	void LoadCommModuleL(const RMessage2& aMessage, CommsFW::TWorkerId aWorker, TBool defaulted, const TDesC& aFilename);
+	void CloseCommModuleL(const RMessage2& aMessage);
+	void NewPortL(const RMessage2& aMessage);
+
+	void NumPorts(const RMessage2& aMessage);
+	void PortInfo(const RMessage2& aMessage,TInt aPortNum);
+	void PortInfoL(const RMessage2& aMessage,const TPortName& aPortName);
+	TInt Write(TInt aPos, const RMessagePtr2& aMessage, const TDesC8& aDes, TInt aOffset=0);
+	TInt Read(TInt aPos, const RMessagePtr2& aMessage, TDes8& aDes, TInt aOffset=0);
+	TInt Write(TInt aPos, const RMessagePtr2& aMessage, const TDesC16& aDes, TInt aOffset=0);
+	TInt Read(TInt aPos, const RMessagePtr2& aMessage, TDes16& aDes,TInt aOffset=0);
+	TInt ExtractPortNameAndNumber(const RMessagePtr2& aMessage, TDes& aPortName, TUint& aPortNumber, TInt& aLength);
+	
+public:
+	inline const CC32Dealer& Dealer() const;
+	CC32WorkerThread& C32WorkerThread() const;
+	CommsFW::TWorkerId WorkerId() const;
+	inline CC32SubSessionIx& SubSessions();
+
+	// RCommServ related APIs
+	TInt AddCSYToSessionL(const TDesC& aCSYFileName, TBool& aIsDuplicate);		//< LoadCommModule
+	TInt RemoveCSYFromSession(const TDesC& aCSYFileName, TBool& aIsLast);	//< used by UnLoadCommModule
+	
+	// Apply a callback function to subsessions of the session, either matching the worker id, or all
+	// if aPeerId == ENullWorkerId
+	typedef void (*TSubSessionProcessor)(CCommSession* aSession, CCommSubSession* aSubSession, TInt aSubSessionHandle, TAny* aArg);
+	void ProcessSubSessions(CommsFW::TWorkerId aPeerId, TSubSessionProcessor aSubSessionProcessor, TAny* aPtr);
+
+	// Callbacks used with ProcessSubSessions()
+	static void ForgetSubSession(CCommSession* aSession, CCommSubSession* aSubSession, TInt aSubSessionHandle, TAny* aArg);
+	static void CountSubSessions(CCommSession* aSession, CCommSubSession* aSubSession, TInt aSubSessionHandle, TAny* aArg);
+
+	// Called by worker when it has received a SessionCloseRespMsg
+	void SessionCloseResp(CommsFW::TWorkerId aPlayerId);
+
+	typedef RPointerArray<HBufC> RCSYFileNameContainer; //< unlike ThreadManager, CSY names stored in 16-bit since in all cases they come in 16-bit
+														//(ie, we never have to compare with ThreadManager CSY list, which is 8-bit since based from 8-bit ini file)
+	
+	void CompleteDisconnect();
+
+	TBool IsPlayerInDisconnectList(CommsFW::TWorkerId aPlayerId) const;
+	TBool IsDisconnectListEmpty() const;
+	TInt DisconnectPlayers();
+
+protected:
+	void Disconnect();
+	// Override of default behaviour for session disconnection
+	virtual void Disconnect(const RMessage2& aMessage);
+
+	void ForwardMessageL(const RMessage2& aMessage, CCommSubSession* aSS, CommsFW::TWorkerId aWorker);
+	void ForwardMessageL(const RMessage2& aMessage, CCommSubSession& aSubSess);
+	void SafeComplete(const RMessagePtr2& aMessage, TInt aCompletionCode);
+	void DontCompleteCurrentRequest();
+
+private:
+	CC32ThreadManager* iThreadManager;	//< ThreadManager for lookup, located in dealer
+	CCommSubSession* SubSessionFromHandle(TUint aHandle, CCommSubSession::TSubSessionType aType) const;
+	void CloseSubSessionL(const RMessage2& aMessage, CCommSubSession::TSubSessionType aType);
+
+	void AddPlayerToDisconnectList(CommsFW::TWorkerId aPlayerId);
+	void RemovePlayerFromDisconnectList(CommsFW::TWorkerId aPlayerId);
+	
+	/** 
+	@class
+	CCommSession::CC32SessionCloseTimer
+	This timer times out after double the deadline given to the Players to return a Session Close response.
+	*/
+    NONSHARABLE_CLASS(CC32SessionCloseTimer) : public CTimer
+    	{
+	public:
+	    static CC32SessionCloseTimer* NewL(CCommSession* aSession);
+		void Start();
+	protected:
+	    void RunL();
+	private:
+	    CC32SessionCloseTimer(CCommSession* aSession);
+	    CCommSession* iSession;
+    	};
+
+    /** Timer starting when SessionClosed message is sent to players.
+	If not all the expected responses come back within the deadline set in the Session
+	Close message, the CC32SessionCloseTimer will fire and the session will be deleted by 
+	the Dealer. This is usually due to a Player somehow being unreliable and shouldn't 
+	normally happen. The purpose of the timeout is to avoid blocking clients.
+	*/
+    CC32SessionCloseTimer* iSessionCloseTimer;
+	TBool iComplete;				//< check if the current message can be completed
+	CC32SubSessionIx iSubSessions;	//< Container of subsessions belonging to this session. 
+									//< They can potentially belong to different Players.
+	TUint32 iDisconnectPlayers;	    //< Set of Players to notify of session death	
+	RMessage2 iDisconnectMessage;	//< EDisConnect Message to complete session destruction
+	RCSYFileNameContainer iCsyCon;	//< CSYs loaded in this session, used to check on unload whether CSY was loaded. Duplicates allowed, order unimportant.
+	};
+
+
+/**
+ * Active Scheduler class with specialised error handling.
+ */
+class CCommScheduler : public CActiveScheduler
+	{
+public:
+	static CCommScheduler* New();
+    void Error(TInt anError) const;
+	};
+
+/**
+ * Owner object for all the CPort Objects.
+ * There is one instance of this, owned by the CCommSession object.
+ * It has no explicit destructor because the C32 thread will never finish unless panicked
+ */
+NONSHARABLE_CLASS (CPortManager) : public CBase
+	{
+public:
+	static CPortManager* NewL();
+	CSerial* LoadCommModuleL(const TDesC& aFileName);
+	CSerial* GetSerialL(const TDesC& aName);
+	CPort* GetPortL(const TDesC& aName, TUint aPort, CSerial *aSerial, TUint aMode, TUint aRole, CCommSession* aSession);
+	TInt PortInfo(const TPortName& aName, TSerialInfo& aSerial);
+	~CPortManager();
+
+private:
+	CObjectConIx* iContainer;
+	CObjectCon* iPorts;
+	CObjectCon* iProviders;
+
+private:
+	void ConstructL();
+
+	};
+
+#ifdef __MARM__
+const TInt KCommTimerGranularity = 31000;
+#else
+const TInt KCommTimerGranularity = 80000;
+#endif
+
+
+#include "cs_std.inl"
+
+#endif // CS_STD_H
+