lowlevellibsandfws/pluginfw/Framework/frame/EComServerSession.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Fri, 17 Sep 2010 08:38:54 +0300
changeset 63 a117ad66e027
parent 0 e4d67989cc36
permissions -rw-r--r--
Revision: 201037 Kit: 201037

// 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:
// Server session object implementation.
// 
//

#include "EComServerStart.h"
#include "EComMessageIds.h"
#include <ecom/ecomerrorcodes.h>
#include <ecom/implementationinformation.h>
#include "EComServerSession.h"
#include "EComSessionAux.h"
#include "EComServer.h"
#include "TestUtilities.h"	// For __FILE__LINE__
#include "EComPerformance.h"
#include "EComDebug.h"

//
// RMessage::Panic() completes the message. This is:
// (a) important for efficient cleanup within the kernel.
// (b) a problem if the message is completed a second time.
//
void PanicClient(const TClientRequest& aMessage, TInt aPanicCode)
	{
	aMessage.Panic(KEComServerPanicCategory, aPanicCode);
	}

//
//	class CEComServerSession
//
CEComServerSession::CEComServerSession()
	: CSession2()
	{
	// Do nothing
	}

//
// 2nd phase construct for sessions - called by the CServer framework
//
void CEComServerSession::CreateL()
	{
	Server().AddSession();
	}

CEComServerSession::~CEComServerSession()
	{
	CleanupInternalList();
	CompleteNotifications(KErrCancel);
	delete iMemoryStore;
	Server().DropSession();
	}

//
// Deliver the notification message to the client
//
void CEComServerSession::CompleteNotifications(TInt aCompletionCode)
	{
	const TInt count = iNotificationRequests.Count();
	for(TInt i = 0; i < count; ++i)
		{
		  iNotificationRequests[i].iMessage.Complete(aCompletionCode);

		}
	iNotificationRequests.Reset();
	}

//
// Handle a client request.
// Leaving is handled by CEComServer::RunError() which reports the error code
// to the client.
//
void CEComServerSession::ServiceL(const RMessage2& aMessage)
{
	const TClientRequest msg(aMessage);
	ServiceL(msg);
}

void CEComServerSession::ServiceL(const TClientRequest& aMessage)
	{
	TInt completionCode = KErrNone;
	TBool asyncRequest = EFalse;

	switch (aMessage.Function())
		{
	case ENotifyOnChange:
		{
RECORD_CLIENT_REQUEST_START_TIMER_RESULT(EEComNotifyOnChangeRequestType, Server().GetCurrentStartupState());
		SEComNotification notif;
		notif.iMessage=aMessage;
		// the TRequestStatus as a TInt is stored for later comparisons
		notif.iRequestStatusHandle=aMessage.Int0();
		//Check that this TRequestStatus is not already being used.
		const TInt count = iNotificationRequests.Count();
		for(TInt i = 0; i < count; ++i)
		{
			if(iNotificationRequests[i].iRequestStatusHandle == notif.iRequestStatusHandle)
				User::Leave(KErrArgument);

		}
		User::LeaveIfError(iNotificationRequests.Append(notif));
		asyncRequest = ETrue;
RECORD_CLIENT_REQUEST_END_TIMER_RESULT;
		break;
		}

	case ECancelNotifyOnChange:
			{
RECORD_CLIENT_REQUEST_START_TIMER_RESULT(EEComCancelNotifyOnChangeRequestType, Server().GetCurrentStartupState());
			TInt statusHandle = aMessage.Int0();

			const TInt count = iNotificationRequests.Count();
			for(TInt i = 0; i < count; ++i)
				{
				if(iNotificationRequests[i].iRequestStatusHandle == statusHandle)
					{
						iNotificationRequests[i].iMessage.Complete(KErrCancel);
						iNotificationRequests.Remove(i);
						break;  // Terminate the loop
					}
				}
			}
RECORD_CLIENT_REQUEST_END_TIMER_RESULT;
		break;

	case EListImplementations:
	case EListResolvedImplementations:
	case EListCustomResolvedImplementations:
		if(Server().RegistryIndexValid())
			{
RECORD_CLIENT_REQUEST_START_TIMER_RESULT(EEComListRequestType, Server().GetCurrentStartupState());
			DoListImplementationsL(aMessage);
RECORD_CLIENT_REQUEST_END_TIMER_RESULT;
			}
		else
			{
			if(ReceivePending())
				User::Leave(KEComErrListInvalidAwaitNotification);
			else
				User::Leave(KEComErrListCurrentlyUnavailable);
			}
		break;

	case ECollectImplementationsList:
RECORD_CLIENT_REQUEST_START_TIMER_RESULT(EEComCollectImplementationsRequestType, Server().GetCurrentStartupState());
		if(!DoCollectListL(aMessage))
			completionCode = KErrNotReady;
RECORD_CLIENT_REQUEST_END_TIMER_RESULT;
		break;

	case EGetImplementationCreationMethod:
	case EGetResolvedCreationMethod:
	case EGetCustomResolvedCreationMethod:
RECORD_CLIENT_REQUEST_START_TIMER_RESULT(EEComCreateRequestType, Server().GetCurrentStartupState());
		DoGetResolvedImplementationL(aMessage);
RECORD_CLIENT_REQUEST_END_TIMER_RESULT;
		break;

	case EListExtendedInterfaces:
RECORD_CLIENT_REQUEST_START_TIMER_RESULT(EEComListExtendedInterfacesRequestType, Server().GetCurrentStartupState());
		DoListExtendedInterfacesL(aMessage);
RECORD_CLIENT_REQUEST_END_TIMER_RESULT;
		break;

	case EEnableImplementation:
	case EDisableImplementation:
		// Ommissions for 6.2
		completionCode = KErrNotSupported;
		break;
#if defined(__ECOM_SERVER_TESTABILITY__) || defined(__ECOM_SERVER_PERFORMANCE__)
	case ESetGetParameters:
		DoSetGetParametersL(aMessage);
		break;
#endif
	//EDestroyedImplementation obsolete due to implementation creation
	//relocation to client side from server
	case EDestroyedImplementation:
	default:
		// Something badly wrong if we get here.
		PanicClient(aMessage,KEComErrUnknownService);
		// RMessage::Panic() has completed the message
		// so treat this as an asynch request.
		asyncRequest = ETrue;
		}
	if (!asyncRequest)
		aMessage.Complete(completionCode);
	}



	
TInt const KDefaultStoreSize = 256;	// Enough space for approx 1 implementation : will grow to fit if required

/**
UnPack the match string and extended interface from the client supplied parameters.
@param			aMessage 
@param			aExtendedInterfaces Return value consisting of an array containing the extended interfaces.
@param			aMatchStr Return value consisting of the matching string.
*/
void CEComServerSession::UnpackMatchStrAndExtendedInterfacesFromClientL(const TClientRequest& aMessage,
													RExtendedInterfacesArray& aExtendedInterfaces,
													RBuf8& aMatchStr)
	{
	
	//now get the matchString and extendedInterfaces
	TInt sizeOfMatchStrExtInfBuf = aMessage.GetDesLength(KIPCParameterMatchStrExtInf);
	User::LeaveIfError(sizeOfMatchStrExtInfBuf);
	RBuf8 matchStrExtInfBuf;
	matchStrExtInfBuf.CreateMaxL(sizeOfMatchStrExtInfBuf);
	matchStrExtInfBuf.CleanupClosePushL();
	
	aMessage.ReadL(KIPCParameterMatchStrExtInf,matchStrExtInfBuf);
	RDesReadStream readStream;
	CleanupClosePushL(readStream);
	readStream.Open(matchStrExtInfBuf);
	TInt lenOfMatchStr = readStream.ReadInt32L();
	aMatchStr.CreateMaxL(lenOfMatchStr);
	aMatchStr.CleanupClosePushL();
	if (lenOfMatchStr>0)
		{
		readStream.ReadL(aMatchStr,lenOfMatchStr);		
		}
	TInt numOfExtendedInterfaces = readStream.ReadInt32L();
	CleanupClosePushL(aExtendedInterfaces);
	for(TInt i = 0; i < numOfExtendedInterfaces; i++)
		{
		aExtendedInterfaces.AppendL(TUid::Uid(readStream.ReadInt32L()));
		}
	
	CleanupStack::Pop(&aExtendedInterfaces);
	CleanupStack::Pop(&aMatchStr);
	CleanupStack::PopAndDestroy(&readStream);
	CleanupStack::PopAndDestroy(&matchStrExtInfBuf); 
	}


// Note that this method for returning the arbitrary sized data set 
// will not work IF the session is shared so...
// DO NOT SHARE SERVER SIDE SESSIONS BETWEEN CLIENTS
void CEComServerSession::DoListImplementationsL(const TClientRequest& aMessage)
	{
	// Unpack the client supplied parameters
	// Firstly get the uids
	TUidType uids;
	TPckg<TUidType> uidsPkg(uids);	
	aMessage.ReadL(KIPCParameterUids, uidsPkg);
	
	if(uids[KInterfaceUidIndex] == KNullUid)
		{
		User::Leave(KEComErrMissingParameter);
		}

	//now get the TListImplParam parameters
  	TListImplParam listParam;
  	TPckg<TListImplParam> listParamPkg(listParam);
  	aMessage.ReadL(2,listParamPkg);
	
	// Now rebuild the TEComResolverParams
	TEComResolverParams resolverParameters;
	resolverParameters.SetGenericMatch(listParam.iMatchType);
	
	//now get the matchString and extendedInterfaces
	RBuf8 matchStr;
	RExtendedInterfacesArray extendedInterfaces;
	UnpackMatchStrAndExtendedInterfacesFromClientL(aMessage,extendedInterfaces,matchStr);
	matchStr.CleanupClosePushL();
	CleanupClosePushL(extendedInterfaces);
	
	if(matchStr.Length()>0)
		{	
		resolverParameters.SetDataType(matchStr);
		}
	// Else the client's resolver params are default constructed i.e. invalid
	// data type descriptor or its length is zero, so use empty RBuf8 above.
	
		
	// Pass to the server
	iListContext = aMessage.Function();
	switch(iListContext)
		{
		case EListImplementations:
			iList = Server().ListImplementationsL( uids[KInterfaceUidIndex], extendedInterfaces, aMessage );
			break;
		case EListResolvedImplementations:
			if(matchStr.Length() == 0)
				{
				User::Leave(KEComErrMissingParameter);
				}
			iList = Server().ListImplementationsL( uids[KInterfaceUidIndex], resolverParameters, extendedInterfaces, aMessage);
			break;
		case EListCustomResolvedImplementations:
			if(uids[KResolverUidIndex] == KNullUid)
				{
				User::Leave(KEComErrMissingParameter);
				}
			iList = Server().ListImplementationsL( uids[KInterfaceUidIndex], resolverParameters, uids[KResolverUidIndex], extendedInterfaces, aMessage);
			break;
		default:
			break;
		}
	//Now cleanup the extended interface
	CleanupStack::PopAndDestroy(&extendedInterfaces);
	CleanupStack::PopAndDestroy(&matchStr);

	TInt bufferSizeRequired=0;
	// Package the array for return
	if(iList)
		{
		if(iList->Count()>0)
			{
			// Allocate a new store and replace the old one first
			CBufFlat* memoryStore = CBufFlat::NewL(KDefaultStoreSize);
			delete iMemoryStore;
			iMemoryStore = memoryStore;

			// Note : There is no need to push
			// the write stream onto the cleanup stack
			// because it has no internal resources.
			RBufWriteStream writeStream;
			writeStream.Open(*iMemoryStore);

			// Build the store data then calculate the end size;
			const TInt entryCount = iList->Count();		
			writeStream.WriteInt32L(entryCount);
			
			for(TInt i = 0; i < entryCount; ++i)
				(*iList)[i]->ExternalizeL(ETrue,writeStream);
	
			writeStream.CommitL();

			// Set to actual size
			bufferSizeRequired=iMemoryStore->Size();
			__ECOM_TRACE1("ECOM ListImplementations request buffer size required=%d",bufferSizeRequired);
			}
			CleanupInternalList();	
		}
	
	//if nothing is returned we should still indicate this to the client side
	if (bufferSizeRequired==0)
		{
		//write back the bufferSize
		listParam.iBufferSize=0;
  		aMessage.WriteL(2,listParamPkg);
		return;
		}
		
	//if the preallocated size is big enough to hold our entry
	//copy it to the client
	if (listParam.iBufferSize >= bufferSizeRequired)
		{
		if (iMemoryStore)
			{
			//write back the bufferSize
			listParam.iBufferSize=bufferSizeRequired;
  			aMessage.WriteL(2,listParamPkg);
			TPtr8 data=iMemoryStore->Ptr(0);
			aMessage.WriteL(3,data);
			delete iMemoryStore;
			iMemoryStore=NULL;
			}
		}
	//if not rewrite back to the client the size that is required
	//and signal with KErrOverFlow to the client
	else
		{
		//write back the bufferSize
		listParam.iBufferSize=bufferSizeRequired;
  		aMessage.WriteL(2,listParamPkg);
		User::Leave(KErrOverflow);
		}
	}

TBool CEComServerSession::DoCollectListL(const TClientRequest& aMessage)
	{
	TBool success = EFalse;
	if(iMemoryStore)
		{
		TPtr8 data=iMemoryStore->Ptr(0);
		aMessage.WriteL(0, data);
		delete iMemoryStore;
		iMemoryStore = NULL;
		success = ETrue;
		}
	return success;
	}

void CEComServerSession::DoGetResolvedImplementationL(const TClientRequest& aMessage)
	{
	// Unpack the client supplied parameters
	// Firstly get the uids
	TUidType uids;
	TPckg<TUidType> uidsPkg(uids);
	aMessage.ReadL(KIPCParameterUids, uidsPkg);

	// Now rebuild the TEComResolverParams
	TEComResolverParams resolverParameters;
	resolverParameters.SetGenericMatch(KIPCParameterResolverParamsTypePtr);	
	
	//now get the matchString and extendedInterfaces
	RBuf8 matchStr;
	matchStr.CleanupClosePushL();
	RExtendedInterfacesArray extendedInterfaces;
	CleanupClosePushL(extendedInterfaces);
	UnpackMatchStrAndExtendedInterfacesFromClientL(aMessage,extendedInterfaces,matchStr);
    if(matchStr.Length()>0)
		{	
		resolverParameters.SetDataType(matchStr);
		}
	// Else the client's resolver params are default constructed i.e. invalid
	// data type descriptor or its length is zero, so use empty HBufC8 above.
	// Set up for the return value
	TUid dtorIdKey(KNullUid);
	TEntry loadInfo;
	
	switch(aMessage.Function())
		{
		case EGetImplementationCreationMethod:
			Server().GetResolvedDllInfoL(uids[KInterfaceUidIndex], 
										 loadInfo, 
										 dtorIdKey,
										 aMessage);
			break;
		case EGetResolvedCreationMethod:
			Server().GetResolvedDllInfoL(uids[KInterfaceUidIndex], 
										 resolverParameters, 
										 extendedInterfaces,
										 loadInfo, 
										 dtorIdKey,
										 aMessage);
			break;
		case EGetCustomResolvedCreationMethod:
			Server().GetResolvedDllInfoL(uids[KInterfaceUidIndex], 
										 resolverParameters, 
										 uids[KResolverUidIndex], 
										 extendedInterfaces,
										 loadInfo, 
										 dtorIdKey,
										 aMessage);
			break;
		default:
			break;
		}
	CleanupStack::PopAndDestroy(&extendedInterfaces);
	CleanupStack::PopAndDestroy(&matchStr);
	
// ??? Compile time assert that sizeof(TProxyNewLPtr) == sizeof(TAny*)?
// Currently I'm not arranging for the client-side of the session to
// convert from TAny* to TProxyNewLPtr, and using this to avoid the
// full agony of following through with conversion...

	// Then re-package the results for return
	// Firstly the Interface Implementation creation method pointer
	TPckg<TEntry> result(loadInfo);
	
	aMessage.WriteL(KIPCReturnParameterCreationMethodPtr, result);
	// Next the destruction identification uid
	TUidType type(KNullUid,dtorIdKey,KNullUid);
	TPckg<TUidType> dtorIdKeyPkg(type);
	
	aMessage.WriteL(KIPCReturnParameterUidsPtr, dtorIdKeyPkg);
	}

// Return the list of interfaces to the client. If not enough space
// has been allocated by the client, KErrOverflow will be returned.
//
void CEComServerSession::DoListExtendedInterfacesL(const TClientRequest& aMessage)
	{
	// Unpack the client supplied parameters
	TInt bufferSize = 0;
	TUid implementationUid(KNullUid);
	TPckg<TUid> implementationUidDes(implementationUid);
	TPckg<TInt> bufferSizeDes(bufferSize);
	aMessage.ReadL(KIPCParameterImplementationUid,implementationUidDes);
	aMessage.ReadL(KIPCParameterBufferSize,bufferSizeDes);
		
	// Get the implementation information for this implementation UID.
	CImplementationInformation* implInfo = NULL;
	Server().GetImplementationInformationL(implementationUid,implInfo,aMessage);
	
	TInt numExtendedInterfaces = 0; // Number of extended interfaces to return to client.

	if(implInfo)
		{
		TInt bufferSizeRequired = 0; // Buffer required to send extended interface data back to client
		
		// Fetch the list of extended interfaces
		RExtendedInterfacesArray* extendedInterfaceList = implInfo->GetExtendedInterfaceList();
		if (extendedInterfaceList != NULL)
			{
			numExtendedInterfaces = extendedInterfaceList->Count();
			}
		if (numExtendedInterfaces > 0)
			{
			bufferSizeRequired = numExtendedInterfaces * sizeof(TUid);
			__ECOM_TRACE1("ECOM ListInterfaces request buffer size required=%d",bufferSizeRequired);
			
			//if the preallocated size is big enough to hold our entry
			//copy it to the client
			if (bufferSize >= bufferSizeRequired)
				{
				RBuf8 buf;
				CleanupClosePushL(buf);
				buf.CreateL(bufferSizeRequired);   // Create the RBuf.
				
				// Note : There is no need to push the write stream onto the cleanup stack
				// because it has no internal resources.
				RDesWriteStream writeStream;
				writeStream.Open(buf);

				// Build the data of extendedInterfaces;
				for(TInt i = 0; i < numExtendedInterfaces; ++i)
					{
					writeStream.WriteInt32L((*extendedInterfaceList)[i].iUid);
					}

				writeStream.CommitL();
				
				// Copy the data to the client.
				bufferSize=bufferSizeRequired;
				aMessage.WriteL(KIPCParameterBufferSize,bufferSizeDes);
				aMessage.WriteL(KIPCParameterInterfaceData,buf);
				
				CleanupStack::PopAndDestroy(&buf);
				}
			//if not rewrite back to the client the size that is required
			//and signal with KErrOverFlow to the client
			else
				{
				bufferSize=bufferSizeRequired;
				aMessage.WriteL(KIPCParameterBufferSize,bufferSizeDes);
				User::Leave(KErrOverflow);
				}
			}
		}
		
	//if nothing is returned we should still indicate this to the client side
	if (numExtendedInterfaces == 0)
		{
		bufferSize=0;
		aMessage.WriteL(KIPCParameterBufferSize,bufferSizeDes);
		}
	}

#if defined(__ECOM_SERVER_TESTABILITY__) || defined(__ECOM_SERVER_PERFORMANCE__)
/**
This method is provided for testability. It allows the user to 
send and receive any parameters. 
@param aMessage IPC message between server and client
*/
void CEComServerSession::DoSetGetParametersL(const TClientRequest& aMessage)
	{
	TInt parameterType = aMessage.Int0();
	
	switch(parameterType)
		{
#ifdef __ECOM_SERVER_TESTABILITY__
		case EChangeStartupState:
			Server().ChangeStartupStateL(aMessage.Int1());
			break;
		case EProcessStartupState:
			Server().ProcessCurrentStartupStateL();
			break;
		case EGetStartupState:
			{
			TInt state = Server().GetCurrentStartupState();
			TPckg<TInt> pckgState(state);
		    aMessage.Write(1, pckgState);
			break;
			}
#endif
#ifdef __ECOM_SERVER_PERFORMANCE__
		case EGetStartupStateTimerResult:
			{
			TStartupStateTimerEntry timerEntry;
			
			TInt ret = EComPerformance::GetStartupStateTimerResult(aMessage.Int1(), timerEntry.iTimerResult, timerEntry.iState);
			
			TPckg<TInt> pckgRetValue(ret);
			aMessage.Write(2, pckgRetValue);
			TPckg<TStartupStateTimerEntry> pckgTimerEntry(timerEntry);
			aMessage.Write(3, pckgTimerEntry);
			break;
			}

		case EGetAccumulatedClientRequestsTimerResult:
			{
			TClientRequestTimerEntry timerEntry;
			TInt ret = EComPerformance::GetAccumulatedClientRequestTimerResult(aMessage.Int1(), timerEntry);
			TPckg<TInt> pckgRetValue(ret);
			aMessage.Write(2, pckgRetValue);
			TPckg<TClientRequestTimerEntry> pckgTimerEntry(timerEntry);
			aMessage.Write(3, pckgTimerEntry);
			break;
			}
		case EGetRegistryCounts:
			{
			RegistryCounts::TRegistryCounts counts;
			Server().GetRegistryCountsL(aMessage.Int1(), counts);
			TPckg<RegistryCounts::TRegistryCounts> pckgRegistryCounts(counts);
			aMessage.Write(2, pckgRegistryCounts);
			break;
			}
		case EResetStartupStateTimerCounts:
			{
			EComPerformance::ResetStartupStateTimerResult();
			break;
			}
		case EGetEComPerfTimeRecord:
			{
			TEComPerfTimeRecordEntry timerEntry;
			TInt ret = EComPerformance::GetEComPerfTimeRecord(aMessage.Int1(), timerEntry);
			TPckg<TInt> pckgRetValue(ret);
			aMessage.Write(2, pckgRetValue);
			TPckg<TEComPerfTimeRecordEntry> pckgTimerEntry(timerEntry);
			aMessage.Write(3, pckgTimerEntry);
			break;
			}
		case EResetEComPerfTimeRecords:
			{
			EComPerformance::ResetEComPerfTimeRecords();
			}
		case EGetEComServerHeapResult:
			{
			TEComPerfHeapUsage heapEntry;
			TInt ret= EComPerformance::GetEComHeapSize(aMessage.Int1(),heapEntry);
			TPckg<TInt> pckgRetValue(ret);
			aMessage.Write(2, pckgRetValue);
			TPckg<TEComPerfHeapUsage> pckgHeapEntry(heapEntry);
			aMessage.Write(3, pckgHeapEntry);
			break;			
			}
#endif
		default:
			break;
		}
	}
#endif

void CEComServerSession::CleanupInternalList()
	{
	if (iList != NULL)
		{
		iList->Reset();
		delete iList;
		iList = NULL;
		}
	}