sl@0: // Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
sl@0: // All rights reserved.
sl@0: // This component and the accompanying materials are made available
sl@0: // under the terms of "Eclipse Public License v1.0"
sl@0: // which accompanies this distribution, and is available
sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0: //
sl@0: // Initial Contributors:
sl@0: // Nokia Corporation - initial contribution.
sl@0: //
sl@0: // Contributors:
sl@0: //
sl@0: // Description:
sl@0: //
sl@0: 
sl@0: #include <e32math.h>
sl@0: #include <mmf/common/mmfcontrollerframework.h>
sl@0: #include "MmfDrmPluginServer.h"
sl@0: #include "MmfDrmPluginServerStart.h"
sl@0: #include "MmfDrmPluginServerSession.h"
sl@0: #ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
sl@0: #include <mmf/common/mmfcontrollerframeworkclasses.h>
sl@0: #endif
sl@0: 
sl@0: CMMFDRMPluginServer* CMMFDRMPluginServer::NewL()
sl@0: 	{
sl@0: 	CMMFDRMPluginServer* s = new(ELeave) CMMFDRMPluginServer();
sl@0: 	CleanupStack::PushL(s);
sl@0: 	s->ConstructL();
sl@0: 	CleanupStack::Pop();
sl@0: 	return s;
sl@0: 	}
sl@0: 
sl@0: CMMFDRMPluginServer::CMMFDRMPluginServer() :
sl@0: 	CMmfIpcServer(EPriorityStandard)
sl@0: 	{
sl@0: 	}
sl@0: 
sl@0: void CMMFDRMPluginServer::ConstructL()
sl@0: 	{
sl@0: 	iDelayServerShutDown = CDelayServerShutDown::NewL();
sl@0: 	// Call base class to Start server
sl@0: 	StartL(KDrmPluginServerName);
sl@0: 	}
sl@0: 
sl@0: CMMFDRMPluginServer::~CMMFDRMPluginServer()
sl@0: 	{
sl@0: 	iControllerServList.ResetAndDestroy();
sl@0: 	iControllerServList.Close();
sl@0: 	delete iDelayServerShutDown;
sl@0: 	}
sl@0: 
sl@0: CMmfIpcSession* CMMFDRMPluginServer::NewSessionL(const TVersion& aVersion) const
sl@0: 	{
sl@0: 	TVersion v(KMMFDRMPluginServerVersion,
sl@0: 				KMMFDRMPluginServerMinorVersionNumber,
sl@0: 				KMMFDRMPluginServerBuildVersionNumber);
sl@0: 	if(!User::QueryVersionSupported(v, aVersion))
sl@0: 		{
sl@0: 		User::Leave(KErrNotSupported);
sl@0: 		}
sl@0: 		
sl@0: 	for(TInt i = 0; i < iControllerServList.Count(); i++)
sl@0: 		{
sl@0: 		CStartAndMonitorControllerThread* controllerMonThread 
sl@0: 			= iControllerServList[i];
sl@0: 		if(!controllerMonThread->IsActive())
sl@0: 			{
sl@0: 			iControllerServList.Remove(i);
sl@0: 			delete controllerMonThread;
sl@0: 			}
sl@0: 		}
sl@0: 	iControllerServList.Compress();
sl@0: 	
sl@0: 	CMMFDRMPluginServerSession* session = CMMFDRMPluginServerSession::NewL();
sl@0: 	return session;
sl@0: 	}
sl@0: 
sl@0: void CMMFDRMPluginServer::IncrementSessionId()
sl@0: 	{
sl@0: 	iSessionCount++;
sl@0: 	}
sl@0: 
sl@0: void CMMFDRMPluginServer::DecrementSessionId()
sl@0: 	{
sl@0: 	iSessionCount--;
sl@0: 	if(iSessionCount == 0 && iControllerCount == 0)
sl@0: 		{
sl@0: 		// Guarantee that server will be closed, after a period of time, even
sl@0: 		// a session has been created without a controller thread initialized 
sl@0: 		if(!iDelayServerShutDown->IsActive())
sl@0: 			{
sl@0: 			// If shut down timer has been started previously, that setup has the piority
sl@0: 			iDelayServerShutDown->SetDelay(TTimeIntervalMicroSeconds32(iServerTimeout));
sl@0: 			}
sl@0: 		}
sl@0: 	}
sl@0: 
sl@0: void CMMFDRMPluginServer::IncrementControllerCount()
sl@0: 	{
sl@0: 	iControllerCount++;
sl@0: 	if(iControllerCount)
sl@0: 		{
sl@0: 		//In the case we started the shutdown due to no more controllers
sl@0: 		iDelayServerShutDown->Cancel(); 
sl@0: 		}
sl@0: 	}
sl@0: 
sl@0: void CMMFDRMPluginServer::DecrementControllerCount()
sl@0: 	{
sl@0: 	iControllerCount--;
sl@0:     if (iControllerCount == 0)
sl@0: 		{
sl@0: 		iDelayServerShutDown->SetDelay(TTimeIntervalMicroSeconds32(iServerTimeout));
sl@0:  		}
sl@0: 	}
sl@0: 	
sl@0: TInt CMMFDRMPluginServer::StartControllerServer(const RThread& aClientThread, TUint aMaxHeapSize, TBool aUseSharedHeap,
sl@0: 											RMMFControllerServerProxy& aControllerSessionHandle, TThreadId& aControllerTID, TUint aStackSize) const
sl@0: 	{
sl@0: 	CStartAndMonitorControllerThread* monitor = NULL;
sl@0: 
sl@0: 	TRAPD(err, monitor = 
sl@0: 		CStartAndMonitorControllerThread::NewL(const_cast<CMMFDRMPluginServer*>(this)));
sl@0: 	if(err != KErrNone)
sl@0: 		{
sl@0: 		delete monitor;
sl@0: 		return err;
sl@0: 		}
sl@0: 
sl@0: 	err = iControllerServList.Append(monitor);
sl@0: 	if(err != KErrNone)
sl@0: 		{
sl@0: 		delete monitor;
sl@0: 		return err;
sl@0: 		}
sl@0: 	
sl@0: 	return monitor->StartControllerServer(aClientThread, aMaxHeapSize, aUseSharedHeap, 
sl@0: 										aControllerSessionHandle, aControllerTID, aStackSize);
sl@0: 	}
sl@0: 
sl@0: void CMMFDRMPluginServer::PanicControllerThread(TThreadId aTid, const TDesC& aCategory,TInt aReason)
sl@0: 	{
sl@0: 	for(TInt i = 0; i < iControllerServList.Count(); i++)
sl@0: 		{
sl@0: 		if(iControllerServList[i]->Thread().Id() == aTid)
sl@0: 			{
sl@0: 			iControllerServList[i]->Thread().Panic(aCategory, aReason);
sl@0: 			return;
sl@0: 			}
sl@0: 		}
sl@0: 	}
sl@0: 
sl@0: void CMMFDRMPluginServer::KillControllerThread(TThreadId aTid, TInt aReason)
sl@0: 	{
sl@0: 	for(TInt i = 0; i < iControllerServList.Count(); i++)
sl@0: 		{
sl@0: 		if(iControllerServList[i]->Thread().Id() == aTid)
sl@0: 			{
sl@0: 			iControllerServList[i]->Thread().Kill(aReason);
sl@0: 			return;
sl@0: 			}
sl@0: 		}
sl@0: 	}
sl@0: 
sl@0: TInt CMMFDRMPluginServer::SetThreadPriority(TThreadId aTid, TThreadPriority aPriority)
sl@0: 	{
sl@0: 	TBool threadFound = EFalse;
sl@0: 	for(TInt i = 0; i < iControllerServList.Count(); i++)
sl@0: 		{
sl@0: 		const RThread& controllerThread = iControllerServList[i]->Thread();
sl@0: 		if (controllerThread.Id() == aTid)
sl@0: 			{
sl@0: 			if (controllerThread.Priority() != aPriority)
sl@0: 				{
sl@0: 				controllerThread.Suspend();
sl@0: 				controllerThread.SetPriority(aPriority);
sl@0: 				controllerThread.Resume();
sl@0: 				}
sl@0: 			threadFound = ETrue;
sl@0: 			break;
sl@0: 			}
sl@0: 		}
sl@0: 	return threadFound? KErrNone: KErrNotFound;
sl@0: 	}
sl@0: 
sl@0: CMMFDRMPluginServer::CDelayServerShutDown* CMMFDRMPluginServer::CDelayServerShutDown::NewL()
sl@0: 	{
sl@0: 	CDelayServerShutDown* self = new(ELeave) CDelayServerShutDown;
sl@0: 	CleanupStack::PushL(self);
sl@0: 	self->ConstructL();
sl@0: 	CleanupStack::Pop();
sl@0: 	return self;
sl@0: 	}
sl@0: 
sl@0: CMMFDRMPluginServer::CDelayServerShutDown::CDelayServerShutDown() : CActive(0)
sl@0: 	{
sl@0: 	}
sl@0:         
sl@0: void CMMFDRMPluginServer::CDelayServerShutDown::ConstructL()
sl@0: 	{
sl@0: 	User::LeaveIfError(iShutDownTimer.CreateLocal());
sl@0: 	CActiveScheduler::Add(this);
sl@0: 	}
sl@0: 
sl@0: CMMFDRMPluginServer::CDelayServerShutDown::~CDelayServerShutDown()
sl@0: 	{
sl@0: 	Cancel();
sl@0: 	iShutDownTimer.Close();
sl@0: 	}
sl@0: 
sl@0: void CMMFDRMPluginServer::CDelayServerShutDown::SetDelay(TTimeIntervalMicroSeconds32 aDelay)
sl@0: 	{
sl@0: 	__ASSERT_ALWAYS(!IsActive(), User::Panic(_L("CMMFDRMPluginServer"), 1));
sl@0: 	iShutDownTimer.After(iStatus, aDelay);
sl@0: 	SetActive();
sl@0: 	}
sl@0: 
sl@0: void CMMFDRMPluginServer::CDelayServerShutDown::RunL()
sl@0: 	{
sl@0: 	CActiveScheduler::Stop();
sl@0: 	}
sl@0: 
sl@0: 
sl@0: void CMMFDRMPluginServer::CDelayServerShutDown::DoCancel()
sl@0: 	{
sl@0: 	iShutDownTimer.Cancel();
sl@0: 	}
sl@0: 
sl@0: CStartAndMonitorControllerThread* CStartAndMonitorControllerThread::NewL(CMMFDRMPluginServer* aPluginServer)
sl@0: 	{
sl@0: 	CStartAndMonitorControllerThread* self = new(ELeave) CStartAndMonitorControllerThread(aPluginServer);
sl@0: 	CleanupStack::PushL(self);
sl@0: 	self->ConstructL();
sl@0: 	CleanupStack::Pop();
sl@0: 	return self;
sl@0: 	}
sl@0: 
sl@0: void CStartAndMonitorControllerThread::ConstructL()
sl@0: 	{
sl@0: 	CActiveScheduler::Add(this);
sl@0: 	}
sl@0: 	
sl@0: TInt CStartAndMonitorControllerThread::StartControllerServer(const RThread& /*aClientThread*/, TUint aMaxHeapSize, TBool aUseSharedHeap,
sl@0: 													RMMFControllerServerProxy& aControllerSessionHandle, TThreadId& aControllerTID,TUint aStackSize)
sl@0: 	{
sl@0: 	Cancel();
sl@0: 	TInt err = KErrNone;
sl@0: 
sl@0: 	RServer2 controllerServer;	
sl@0: 	TControllerProxyServerParams params;
sl@0: 	params.iServer = &controllerServer;
sl@0: 	params.iUsingSharedHeap = aUseSharedHeap;
sl@0: 	
sl@0: 	TName name;
sl@0: 	name.Append(KMMFControllerProxyServerName);
sl@0: 	
sl@0: 	// Threads create own heap (default behaviour)
sl@0: 	if(aMaxHeapSize < static_cast<TUint>(KMinHeapSize))
sl@0: 		{
sl@0: 		aMaxHeapSize = KMinHeapSize; //else raises a USER 111 panic
sl@0: 		}
sl@0: 	else if(aMaxHeapSize >  static_cast<TUint>(KMMFControllerProxyMaxHeapSize))
sl@0: 		{
sl@0: 		aMaxHeapSize = KMMFControllerProxyMaxHeapSize;
sl@0: 		}
sl@0: 	
sl@0: 	err = iServerThread.Create(name, &CMMFControllerProxyServer::StartThread,
sl@0: 		aStackSize, KMinHeapSize, aMaxHeapSize, 
sl@0: 		&params, EOwnerThread);
sl@0: 	if (err)
sl@0: 		{
sl@0: 		return err;
sl@0: 		}
sl@0: 		
sl@0: 	// Synchronise with the server
sl@0: 	TRequestStatus reqStatus;
sl@0: 	iServerThread.Rendezvous(reqStatus);
sl@0: 	
sl@0: 	if (reqStatus!=KRequestPending)
sl@0: 		{
sl@0: 		iServerThread.Kill(0);
sl@0: 		}
sl@0: 	else
sl@0: 		{
sl@0: 		iServerThread.SetPriority(EPriorityNormal);
sl@0: 		iServerThread.Resume();
sl@0: 		// Server will call the reciprocal static synchronise call	
sl@0: 		}
sl@0: 
sl@0: 	User::WaitForRequest(reqStatus); // wait for start or death
sl@0: 	if(reqStatus.Int() != KErrNone)
sl@0: 		{
sl@0: 		iServerThread.Close();
sl@0: 		controllerServer.Close();
sl@0: 		return reqStatus.Int();
sl@0: 		}
sl@0: 	
sl@0: 	err = aControllerSessionHandle.Open(controllerServer);
sl@0: 	if(err != KErrNone)
sl@0: 		{
sl@0: 		iServerThread.Close();
sl@0: 		controllerServer.Close();
sl@0: 		return err;
sl@0: 		}
sl@0: 	
sl@0: 	iStatus = KRequestPending;
sl@0: 	iServerThread.Logon(iStatus);
sl@0: 	if (iStatus != KRequestPending)
sl@0: 		{
sl@0: 		// Failed to logon
sl@0: 		aControllerSessionHandle.Close();
sl@0: 		iServerThread.Close();
sl@0: 		controllerServer.Close();
sl@0: 		return iStatus.Int();
sl@0: 		}
sl@0: 	else
sl@0: 		{
sl@0: 		SetActive();
sl@0: 		}
sl@0: 		
sl@0: 	aControllerSessionHandle.ShareProtected();
sl@0: 	aControllerTID = iServerThread.Id();
sl@0: 	iDrmPluginServer->IncrementControllerCount();
sl@0: 	return KErrNone;
sl@0: 	}
sl@0: 
sl@0: 
sl@0: CStartAndMonitorControllerThread::CStartAndMonitorControllerThread(CMMFDRMPluginServer* aPluginServer)
sl@0: 	: CActive(EPriorityStandard)
sl@0: 	{
sl@0: 	iDrmPluginServer = aPluginServer;
sl@0: 	}
sl@0: 
sl@0: CStartAndMonitorControllerThread::~CStartAndMonitorControllerThread()
sl@0: 	{
sl@0: 	Cancel();
sl@0: 	}
sl@0:     
sl@0: void CStartAndMonitorControllerThread::RunL()
sl@0: 	{
sl@0: 	iServerThread.Close();
sl@0: 	iDrmPluginServer->DecrementControllerCount();
sl@0: 	}
sl@0: 
sl@0: void CStartAndMonitorControllerThread::DoCancel()
sl@0: 	{
sl@0: 	iServerThread.LogonCancel(iStatus);
sl@0: 	iServerThread.Kill(0);
sl@0: 	iServerThread.Close();
sl@0: 	iDrmPluginServer->DecrementControllerCount();
sl@0: 	}
sl@0: 
sl@0: TInt RMMFControllerServerProxy::Open(RServer2& aControllerServerHandle)
sl@0: 	{
sl@0: 	TInt err = CreateSession(aControllerServerHandle, KMMFControllerProxyVersion, 
sl@0: 							-1, EIpcSession_GlobalSharable);
sl@0: 	return err;
sl@0: 	}